{"id":21971570,"url":"https://github.com/mandarancio/proofkit","last_synced_at":"2025-03-22T23:11:06.267Z","repository":{"id":75095797,"uuid":"93537073","full_name":"Mandarancio/ProofKit","owner":"Mandarancio","description":"ADT and Proof editor","archived":false,"fork":false,"pushed_at":"2021-10-25T16:53:17.000Z","size":939,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-15T00:14:01.675Z","etag":null,"topics":["adt","formal","logic","logickit","proofs","swift","tools"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mandarancio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-06-06T15:58:05.000Z","updated_at":"2021-10-25T16:53:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"699c75b4-b043-408b-8ebc-53bf24285a69","html_url":"https://github.com/Mandarancio/ProofKit","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandarancio%2FProofKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandarancio%2FProofKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandarancio%2FProofKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandarancio%2FProofKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mandarancio","download_url":"https://codeload.github.com/Mandarancio/ProofKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245031509,"owners_count":20549925,"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":["adt","formal","logic","logickit","proofs","swift","tools"],"created_at":"2024-11-29T14:52:03.063Z","updated_at":"2025-03-22T23:11:06.245Z","avatar_url":"https://github.com/Mandarancio.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/Mandarancio/ProofKit.svg?branch=master)](https://travis-ci.org/Mandarancio/ProofKit)\n\n# ProofKit\nADT toolkit and Proof verifier based on [LogicKit](https://github.com/kyouko-taiga/LogicKit).\n\n**Project WIKI**: [link](https://github.com/Mandarancio/ProofKit/wiki)\n\n**PetriKit Lib**: [link](https://github.com/Dexter9313/PetriNetLib)\n\n## Implemented ADTs\nCurrently implemented ADT and Operators\n\n|ADT|Generators|Constructor|Operators|\n|---|----------|-----------|---------|\n|Boolean|```True() False()```|```n(Bool)```|```not(x) and(x,y) or(x,y)```|\n|Nat|```zero() succ(x)```|```n(Int)```|```add(x,y) mul(x,y) sub(x,y) div(x,y) mod(x) lt(x,y) gt(x,y) eq(x,y) gcd(x,y) ```|\n|Integer|```int(x,y)```|```n(Int)```|```add(x,y) mul(x,y) sub(x,y) div(x,y) abs(x), normalize(x) lt(x,y) gt(x,y) eq(x,y) sign(x) ```|\n|[Multiset](https://en.wikipedia.org/wiki/Linked_list)|```empty() cons(first, rest)```|```n([Term])```|```first(x) rest(x) contains(x,y) size(x) concat(x,y) removeOne(x,y) removeAll(x,y) eq(x,y)```|\n|[Set](https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29)|```empty() cons(first, rest)```|```n([Term])```|```union(x,y) subSet(x,y) intersection(x,y) difference(x,y)  contains(x,y) size(x) removeOne(x,y) eq(x,y) insert(x,y)```|\n|Sequence|```empty(), cons(value,index,rest)```|```n([Term])```|```push(value,rest), getAt(sequence, index), setAt(sequence, index, value) size(sequence)```|\n\n## Implemented Proofs:\n\n|Name|Call|Status|\n|----|----|------:|\n|reflexivity|```Proof.reflexivity(Term) -\u003e Rule```| **tested**|\n|symmetry |```Proof.symmetry(Rule) -\u003e Rule``` |**tested** |\n|transitivity |```Proof.transitivity(Rule, Rule) -\u003e Rule```| **tested**|\n|substitution|```Proof.substitution(Rule, Variable, Term) -\u003e Rule```| **tested**|\n|substitutivity|```Proof.substitutivity((Term...)-\u003eTerm, [Term], [Term]) -\u003e Rule```| **tested**|\n|inductive|```Proof.inductive(Rule, Variable, ADT, [String:(Rule...)-\u003eRule])```| - |\n\n## Your first code\nWrite your first code is simple, just import ```ProofKit``` inside your ```package.swift```:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n    name: \"YourPackageName\",\n    dependencies: [\n        // Dependencies declare other packages that this package depends on.\n        .package(\n            url: \"https://github.com/Mandarancio/ProofKit.git\",\n            .branch(\"master\")\n        ),\n    ],\n    targets: [\n        .target(\n            name: \"YourPackageName\",\n            dependencies: [\"ProofKit\"]),\n        .testTarget(\n            name: \"YourPackageNameTests\",\n            dependencies: [\"YourPackageName\"]),\n    ]\n)\n```\n\nAnd finally your code in ```main.swift```:\n\n```swift\nimport SwiftKanren\nimport ProofKit\n\nlet x = Variable(named: \"x\")\nlet y = Variable(named: \"y\")\n\nlet goal = (x \u003c Nat.self \u0026\u0026 y \u003c Nat.self) =\u003e ((x + y) \u003c-\u003e Nat.n(5))\nfor solution in solve(goal).prefix(11)\n{\n  let rsolution = solution.reified()\n  print(\"x: \\(ADTm.pprint(rsolution[x])), y: \\(ADTm.pprint(rsolution[y]))\")\n}\n```\n\nOnce compiled and executed (*remember*: the binary is located ```.build/debug/YOUR_PROJECT_NAME```) the output should be:\n\n```\nx: 0, y: 5\nx: 1, y: 4\nx: 2, y: 3\nx: 3, y: 2\nx: 4, y: 1\nx: 5, y: 0\n```\n\n## Advanced usage\n![Diagram](docs/diagram.png)\n\n### Rule\nThe *struct* **Rule** is the container of **axioms** and future **theorems**. Is composed in left and right components (both Term) and implement both a function to apply the rule and one to *pretty print* it.\nTo create a rule simply:\n\n```swift\n 1\u003e let r = Rule(\n      Nat.add(Variable(named: \"x\"), Nat.zero()), // left component\n      Variable(named: \"x\"), // right component\n      Boolean.True() // optional Boolean condition (default: Boolean.True())\n    )\n```\n\nPrint the rule:\n\n```swift\n 2\u003e print(r)\nx + 0 = x\n```\nApply it:\n```swift\n 3\u003e let g : Goal = r.apply(Nat.n(4) + Nat.zero(), Variable(named: x)) // create goal (4+0) to applay rule\n 4\u003e let res : Term = get_result(g,x) //function solve goal and return the substitution of x\n 5\u003e print(ADTm.pprint(res))\n4\n```\n\n### ADT\n\nAll ADTm extend the base *class* **ADT**, this contains both generator, opertors generator and operators axioms as well as some basic helpers such a chek type and a *pretty print* function.\n\nTo access to axioms, generators and operators there are always two methods, a long and a shortcut, e.g. ```get_generator(\"name\")``` and ```g(\"name\")```.\n\nFor both **generators** and **operators** is possible to access just using ```[\"name\"]```.\n\nAdding operators and axioms is possible **only internally**.\nA simple example is a simplify version of the boolean adt:\n```swift\npublic class Boolean : ADT {\n    public init(){\n      super.init(\"boolean\")\n      self.add_generator(\"true\", Boolean.True)\n      self.add_generator(\"false\", Boolean.False)\n      self.add_operator(\"not\", Boolean.not, [\n        Rule(Boolean.not(Boolean.False()),Boolean.True()),\n        Rule(Boolean.not(Boolean.True()),Boolean.False())\n      ], [\"boolean\"])\n    }\n    public static func True(_:Term...) -\u003e Term{\n      return new_term(Value\u003cBool\u003e(true), \"boolean\")\n    }\n\n    public static func False(_:Term...) -\u003e Term{\n      return new_term(Value\u003cBool\u003e(false), \"boolean\")\n    }\n\n    public static func not(_ operands: Term...)-\u003eTerm{\n      return Operator.n(Value(\"nil\"), operands[0], \"not\")\n    }\n}\n```\n\n### ADTManager\n\nFinally to manage the *ADT* and have the possibility to mixit together in the future we use an **ADTManager**. This is composed by a dictionary of ADT and some helper function (such as the *pretty printer*).\n\nTo avoid the creation of multiple ADTManager, there is a single ADTManager (as the constructor is private) instance called **ADTm**.\n\nTo get or add an ADT from the instance **ADTm**:\n\n```swift\nlet nat : ADT = ADTm[\"nat\"] // to get adt\n/// or\nADTm[\"boolean\"] = Boolean() // to add adt\n```\n\nTo pretty print any term:\n\n```swift\nlet t = Nat.n(1) + Nat.n(1)\nprint(\"\\(ADTm.pprint(t))\")\n//// 1 + 1\nprint(t)\n//// [type: operator, name: \"+\", 0: [type: nat, value: [succ: [type: nat, value: 0]]]....\n```\n#### Universal Evaluator\n\nA simple inner most universal evaluator is implemented. To use it:\n\n```swift\nlet operation : Term = Nat.n(2) * Nat.n(3)\nlet result : Term = ADTm.eval(operation)\nprint(\" \\(ADTm.pprint(operation)) =\u003e \\(ADTm.pprint(result))\")\n//// 2 * 3 =\u003e 6\n```\n\nTo be able to perform any type of computation it trys to solve the inner most operation first using the operation axioms and the generator evaluator.\n\n\n### How to create an ADT?\n\nYou can see an exemple at **Source/ADTDemo**\nFirst create a file with the name of your adt.\nYou have a typical example at **Source/ADTDemo/char.swift**\nTwo mains steps when you create your own ADT:\n- Create **Generators**\n- Create **Operators**\n\nYou have to add this in ```public init()``` and create a function\nfor each **generator** and **operator**.\n\nMoreover you have to override some basics functions for the inheritance if you want that your ADT works!\nThis functions are:\n- **belong** (Goal to know if a term belong to this adt)\n- **check** (Simple check to check if a term is of this adt type)\n- **pprint** (Print nicely your term)\n\nNice you have your ADT, but it's not the end! We have seen above the **ADTManager**.\nYou have to add all of your ADT in this **ADTManager**. You can do it easily as follows:\n```swift\n// Then you add your new adt to the manager\nADTm[\"char\"] = Char()\n```\n\nYou have a simple example how ADTManager works at **Source/ADTDemo/main.swift**.\nYou can make tests with your own ADT that you can add into an ADTManager to use it.\nNow you can easily use and test your ADT. Use your ADT to create your variable and use the ADTManager to evaluate operations.\n\n```swift\n// Example:\n\nlet a = Char.a()\nlet b = Char.b()\nvar op = a == b\nvar r = ADTm.eval(op)\nprint(\"\\(ADTm.pprint(op)) =\u003e \\(ADTm.pprint(r))\")\n// a == b =\u003e false\n```\n\n\n### Proofs\n\nNow we have all ADT that we need and we can use it for proofs.\nFirstly, you have several examples avaible in **Source/EqProofDemo**.\nWhen you want to verify a proof, you need to write all the steps.\nFor classical proof you just have to follow the example that are avaible.\n\nIf you want to create your own induction proof, here are the steps to follow:\n\n1. You just have to specify axioms that you will need.\n\n ```swift\n  let ax0 = ADTm[\"nat\"].a(\"+\")[0]\n  let ax1 = ADTm[\"nat\"].a(\"+\")[1]\n ```\n2. Write the conjecture you want to verify.\n\n ```swift\n // We try to proof that succ(0) + x = suc(x)\n let conj = Rule(\n   Nat.add(Nat.succ(x: Nat.zero()), Variable(named:\"x\")),\n   Nat.succ(x: Variable(named: \"x\"))\n )\n ```\n\n3. **For each** generators you have to verify the initial case and\nthe higher rank. Here we have just one generator!\n\n ```swift\n // Initial case\n func zero_proof(t: Rule...)-\u003eRule{\n   let ax0 = ADTm[\"nat\"].a(\"+\")[0]\n   // s(0)+0 = s(0)\n   return Proof.substitution(ax0, Variable(named: \"x\"), Nat.succ(x: Nat.zero()))\n }\n```\n```swift\n// Higher rank\n func succ_proof(t: Rule...)-\u003eRule{\n   let ax1 = ADTm[\"nat\"].a(\"+\")[1]\n   // s(0) + s(y) = s(s(0) + y)\n   let t2 = Proof.substitution(ax1, Variable(named: \"x\"), Nat.succ(x: Nat.zero()))\n   // s(s(0) + x) = s(s(x))\n   let t3 = Proof.substitutivity (Nat.succ, [t[0]])\n   // s(0) + s(y) = s(s(y))\n   return Proof.transitivity(t2, t3)\n }\n ```\n\n4. Now we can call out our function to know if steps are good.\n\n ```swift\n do {\n   let teo = try Proof.inductive(conj, Variable(named: \"x\"), ADTm[\"nat\"], [\n     \"zero\": zero_proof,\n     \"succ\": succ_proof\n   ])\n   print(\"Indcutive result: \\(teo)\")\n }\n // If the induction failed\n catch ProofError.InductionFail {\n   print(\"Induction failed!\")\n }\n ```\n\n Great! Now you can see \"true\" if all are good!\n\n## Syntattic Sugar\n\nLogicKit integration:\n\n|Syntax| Semantic|\n|---|---|\n|```Term ∈ ADT.Type: Goal```|  Term in ADT|\n|```Term \u003c ADT.Type: Goal```|  Term in ADT|\n|```Goal =\u003e Goal: Goal```| Goal such that Goal |\n|```Term \u003c-\u003e Term: Goal```| evalue(Term) equal to evalue(Term) |\n\nMathematical operations:\n\n|Operation| Symbol| Supported types|\n|---------|:-----:|----------------|\n|sum      |+      |Nat, Integer    |\n|diffrence|-      |Nat, Integer    |\n|multiply |*      |Nat, Integer    |\n|divide   |/      |Nat, Integer    |\n|equal    |==     |All types       |\n|great    |\u003e      |Nat, Integer    |\n|less     |\u003c      |Nat, Integer    |\n|and      |\u0026amp;\u0026amp;|Boolean      |\n|or       |\u0026#124;\u0026#124;|Boolean         |\n\nUsing LogicKit and the ```ADTm.geval()``` method is possible to evaluate simple logic expressions:\n\n```swift\nlet x = Variable(named: \"x\")\nlet y = Variable(named: \"y\")\n\n// x,y ∈ Nat =\u003e (x+y) \u003c 9 \u0026\u0026 x\u003cy\nlet goal = x ∈ Nat.self \u0026\u0026  y ∈ Nat.self =\u003e (x+y) \u003c-\u003e Nat.n(6) \u0026\u0026 (x\u003cy) \u003c-\u003e Boolean.True()\n// NOTE \u003c can be used instead of ∈\n\nfor sol in solve(goal).prefix(3){ // NOTE .prefix(N) is used to stop the research of possible solution after N found\n  let rsol = sol.reified()\n  print(\" x: \\(ADTm.pprint(rsol[x]), y: \\(ADTm.pprint(rsol[y]))\")\n}\n\n```\n\nResulting in:\n\n```\n x: 0, y: 6\n x: 1, y: 5\n x: 2, y: 4\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandarancio%2Fproofkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandarancio%2Fproofkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandarancio%2Fproofkit/lists"}