{"id":15061171,"url":"https://github.com/c-cube/datalog","last_synced_at":"2025-05-16T18:05:26.671Z","repository":{"id":6082663,"uuid":"7309253","full_name":"c-cube/datalog","owner":"c-cube","description":"An in-memory datalog implementation for OCaml.","archived":false,"fork":false,"pushed_at":"2024-10-17T17:45:09.000Z","size":2239,"stargazers_count":269,"open_issues_count":1,"forks_count":24,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-16T18:03:22.872Z","etag":null,"topics":["datalog","logic-programming","memoization","ocaml","prolog"],"latest_commit_sha":null,"homepage":"https://c-cube.github.io/datalog","language":"Prolog","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-cube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","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":"2012-12-24T16:13:37.000Z","updated_at":"2025-04-25T14:43:09.000Z","dependencies_parsed_at":"2024-11-13T19:00:44.084Z","dependency_job_id":"d2996449-1937-436f-9fa6-79e8bc19cbfa","html_url":"https://github.com/c-cube/datalog","commit_stats":{"total_commits":215,"total_committers":3,"mean_commits":71.66666666666667,"dds":0.009302325581395321,"last_synced_commit":"37b450a4f7e68fa1e2ed669d583ee7a2ccdf4a5c"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fdatalog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fdatalog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fdatalog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Fdatalog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-cube","download_url":"https://codeload.github.com/c-cube/datalog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582903,"owners_count":22095518,"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":["datalog","logic-programming","memoization","ocaml","prolog"],"created_at":"2024-09-24T23:10:56.390Z","updated_at":"2025-05-16T18:05:26.618Z","avatar_url":"https://github.com/c-cube.png","language":"Prolog","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Datalog\n\n[![build](https://github.com/c-cube/datalog/actions/workflows/main.yml/badge.svg)](https://github.com/c-cube/datalog/actions/workflows/main.yml)\n\nAn in-memory datalog implementation for OCaml.\n\nIt features two main algorithm:\n\n- bottom-up focuses on big sets of rules with small relations, with frequent\n  updates of the relations. Therefore, it tries to achieve good behavior in\n  presence of incremental modifications of the relations.\n\n- top-down resembles prolog (and allows nested subterms). It handles\n  stratified negation and only explores the part of the search space that\n  is relevant to a given query.\n\n## Bottom-Up\n\nThis version, `backward`, features a backward-chaining operation. It resembles\ntop-down algorithms because goals (possibly non-ground literals) can be\nadded to the `db`; it means that if `G` is a goal and\n`A :- B1,B2,...,Bn` is a clause,\nif `A` and `B1` are unifiable with `subst`, then `subst(B1)` is also a goal.\nHandlers (semantic attachments) can be provided by the user, to be called on\nevery goal. The point is that the handlers can add facts that **solve** the\ngoal by adding facts that match it.\n\nFor instance, a handler may solve goals of the form `lt_than(i,j)` (where\n`i` and `j` are integers) by adding the fact `lt(i,j)` if `i \u003c j` is\nreally true. Another example: if symbols are strings, then the goal\n`concat(\"foo\", \"bar\", X)` may be solved by adding the fact\n`concat(\"foo\", \"bar\", \"foobar\")`. The tool `datalog_cli` has build-in\ndefinitions of `lt`, `le` (lower or equal) and `equal`; see the last example.\nThus, goals are a way to call semantic attachments in a goal-oriented way.\n\nA relational query mode is available (its signature is in\n`Datalog.BottomUp.S.Query`, see the\n[module's documentation](http://c-cube.github.io/datalog/0.6/datalog/Datalog/BottomUp/module-type-S/Query/index.html).\nIt allows to make one-shot queries on a `db` (the result won't update\nif facts or clauses are added later), with a simple relational model\nwith negation.\n\n## Top-Down\n\nThere is also a top-down, prolog-like algorithm that should be very efficient\nfor querying only a subpart of the intensional database (the set of all\nfacts that can be deduced from rules). The main module is `Datalog_top_down`,\nand it has its own parser and lexer. An executable (not installed but compiled)\nis `topDownCli.exe`. A very important distinction is that terms\ncan be nested (hence the distinct AST and parsers).\n\nThe format of semantic attachments for symbols is simpler: a handler, when\nqueried with a given goal, can return a set of clauses whose heads will\nthen be unified with the goal.\n\n## CamlInterface\n\nThe module `Datalog_caml_interface` in the library `datalog.caml_interface`\ncontains a universal embedding of OCaml's types,\nwith helpers to build unary, binary, and ternary atoms that directly relate\nOCaml values.\n\nSmall example:\n\n```ocaml\n# #require \"datalog\";;\n# #require \"datalog.caml_interface\";;\n# module CI = Datalog_caml_interface;;\nmodule CI = Datalog_caml_interface\n# let edge = CI.Rel2.create ~k1:CI.Univ.int ~k2:CI.Univ.int \"edge\";;\nval edge : (int, int) CI.Rel2.t = \u003cabstr\u003e\n# let db = CI.Logic.DB.create();;\nval db : CI.Logic.DB.t = \u003cabstr\u003e\n# CI.Rel2.symmetry db edge;;\n- : unit = ()\n# CI.Rel2.add_list db edge [1,2; 2,3; 3,4];;\n- : unit = ()\n# CI.Rel2.find db edge;;\n- : (int * int) list = [(4, 3); (3, 2); (2, 1); (3, 4); (2, 3); (1, 2)]\n```\n\nThe relation `edge` is really intensional: if we add axioms to it,\n`CI.Rel2.find` will return an updated view.\n\n```ocaml\n# CI.Rel2.transitive db edge;;\n- : unit = ()\n# CI.Rel2.find db edge;;\n- : (int * int) list =\n[(1, 3); (2, 4); (1, 4); (4, 1); (3, 1); (4, 2); (4, 3); (3, 2); (2, 1);\n (1, 1); (3, 3); (4, 4); (2, 2); (3, 4); (2, 3); (1, 2)]\n```\n\nOne can also directly load a Datalog file (atoms: ints and strings) and access\nit using (properly typed) relations:\n\n```ocaml\n# let db = CI.Logic.DB.create ();;\nval db : CI.Logic.DB.t = \u003cabstr\u003e\n# CI.Parse.load_file db \"tests/clique10.pl\";;\n- : bool = true\n# let edge = CI.Rel2.create ~k1:CI.Univ.int ~k2:CI.Univ.int \"edge\";;\nval edge : (int, int) CI.Rel2.t = \u003cabstr\u003e\n# let reachable = CI.Rel2.create ~k1:CI.Univ.int ~k2:CI.Univ.int \"reachable\";;\nval reachable : (int, int) CI.Rel2.t = \u003cabstr\u003e\n# CI.Rel2.find db reachable;;\n- : (int * int) list =\n[(5, 0); (5, 1); (4, 0); (5, 2); (4, 1); (3, 0); (10, 7); (5, 3); (10, 8);\n (9, 7); (4, 2); (3, 1); (2, 0); (5, 4); (10, 9); (9, 8); (8, 7); (4, 3);\n (3, 2); (2, 1); (1, 0); (5, 5); (10, 10); (9, 9); (8, 8); (7, 7); (4, 4);\n (3, 3); (2, 2); (1, 1); (0, 0); (0, 1); (1, 2); (2, 3); (3, 4); (4, 5);\n (5, 6); (6, 7); (7, 8); (8, 9); (9, 10); (8, 10); (7, 9); (6, 8); (5, 7);\n (4, 6); (3, 5); (2, 4); (1, 3); (0, 2); (7, 10); (6, 9); (5, 8); (4, 7);\n (3, 6); (2, 5); (1, 4); (0, 3); (6, 10); (5, 9); (4, 8); (3, 7); (2, 6);\n (1, 5); (0, 4); (5, 10); (4, 9); (3, 8); (2, 7); (1, 6); (0, 5); (4, 10);\n (3, 9); (2, 8); (1, 7); (0, 6); (3, 10); (2, 9); (1, 8); (0, 7); (2, 10);\n (1, 9); (0, 8); (1, 10); (0, 9); (0, 10)]\n```\n\n## Documentation\n\nYou can consult the [online documentation](https://c-cube.github.io/datalog)\n\n## License\n\nThe code is distributed under the [bsd_license](http://opensource.org/licenses/BSD-2-Clause)\nSee the `LICENSE` file.\n\nBuild\n=====\n\nIt is recommended to use opam: `opam install datalog`.\n\nManual build:\n\nYou need **OCaml \u003e= 4.02** with [dune](https://github.com/ocaml/dune). Just type in the root directory:\n\n```sh non-deterministic\n$ make\n$ cp src/bottom_up_cli/datalog_cli.exe ./datalog_cli\n```\n\n## How to use it\n\nThere are two ways to use `datalog`:\n\n- With the command line tool, `datalog_cli.exe`, or `datalog_cli` if you\n  installed it on your system; just type in\n\n```sh non-deterministic\n$ ./src/datalog_cli \u003cproblem_file\u003e\n```\n\n- The libraries `datalog`, `datalog.top_down`, `datalog.unix`, `datalog.caml_interface`.\n  See the `.mli` files for documentation, or the online documentation.\n  For both `Datalog_top_down` and `Datalog.BottomUp`, functors are\n  provided to use your own datatype for symbols (constants);\n  however, a default implementation with strings as symbols is available as\n  `Datalog.Default` (which is used by the parser `Datalog.Parser`)\n  for bottom-up and in `Datalog_top_down.Default` for top-down.\n\nA few example files, suffixed with `.pl`, can be found in `tests/`. For instance, you\ncan try:\n\n```sh\n$ cat tests/clique10.pl\n% generate problem of size 10\nreachable(X,Y) :- edge(X,Y).\nreachable(X,Y) :- edge(X,Z), reachable(Z,Y).\nsame_clique(X,Y) :- reachable(X,Y), reachable(Y,X).\nedge(0, 1).\nedge(1, 2).\nedge(2, 3).\nedge(3, 4).\nedge(4, 5).\nedge(5, 0).\nedge(5, 6).\nedge(6, 7).\nedge(7, 8).\nedge(8, 9).\nedge(9, 10).\nedge(10, 7).\n$ ./datalog_cli tests/clique10.pl --pattern 'same_clique(1,X)'\n% start datalog\n% parse file tests/clique10.pl\n% process 15 clauses\n% computing fixpoint...\n% done.\n% facts matching pattern same_clique(1, X0):\n  same_clique(1, 4).\n  same_clique(1, 5).\n  same_clique(1, 3).\n  same_clique(1, 2).\n  same_clique(1, 1).\n  same_clique(1, 0).\n...\n```\n\nOr\n\n```sh\n$ ./datalog_cli tests/graph200.pl --size --sum reachable\n% start datalog\n% parse file tests/graph200.pl\n% process 205 clauses\n% computing fixpoint...\n% done.\n% size of saturated set: 41209\n% number of fact with head reachable: 40401\n...\n```\n\nOr\n\n```sh\n$ ./datalog_cli tests/graph10.pl --goal 'increasing(3,7)' --pattern 'increasing(3,X)'\n% start datalog\n% parse file tests/graph10.pl\n% process 15 clauses\n% computing fixpoint...\n% done.\n% facts matching pattern increasing(3, X0):\n  increasing(3, 10).\n  increasing(3, 7).\n  increasing(3, 6).\n  increasing(3, 4).\n  increasing(3, 5).\n  increasing(3, 8).\n  increasing(3, 9).\n...\n```\n\nOr\n\n```sh\n$ ./datalog_cli tests/small.pl --query '(X,Y) :- ancestor(X,john), father(X,Y), not mother(Y,Z)'\n% start datalog\n% parse file tests/small.pl\n% process 12 clauses\n% computing fixpoint...\n% done.\n% query plan: (match[0] ancestor(X0, john) |\u003e\u003c| match[1,0] father(X0, X1)) |\u003e match[2,1] mother(X1, X2)\n% query answer:\n    'jean-jacques', alphonse\n    brad, john\n...\n```\n\n## Aggregates in top-down:\n\n```prolog\n$ cat test.pl\nfoo(a, 1).\nfoo(a, 2).\nfoo(b, 10).\nfoo(b, 11).\nfoo(c, 0).\n\nbar(A, S) :- S := sum B : foo(A, B).\n\n$ topDownCli -load foo.pl -builtin '(X,Y) :- bar(X,Y)'\n  (a, 3).\n  (b, 21).\n  (c, 0).\n```\n\n## TODOs/ideas\n\n- Goal subsumption\n- Clause subsumption (when selected lit is ground)\n- Clause retraction\n- Library of standard interpreted predicates\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Fdatalog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-cube%2Fdatalog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Fdatalog/lists"}