{"id":27294340,"url":"https://github.com/ilya-kolchinsky/opencep","last_synced_at":"2025-07-10T05:33:27.422Z","repository":{"id":43718159,"uuid":"246560360","full_name":"ilya-kolchinsky/OpenCEP","owner":"ilya-kolchinsky","description":"A highly efficient and expressive CEP framework written entirely in Python.","archived":false,"fork":false,"pushed_at":"2022-06-07T10:29:27.000Z","size":25546,"stargazers_count":38,"open_issues_count":49,"forks_count":20,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-11T22:52:01.064Z","etag":null,"topics":["cep"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ilya-kolchinsky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-11T12:06:25.000Z","updated_at":"2025-02-27T11:47:00.000Z","dependencies_parsed_at":"2022-08-22T02:10:11.820Z","dependency_job_id":null,"html_url":"https://github.com/ilya-kolchinsky/OpenCEP","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ilya-kolchinsky/OpenCEP","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilya-kolchinsky%2FOpenCEP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilya-kolchinsky%2FOpenCEP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilya-kolchinsky%2FOpenCEP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilya-kolchinsky%2FOpenCEP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ilya-kolchinsky","download_url":"https://codeload.github.com/ilya-kolchinsky/OpenCEP/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ilya-kolchinsky%2FOpenCEP/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264535990,"owners_count":23624404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cep"],"created_at":"2025-04-11T22:51:59.343Z","updated_at":"2025-07-10T05:33:27.377Z","avatar_url":"https://github.com/ilya-kolchinsky.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenCEP\nOpenCEP is an open-source library and framework providing advanced complex event processing (CEP) capabilities.\n\nCEP is a prominent technology for robust and high-performance real-time detection of arbitrarily complex patterns in massive data streams. It is widely employed in many areas where extremely large amounts of streaming data are continuously generated and need to be promptly and efficiently analyzed on-the-fly. Online finance, network security monitoring, credit card fraud detection, sensor networks, traffic monitoring, healthcare industry, and IoT applications are among the many examples.\n\nCEP systems treat data items as primitive events arriving from event sources. As new primitive events are observed, they are assembled into higher-level complex events matching the specified patterns. The process of complex event detection generally consists of collecting primitive events and combining them into potential (partial) matches using some type of detection model. As more events are added to a partial match, a full pattern match is eventually formed and reported.\n\nThe patterns detected by CEP engines are often of exceedingly high complexity and nesting level, and may include multiple complex operators and conditions on the data items. Moreover, these systems are typically required to operate under tight constraints on response time and detection precision, and to process multiple patterns and streams in parallel. Therefore, advanced algorithmic solutions and sophisticated optimizations must be utilized by CEP implementations to achieve an acceptable level of service quality.\n\n![OpenCEP structure overview](CEP.png)\n\nThe figure above presents an overview of OpenCEP structure. Incoming data streams are analyzed on-the-fly and useful statistics and data characteristics are extracted to facilitate the optimizer in applying the aforementioned optimization techniques and maximize the performance of the evaluation mechanism – a component in charge of the actual pattern matching.\n\nBy incorporating a multitude of state-of-the-art methods and algorithms for scalable event processing, OpenCEP can adequately satisfy the requirements of modern event-driven domains and outperform existing alternatives, both in terms of the actual performance and the provided functionality.\n\nOpenCEP features a generic and intuitive API, making it easily applicable to any domain where event-based streaming data is present. \n\n# How to Use\n* Users can apply complex patterns on event streams by creating and invoking a CEP object (CEP.py).\n* The CEP object is initialized with a list of patterns to be detected and a set of configurable parameters.\n* To create an event stream, you can manually create an empty stream and add events to it, and you can also provide a csv file to the fileInput function.\n* To handle the CEP output, you can manually read the events from the CEP object or from the matches container, or use the fileOutput function to print the matches into a file.\n* To create a pattern, the following components must be specified:\n    * The pattern structure - e.g., SEQ(A, B, C) or AND(X, Y).\n    * The condition that must be satisfied by the atomic items in the pattern structure.\n    * The time window within which the atomic items in the pattern structure should appear in the stream.\n\n\n# Usage Examples\n## Defining a pattern\nThis pattern is looking for a short ascend in the Google peak prices:\n```\n# PATTERN SEQ(GoogleStockPriceUpdate a, GoogleStockPriceUpdate b, GoogleStockPriceUpdate c)\n# WHERE a.PeakPrice \u003c b.PeakPrice AND b.PeakPrice \u003c c.PeakPrice\n# WITHIN 3 minutes\ngoogleAscendPattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"GOOG\", \"a\"), \n                    PrimitiveEventStructure(\"GOOG\", \"b\"), \n                    PrimitiveEventStructure(\"GOOG\", \"c\")),\n        AndCondition(\n            SmallerThanCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]), \n                                 Variable(\"b\", lambda x: x[\"Peak Price\"])),\n            SmallerThanCondition(Variable(\"b\", lambda x: x[\"Peak Price\"]), \n                                 Variable(\"c\", lambda x: x[\"Peak Price\"]))\n        ),\n        timedelta(minutes=3)\n    )\n```\nAnother way to define the above example is to use SimpleCondition and a lambda function:\n```\ngoogleAscendPattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"GOOG\", \"a\"), \n                    PrimitiveEventStructure(\"GOOG\", \"b\"), \n                    PrimitiveEventStructure(\"GOOG\", \"c\")),\n        SimpleCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]), \n                        Variable(\"b\", lambda x: x[\"Peak Price\"]),\n                        Variable(\"c\", lambda x: x[\"Peak Price\"]),\n                        relation_op=lambda x,y,z: x \u003c y \u003c z),\n        timedelta(minutes=3)\n    )\n```\nThis pattern is looking for low prices of Amazon and Google at the same minute:\n```\n# PATTERN AND(AmazonStockPriceUpdate a, GoogleStockPriceUpdate g)\n# WHERE a.PeakPrice \u003c= 73 AND g.PeakPrice \u003c= 525\n# WITHIN 1 minute\ngoogleAmazonLowPattern = Pattern(\n    AndOperator(PrimitiveEventStructure(\"AMZN\", \"a\"), PrimitiveEventStructure(\"GOOG\", \"g\")),\n    AndCondition(\n        SmallerThanEqCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]), 73),\n        SmallerThanEqCondition(Variable(\"g\", lambda x: x[\"Peak Price\"]), 525)\n    ),\n    timedelta(minutes=1)\n)\n```\nAnother way to define the above pattern is to use the generic BinaryCondition with a lambda function\n```\ngoogleAmazonLowPattern = Pattern(\n    AndOperator(PrimitiveEventStructure(\"AMZN\", \"a\"), PrimitiveEventStructure(\"GOOG\", \"g\")),\n    BinaryCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]),\n                    Variable(\"g\", lambda x: x[\"Peak Price\"]),\n                    lambda x, y: x \u003c= 73 and y \u003c= 525),\n    timedelta(minutes=1)\n)\n\n```\n## Activating the CEP engine\nCreating a CEP object for monitoring the first pattern from the example above:\n```\ncep = CEP([googleAscendPattern])\n```\n\nDefining a new file-based event stream formatted according to Metastock 7 format:\n```\nevents = FileInputStream(\"test/EventFiles/NASDAQ_SHORT.txt\")\n```\n\nApplying an existing CEP object on an event stream created above and storing the resulting pattern matches to a file:\n```\ncep.run(events, FileOutputStream('test/Matches', 'output.txt'), MetastockDataFormatter())\n```\n\n## Advanced features and settings\n### Kleene Closure Operator \n\nThe following is the example of a pattern containing a Kleene closure operator:\n\n```\npattern = Pattern(\n        SeqOperator(\n            PrimitiveEventStructure(\"GOOG\", \"a\"), \n            KleeneClosureOperator(PrimitiveEventStructure(\"GOOG\", \"b\"))\n        ),\n        AndCondition(\n            SmallerThanCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]), Variable(\"b\", lambda x: x[\"Peak Price\"])),\n            SmallerThanCondition(Variable(\"b\", lambda x: x[\"Peak Price\"]), Variable(\"c\", lambda x: x[\"Peak Price\"]))\n        ),\n        timedelta(minutes=5)\n    )\n```\n\nThe following example of a pattern containing a Kleene closure operator with an offset condition:\n```\npattern = Pattern(\n    SeqOperator(KleeneClosureOperator(PrimitiveEventStructure(\"GOOG\", \"a\"))),\n    AndCondition(\n        SimpleCondition(Variable(\"a\", lambda x: x[\"Opening Price\"]), relation_op=lambda x: x \u003e 0),\n        KCValueCondition(names={'a'}, getattr_func=lambda x: x[\"Peak Price\"],\n                         relation_op=lambda x, y: x \u003e y,\n                         value=530.5),\n        KCIndexCondition(names={'a'}, getattr_func=lambda x: x[\"Opening Price\"],\n                         relation_op=lambda x, y: x+0.5 \u003c y,\n                         offset=-1)\n    ),\n    timedelta(minutes=5)\n)\n```\n\nThe following example of a pattern containing a Kleene closure operator with a value condition:\n```\npattern = Pattern(\n    SeqOperator(KleeneClosureOperator(PrimitiveEventStructure(\"GOOG\", \"a\"))),\n    AndCondition(\n        SimpleCondition(Variable(\"a\", lambda x: x[\"Opening Price\"]), \n                        relation_op=lambda x: x \u003e 0),\n        KCValueCondition(names={'a'}, \n                         getattr_func=lambda x: x[\"Peak Price\"], \n                         relation_op=lambda x, y: x \u003e y, value=530.5)\n        ),\n    timedelta(minutes=5)\n)\n```\n\n### Multi-Pattern Support\nFor multi-pattern workloads, you can choose one of the algorithms to share the common sub-patterns:\n* `TRIVIAL_SHARING_LEAVES`: shares equivalent leaves from different tree plans.\n* `TREE_PLAN_SUBTREES_UNION`: shares equivalent subtrees of different tree plans.\n* `TREE_PLAN_LOCAL_SEARCH`: shares multiple subtrees of different tree plans, using the local search algorithm.\n\nMore muti-pattern sharing algorithms will be supported in the future.\n\n```\n\nfirst_pattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"GOOG\", \"a\"), PrimitiveEventStructure(\"GOOG\", \"b\"),\n                    PrimitiveEventStructure(\"AAPL\", \"c\")),\n        AndCondition(\n            SmallerThanCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]),\n                                 Variable(\"b\", lambda x: x[\"Peak Price\"])),\n            GreaterThanCondition(Variable(\"b\", lambda x: x[\"Peak Price\"]),\n                                 Variable(\"c\", lambda x: x[\"Peak Price\"]))\n        ),\n        timedelta(minutes=3)\n    )\nsecond_pattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"GOOG\", \"a\"), PrimitiveEventStructure(\"GOOG\", \"b\")),\n        SmallerThanCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]),\n                             Variable(\"b\", lambda x: x[\"Peak Price\"]))\n        ,\n        timedelta(minutes=3)\n)    \n\neval_mechanism_params = TreeBasedEvaluationMechanismParameters(TreePlanBuilderParameters(TreePlanBuilderTypes.TRIVIAL_LEFT_DEEP_TREE,\n                                                                                             TreeCostModels.INTERMEDIATE_RESULTS_TREE_COST_MODEL,\n                                                                                             MultiPatternTreePlanUnionApproaches.TREE_PLAN_SUBTREES_UNION))\n\n\n# Then, running activating cep engine: \ncep = CEP([first_pattern, second_pattern] , eval_mechanism_params)\n```\n\n### Negation Operator \n\nOpenCEP supports a variety of negation algorithms provided using the TreeBasedEvaluationMechanismParameters parameter.\nIt is an optional parameter, if the pattern includes negative events and negation algorithm was not provided, the naive negation algorithm would be used. \n \nThe following is an example of a pattern containing a negation operator (without providing negation algorithm):\n\n```\npattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                    NegationOperator(PrimitiveEventStructure(\"AMZN\", \"b\")), \n                    PrimitiveEventStructure(\"GOOG\", \"c\")),\n        AndCondition(\n            GreaterThanCondition(Variable(\"a\", lambda x: x[\"Opening Price\"]),\n                                 Variable(\"b\", lambda x: x[\"Opening Price\"])),\n            SmallerThanCondition(Variable(\"b\", lambda x: x[\"Opening Price\"]),\n                                 Variable(\"c\", lambda x: x[\"Opening Price\"]))),\n        timedelta(minutes=5)\n    )\n\n```\n#### Optimizing evaluation performance with custom TreeBasedEvaluationMechanismParameters\n\nThe following is an example of a pattern containing a negation operator specifying the statistic negation algorithm:\n\n```\npattern = Pattern(\n        SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                    NegationOperator(PrimitiveEventStructure(\"AMZN\", \"b\")), \n                    PrimitiveEventStructure(\"GOOG\", \"c\")),\n        AndCondition(\n            GreaterThanCondition(Variable(\"a\", lambda x: x[\"Opening Price\"]),\n                                 Variable(\"b\", lambda x: x[\"Opening Price\"])),\n            SmallerThanCondition(Variable(\"b\", lambda x: x[\"Opening Price\"]),\n                                 Variable(\"c\", lambda x: x[\"Opening Price\"]))),\n        timedelta(minutes=5)\n    )\n    eval_params = TreeBasedEvaluationMechanismParameters(\n        negation_algorithm_type = NegationAlgorithmTypes.STATISTIC_NEGATION_ALGORITHM\n    )\n    cep = CEP(pattern, eval_mechanism_params)\n```\nThere is one more negation algorithm, the lowest position algorithm. In order to use it, use the TreeBasedEvaluationMechanismParameters as demonstrated above, specifying \"NegationAlgorithmTypes.LOWEST_POSITION_NEGATION_ALGORITHM\" as negation algorithm type.\n\nThe use of the non naive algorithms may improve system performance.\nThe statistic algorithm is recommended when data stream include a large amount of negative events.\nThe lowest position algorithm is recommended when some of the negative events are bounded (i.e. not located at the beginning nor the end of the events sequence in the pattern). \n\n### Consumption policies and selection strategies\n\nOpenCEP supports a variety of consumption policies provided using the ConsumptionPolicy parameter in the pattern definition.\n\nThe following pattern definition limiting all primitive events to only appear in a single full match.\n```\npattern = Pattern(\n    SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                PrimitiveEventStructure(\"AMZN\", \"b\"), \n                PrimitiveEventStructure(\"AVID\", \"c\")), \n    TrueCondition(),\n    timedelta(minutes=5),\n    ConsumptionPolicy(primary_selection_strategy = SelectionStrategies.MATCH_SINGLE)\n)\n```\nThis selection strategy further limits the pattern detection process, only allowing to match produce a single intermediate partial match containing an event. \n```\npattern = Pattern(\n    SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                PrimitiveEventStructure(\"AMZN\", \"b\"), \n                PrimitiveEventStructure(\"AVID\", \"c\")), \n    TrueCondition(),\n    timedelta(minutes=5),\n    ConsumptionPolicy(primary_selection_strategy = SelectionStrategies.MATCH_NEXT)\n)\n```\nIt is also possible to enforce either MATCH_NEXT or MATCH_SINGLE on a subset of event types. \n```\npattern = Pattern(\n    SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                PrimitiveEventStructure(\"AMZN\", \"b\"), \n                PrimitiveEventStructure(\"AVID\", \"c\")), \n    TrueCondition(),\n    timedelta(minutes=5),\n    ConsumptionPolicy(single=[\"AMZN\", \"AVID\"], \n                      secondary_selection_strategy = SelectionStrategies.MATCH_NEXT)\n)\n```\nThis consumption policy specifies a list of events that must be contiguous in the input stream, i.e., \nno other unrelated event is allowed to appear in between.\n```\npattern = Pattern(\n    SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                PrimitiveEventStructure(\"AMZN\", \"b\"), \n                PrimitiveEventStructure(\"AVID\", \"c\")), \n    TrueCondition(),\n    timedelta(minutes=5),\n    ConsumptionPolicy(contiguous=[\"a\", \"b\", \"c\"])\n)\n```\nThe following example instructs the framework to prohibit creation of new partial matches\nfrom the point a new \"b\" event is accepted and until it is either matched or expired.\n\n```\n# Enforce mechanism from the first event in the sequence\npattern = Pattern(\n    SeqOperator(PrimitiveEventStructure(\"AAPL\", \"a\"), \n                PrimitiveEventStructure(\"AMZN\", \"b\"), \n                PrimitiveEventStructure(\"AVID\", \"c\")), \n    AndCondition(\n        GreaterThanCondition(Variable(\"a\", lambda x: x[\"Opening Price\"]), \n                             Variable(\"b\", lambda x: x[\"Opening Price\"])), \n        GreaterThanCondition(Variable(\"b\", lambda x: x[\"Opening Price\"]), \n                             Variable(\"c\", lambda x: x[\"Opening Price\"]))),\n    timedelta(minutes=5),\n    ConsumptionPolicy(freeze=\"b\")\n)\n```\n\n### Optimizing evaluation performance with custom TreeStorageParameters\n```\nstorage_params = TreeStorageParameters(sort_storage=True,\n                                       attributes_priorities={\"a\": 122, \"b\": 200, \"c\": 104, \"m\": 139})\neval_mechanism_params=TreeBasedEvaluationMechanismParameters(storage_params=storage_params)\ncep = CEP(pattern, eval_mechanism_params)\n```\n\n### Optimizing evaluation performance with the use of Adaptive CEP\n\nOpenCEP supports timely evaluation plan replacement according to statistics obtained from the stream. \nThe CEP object maintains a statistics collector that supports several types of statistics. in addition it supports several optimization algorithms \nthat decide when to invoke plan reconstruction and a tree based evaluation method that decides how to replace evaluation trees.\nThe following example shows how to create a CEP object that supports adaptive evaluation plan replacement based on \nevent type arrival rates and selectivity matrix statistics along with a deviation aware optimizer.\n\nFirst, define parameters of the statistics collector that will keep arrival rates statistics, \nselectivity statistics and a certain time window:\n```\nstatistics_types = [StatisticsTypes.SELECTIVITY_MATRIX, StatisticsTypes.ARRIVAL_RATES]\n\ntime_window = timedelta(minutes=2)\n# the statistics are kept for a 2 minutes time interval\n\nstatistics_collector_params = StatisticsCollectorParameters(statistics_types=statistics_types ,statistics_time_window=time_window)\n```\n\nTo make use of the statistics, an optimizer is needed. The following example shows how to initialize the optimizer parameters:\n```\n# There are different types of optimizers, here we define an optimizer that \n# calls for a new evaluation plan if at least one of the statistics has deviated by a factor of t. \n# note that different optimizers are initialized by different parameters.\n\noptimizer_params = StatisticsDeviationAwareOptimizerParameters(t = 0.5, statistics_types = statistics_types)\n```\n\nAfter defining the parameters of the statistics collector and the optimizer, we create a CEP object that support adaptivity:\n```\neval_mechanism_params = TreeBasedEvaluationMechanismParameters(statistics_collector_params=statistics_collector_params, optimizer_params=optimizer_params)\nCEP = CEP(pattern, eval_mechanism_params)\n```\n\n### Probabilistic streams and confidence parameters\n\nOpenCEP supports probabilistic streams, where each incoming event is associated\nwith an occurrence probability. In this scenario, a pattern should contain a\n\"confidence threshold\" specifying what is the lowest acceptable probability of\na match of this pattern.\n\nProbabilistic patterns are specified with the confidence threshold as follows:\n\n```\npattern = Pattern(\n        SeqOperator(\n            PrimitiveEventStructure(\"GOOG\", \"a\"), \n            PrimitiveEventStructure(\"GOOG\", \"b\")\n        ),\n        SmallerThanCondition(Variable(\"a\", lambda x: x[\"Peak Price\"]), Variable(\"b\", lambda x: x[\"Peak Price\"])),\n        timedelta(minutes=5),\n        confidence=0.9\n    )\n```\n\n## Twitter API support\n### Authentication\nTo receive a Twitter stream via Twitter API, provide your credentials in plugin/twitter/TwitterCredentials.py\n### Creating a twitter stream\nTo create a twitter stream, create an instance of TwitterInputStream and use it as you would any other OpenCEP input stream.\nFiltering parameters for the twitter stream can be provided via the constructor of the class.\n```\nevent_stream = TwitterInputStream(['corona'])\n```\n### Tweet formation in CEP\nThe format of a tweet is defined in Tweets.py (see documentation). The tweet keys are described there based on the overview of a tweet in https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/tweet-object\n\n### Data Parallel Algorithms\n\nIn order to run the program in parallel, the user is required to input the needed parameters\nunder the following structure while the underline filled with the name of the chosen algorithm\n(\"Hirzel\" / \"RIP\" / \"HyperCube\"): DataParallelExecutionParameters___Algorithm  \nThe structure above contains the following parameters:\n1.Parallel execution platforms (Threading available for now)\n2.Calculations units number\n\nAdditionally, for each algorithm there is a unique additional input and certain terms on the inputs or on the pattern.\nPlease note that there is no input validation. Input correctness is the user responsibility.\n\nHirzel Algorithm -\nAdditional input: An attribute the data will be divided into units according to it.\nTerms on the pattern: The pattern will only contain equations (for example: equations between attributes of different types, equality of a certain value to the attribute of a specific type).\nPlease note that the given attribute has to be the same attribute that his equality tested in the pattern.\n\nRIP Algorithm -\nAdditional input: multiple of timedelta, the multiple should be \u003e 1. The algorithm will run Round Robin between the units every (time_delta * multiple) \nTerms on the pattern: The pattern will not contain unblocked negation.\n\nHyperCube Algorithm -\nAdditional input: A dictionary consist of data type(key) and attribute(data) the data will be divided into units according to it.\nTerms on the given units number: the units number should satisfy the equation for some X: X**(types number)=(units number-1).\nFor example, for a pattern consist of 3 types, a possible units number may be 28 (1+ 3 power 3).\nnotes: - For KC patterns, only works when max_size for the Klenee Closer is given in the pattern, and doesn't work with nested Andoperator inside the KC pattern.\n       - The algorithm can't deal with negation condition. \nWarning: The more times one type is used in a pattern, the more time the algorithm runs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filya-kolchinsky%2Fopencep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filya-kolchinsky%2Fopencep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filya-kolchinsky%2Fopencep/lists"}