{"id":15871059,"url":"https://github.com/sgreben/rc","last_synced_at":"2025-03-16T04:30:30.366Z","repository":{"id":17015577,"uuid":"81006510","full_name":"sgreben/rc","owner":"sgreben","description":"A rule checker library for Java. Checks sets of rules for completeness, overlap, and constraint satisfaction.","archived":false,"fork":false,"pushed_at":"2025-03-01T01:51:25.000Z","size":58,"stargazers_count":1,"open_issues_count":7,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-01T02:30:35.758Z","etag":null,"topics":["analysis","builder","checker","constraint-satisfaction","rule-checker","rules","ruleset","yaml","z3"],"latest_commit_sha":null,"homepage":"","language":"Java","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/sgreben.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-05T16:48:13.000Z","updated_at":"2020-08-07T16:21:37.000Z","dependencies_parsed_at":"2023-01-11T20:25:47.884Z","dependency_job_id":"91de1b5f-9008-4f7f-8213-b82839cab1a5","html_url":"https://github.com/sgreben/rc","commit_stats":{"total_commits":27,"total_committers":3,"mean_commits":9.0,"dds":"0.33333333333333337","last_synced_commit":"679c55e4cd25945080fdf0fabb19a36b4c6f686d"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgreben%2Frc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgreben%2Frc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgreben%2Frc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgreben%2Frc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sgreben","download_url":"https://codeload.github.com/sgreben/rc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243801679,"owners_count":20350108,"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":["analysis","builder","checker","constraint-satisfaction","rule-checker","rules","ruleset","yaml","z3"],"created_at":"2024-10-06T00:41:37.332Z","updated_at":"2025-03-16T04:30:30.082Z","avatar_url":"https://github.com/sgreben.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `rc` - a rule checker\n\n`rc` is a completeness, overlap, and constraint satisfaction checker library for sets of rules. For a command-line interface to this library see [rc-cli](https://github.com/sgreben/rc-cli).\n\n\n`rc` is implemented using [Z3](https://github.com/Z3Prover/z3), the automatic theorem prover built by Microsoft Research.\n\n**Table of Contents** \n- [Installation](#installation)\n    - [Maven dependency](#maven-dependency)\n- [Usage](#usage)\n    - [Using the builder API](#using-the-builder-api)\n    - [Using the declaration API](#using-the-declaration-api)\n    - [Performing analysis](#performing-analysis)\n\n## Installation\n### Maven dependency\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.sgreben\u003c/groupId\u003e\n    \u003cartifactId\u003erule-checker\u003c/artifactId\u003e\n    \u003cversion\u003e1.0-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Usage\n\n`rc` is used as follows:\n- Construct a set of rules as an input to rc (either via a builder API or via YAML files)\n- Use `rc` to check the rules for completeness, consistency and constraint satisfaction\n- Use the counterexamples generated by `rc` to improve the rules\n\nThe input to `rc` has the following structure:\n- Module\n    - Type definitions\n    - Rule sets\n        - Variable definitions\n        - Rules\n            - Precondition (when)\n            - Postcondition (then)\n        \nThere are two ways of constructing these objects:\n- Using the builders in `io.github.sgreben.rc.Context` and `io.github.sgreben.rc.builders`to construct the objects directly.\n- Building (or loading from YAML) the declaration classes in `io.github.sgreben.rc.declartions` and then compiling them.\n\n\nAs an example, we will express the following rules for a fictional IoT device:\n\n- Given an enumeration type `STATE` with the values `ON`, `OFF`, `STANDBY`,\n- Given the sensor inputs `temperature` (integer), `temperatureGoal` (integer),  `brightness` (real), `motion` (real),\n- Given the state input variable `state` and output variable `stateOut` of type `STATE`,\n- We apply the rules\n    - When `temperature \u003e 23 \u0026\u0026 (motion \u003c 0.3 || brightness \u003c 0.1)`\n        - Then `stateOut = OFF`\n    - When `temperature \u003c temperatureGoal \u0026\u0026 motion \u003e= 0.3`\n        - Then `stateOut = ON`\n    - When `temperature \u003e= temperatureGoal \u0026\u0026 motion \u003c 0.1`\n        - Then `stateOut = state`\n    - When `temperature \u003e= temperatureGoal \u0026\u0026 motion \u003e 0.1`\n        - Then `stateOut = STANDBY`\n\n### Using the builder API\n\nTo start, we grab an instance of the `Context` class, which we will use to access the builders:\n\n```java\nimport io.github.sgreben.rc.Context;\n\nContext context = new Context();\n```\n\nNext, we construct the enumeration type:\n\n```java\nEnumType stateType = context.buildType().enumeration()\n    .withName(\"STATE\")\n    .withValue(\"ON\")\n    .withValue(\"OFF\")\n    .withValue(\"STANDBY\")\n    .build();\n```\n\nUsing the type definition we can construct our variables:\n\n```java\nVariable temperature = context.buildExpression()\n    .variable(\"temperature\")\n    .ofType(context.buildType().integer());\nVariable temperatureGoal = context.buildExpression()\n    .variable(\"temperatureGoal\")\n    .ofType(context.buildType().integer());\nVariable brightness = context.buildExpression()\n    .variable(\"brightness\")\n    .ofType(context.buildType().real());\nVariable motion = context.buildExpression()\n    .variable(\"motion\")\n    .ofType(context.buildType().real());\nVariable state = context.buildExpression()\n    .variable(\"state\")\n    .ofType(stateType);\nVariable stateOut = context.buildExpression()\n    .variable(\"stateOut\")\n    .ofType(stateType);\n\n```\n\nWe are now ready to construct our rules:\n\n```java\nExpressionBuilder eb = context.buildExpression();\n\n// When `temperature \u003e 23 \u0026\u0026 (motion \u003c 0.3 || brightness \u003c 0.1)`\n// Then `stateOut = OFF`\nRule rule1 = context.buildRule()\n    .withName(\"rule 1\")\n    .withPrecondition(eb.And(\n        eb.Greater(temperature, context.buildValue().integer(23)),\n        eb.Or(\n            eb.Less(motion, context.buildValue().real(0.3)),\n            eb.Less(brightness, context.buildValue().real(0.1))\n        )\n    ))\n    .withPostcondition(eb.Equal(\n        stateOut, context.buildValue().enumeration(\"OFF\"))\n    )\n    .build();\n\n// When `temperature \u003c temperatureGoal \u0026\u0026 motion \u003e= 0.3`\n// Then `stateOut = ON`\nRule rule2 = context.buildRule()\n    .withName(\"rule 2\")\n    .withPrecondition(eb.And(\n        eb.Less(temperature, temperatureGoal),\n        eb.GreaterOrEqual(motion, context.buildValue().real(0.3))\n    ))\n    .withPostcondition(eb.Equal(\n        stateOut, context.buildValue().enumeration(\"ON\"))\n    )\n    .build();\n\n// When `temperature \u003e= temperatureGoal \u0026\u0026 motion \u003c 0.1`\n// Then `stateOut = state`\nRule rule3 = context.buildRule()\n    .withName(\"rule 3\")\n    .withPrecondition(eb.And(\n        eb.GreaterOrEqual(temperature, temperatureGoal),\n        eb.Less(motion, context.buildValue().real(0.1))\n    ))\n    .withPostcondition(eb.Equal(stateOut, state))\n    .build();\n\n// When `temperature \u003e= temperatureGoal \u0026\u0026 motion \u003e 0.1`\n// Then `stateOut = STANDBY`\nRule rule4 = context.buildRule()\n    .withName(\"rule 4\")\n    .withPrecondition(eb.And(\n        eb.GreaterOrEqual(temperature, temperatureGoal),\n        eb.Greater(motion, context.buildValue().real(0.1))\n    ))\n    .withPostcondition(eb.Equal(\n        stateOut, context.buildValue().enumeration(\"STANDBY\"))\n    )\n    .build();\n\n```\n\nTo check properties of a set of rules, we construct an instance of the `RuleSet` class:\n\n```java\nRuleSet myRuleSet = context.buildRuleSet()\n    .withName(\"my rule set\")\n    .withRule(rule1)\n    .withRule(rule2)\n    .withRule(rule3)\n    .withRule(rule4)\n    .build();\n```\n\nDone! You can now skip ahead to [Performing analysis](#performing-analysis) to learn how to check the rule set for completeness, overlap, and constraint satisfaction.\n\n### Using the declaration API\n\nSave the following as a file `myModule.yaml`.\n\n```yaml\nname: myModule\ntypes:\n    STATE:\n      values:\n        - ON\n        - OFF\n        - STANDBY\nruleSets:\n    - name: my rule set\n      variables:\n        temperature: int \n        temperatureGoal: int \n        motion: real\n        brightness: real\n        state: STATE\n        stateOut: STATE\n      rules:\n        - name: rule 1\n          when: temperature \u003e 23 \u0026\u0026 (motion \u003c 0.3 || brightness \u003c 0.1)\n          then:\n            stateOut: OFF\n        - name: rule 2\n          when: temperature \u003c temperatureGoal \u0026\u0026 motion \u003e= 0.3\n          then:\n              stateOut: ON\n        - name: rule 3\n          when: temperature \u003e= temperatureGoal \u0026\u0026 motion \u003c 0.1\n          then:\n              stateOut: state\n        - name: rule 4\n          when: temperature \u003e= temperatureGoal \u0026\u0026 motion \u003e 0.1\n          then:\n              stateOut: STANDBY\n```\n\nWe can now load this module using the `ModuleDeclaration` class:\n\n```java\n\nimport io.github.sgreben.rc.declarations.ModuleDeclaration;\n\nModuleDeclaration moduleDeclaration = ModuleDeclaration.load(\"myModule.yaml\")\n```\n\nTo perform analysis on the module, we have to *compile* it using a `Context`:\n\n```java\nContext context = new Context();\nModule module = moduleDeclaration.compile(context);\n```\n\nWe can now obtain the rule set we defined above:\n\n```java\nRuleSet myRuleSet = module.ruleSet(\"my rule set\");\n```\n\nDone! You can now continue to [Performing analysis](#performing-analysis) to learn how to check the rule set for completeness, overlap, and constraint satisfaction.\n\n\n### Performing analysis\n\nWe are now ready to check our rules for completeness, overlap, and constraint satisfaction:\n\n```java\n// Checks completeness, prints example unmatched values if incomplete\nif (!myRuleSet.isComplete()) {\n    System.out.println(myRuleSet.completenessCounterexample())\n}\n```\n\n```java\n// Checks for overlaps, prints example values matched by multiple rules\nif (myRuleSet.isOverlapping()) {\n    System.out.println(myRuleSet.overlaps())\n}\n```\n\n```java\n// Checks if the given constraint is satisfied in all cases\n// Constraint: motion \u003e 0.1 =\u003e state != OFF\nExpression constraint = eb.Implies(\n    eb.Greater(motion, context.buildValue.real(0.1)),\n    eb.NotEqual(state, context.buildValue.enumeration(\"OFF\"))\n);\n    \nif (!myRuleSet.satisfiesConstraint(constraint)) {\n    System.out.println(myRuleSet.constraintCounterExamples(constraint))\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgreben%2Frc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsgreben%2Frc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgreben%2Frc/lists"}