{"id":21665909,"url":"https://github.com/triska/clpb","last_synced_at":"2026-01-04T14:06:18.252Z","repository":{"id":19447677,"uuid":"22691770","full_name":"triska/clpb","owner":"triska","description":"Boolean Constraint Solving in Prolog","archived":false,"fork":false,"pushed_at":"2024-12-08T20:01:20.000Z","size":312,"stargazers_count":38,"open_issues_count":0,"forks_count":5,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-25T08:09:33.991Z","etag":null,"topics":["bdd","clp","constraint-programming","constraints","independent-sets","matchsticks-puzzle","prolog","sat","satisfiability"],"latest_commit_sha":null,"homepage":"https://www.metalevel.at/clpb/","language":"Prolog","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"torvalds/libdc-for-dirk","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/triska.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}},"created_at":"2014-08-06T17:32:12.000Z","updated_at":"2024-12-22T11:43:24.000Z","dependencies_parsed_at":"2022-09-05T14:21:55.067Z","dependency_job_id":"bd846e4d-ada8-4d7c-9ede-7b21099c760d","html_url":"https://github.com/triska/clpb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/triska","download_url":"https://codeload.github.com/triska/clpb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244563623,"owners_count":20472892,"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":["bdd","clp","constraint-programming","constraints","independent-sets","matchsticks-puzzle","prolog","sat","satisfiability"],"created_at":"2024-11-25T11:18:36.192Z","updated_at":"2026-01-04T14:06:18.163Z","avatar_url":"https://github.com/triska.png","language":"Prolog","readme":"# CLP(B): Constraint Logic Programming over Boolean variables\n\nCLP(B), Constraint Logic Programming over Boolean variables, is\navailable in Scryer\u0026nbsp;Prolog and SWI-Prolog as\n[**library(clpb)**](https://www.scryer.pl/clpb.html).\n\nThis repository contains usage examples and tests of the library.\n\n[**clpb.pdf**](clpb.pdf) is a _shortened version_ of the library\ndocumentation, intended as supplementary lecture material.\n\n**Project page**:\n\n[**https://www.metalevel.at/clpb/**](https://www.metalevel.at/clpb/)\n\n## Using CLP(B) constraints\n\nMany of the examples use\n[**DCG notation**](https://www.metalevel.at/prolog/dcg) to\ndescribe lists of clauses. This lets you easily reason about the\nconstraints that are being posted, change the order in which they are\nposted, and in general more conveniently experiment with\u0026nbsp;CLP(B).\nIn some examples, it is faster to post a single big conjunction\ninstead of several smaller ones.\n\nI recommend you start with the following examples:\n\n1. [**knights_and_knaves.pl**](knights_and_knaves.pl): Solution of\n   several Boolean puzzles that appear in Raymond Smullyan's _What Is\n   the Name of this Book_ and Maurice Kraitchik's _Mathematical\n   Recreations_. These examples and other\n   [**logic\u0026nbsp;puzzles**](https://www.metalevel.at/prolog/puzzles)\n   are good starting points for learning more about\u0026nbsp;CLP(B).\n\n2. [**xor.pl**](xor.pl): Verification of a digital circuit, expressing\n   XOR with NAND\u0026nbsp;gates:\n\n   ![](figures/filler.png) ![XOR with NAND gates](figures/xor.png)\n\n   This example uses *universally quantified* variables to express the\n   output as a function of the input variables in residual goals.\n\n3. [**matchsticks.pl**](matchsticks.pl): A puzzle involving\n   matchsticks. See below for more information.\n\n4. [**cycle_n.pl**](cycle_n.pl): Uses Boolean constraints to express\n   independent sets and *maximal* independent sets (also called\n   *kernels*) of the\n   [cycle graph](https://en.wikipedia.org/wiki/Cycle_graph)\u0026nbsp;\u003ci\u003eC\u003csub\u003eN\u003c/sub\u003e\u003c/i\u003e.\n   \n   ![](figures/filler.png) ![Cycle graph C_7](figures/cycle7.png) ![](figures/filler20.png) ![Kernel of C_7](figures/cycle7_kernel.png)\n\n    See below for more information about weighted solutions.\n\n5. [**euler_172.pl**](euler_172.pl): CLP(B) solution of Project Euler\n   [Problem 172](https://projecteuler.net/problem=172): How many\n   18-digit numbers\u0026nbsp;\u003ci\u003en\u003c/i\u003e (without leading zeros) are there\n   such that no digit occurs more than three times in\u0026nbsp;\u003ci\u003en\u003c/i\u003e?\n\n6. [**domino_tiling.pl**](domino_tiling.pl): Domino tiling of an\n   \u003ci\u003eM\u0026times;N\u003c/i\u003e\u0026nbsp;chessboard. Using CLP(B), it is easy to see\n   that there are 12,988,816\u0026nbsp;ways to cover an\n   8\u0026times;8\u0026nbsp;chessboard with dominoes:\n   \n   ![](figures/filler.png) ![Domino tiling of an 8x8 chessboard](figures/domino8x8.png) ![](figures/filler20.png) ![Domino tiling of a 2x8 chessboard](figures/domino2x8.png)\n\n   Interestingly, the\n   [Fibonacci numbers](http://mathworld.wolfram.com/FibonacciNumber.html)\n   arise when we count the number of domino tilings of\n   \u003cb\u003e2\u003c/b\u003e\u0026times;N\u0026nbsp;chessboards. An example is shown in the right\n   figure.\n\nOther examples are useful as benchmarks:\n\n- [**langford.pl**](langford.pl): Count the number of [Langford pairings](https://en.wikipedia.org/wiki/Langford_pairing).\n- [**n_queens.pl**](n_queens.pl): CLP(B) formulation of the\n  [N-queens puzzle](https://en.wikipedia.org/wiki/Eight_queens_puzzle).\n- [**pigeon.pl**](pigeon.pl): A simple allocation task.\n- [**schur.pl**](schur.pl): A problem related to\n  [Schur's number](http://mathworld.wolfram.com/SchurNumber.html) as\n  known from\n  [Ramsey theory](http://mathworld.wolfram.com/RamseyTheory.html).\n\nThe directory [**bddcalc**](bddcalc) contains a very simple calculator\nfor\u0026nbsp;BDDs.\n\n### Matchsticks puzzle\n\nIn [**matchsticks.pl**](matchsticks.pl), Boolean variables indicate\nwhether a matchstick is placed at a specific position. The task is to\neliminate all subsquares from the initial configuration in such a way\nthat the maximum number of matchsticks is left in place:\n\n![](figures/filler.png) ![Matchsticks initial configuration](figures/matchsticks1.png)\n\nWe can use the CLP(B) predicate `weighted_maximum/3` to show that we\nneed to remove at least 9 matchsticks to eliminate all subsquares.\n\n![](figures/filler.png) ![Matchsticks without any subsquares](figures/matchsticks2.png) ![](figures/filler.png) ![Exactly 7 subsquares remaining](figures/matchsticks3.png)\n\nThe left figure shows a sample solution, leaving the maximum number of\nmatchsticks\u0026nbsp;(31) in place. If you keep more matchsticks in place,\nsubsquares remain. For example, the right figure contains exactly\n7\u0026nbsp;subsquares, including the 4x4 outer square.\n\nCLP(B) constraints can be used to quickly generate, test and count\nsolutions of such puzzles, among many other applications. For example,\nthere are precisely 62,382,215,032 subsquare-free configurations that\nuse exactly 18\u0026nbsp;matchsticks. This is the maximum number of such\nconfigurations for any fixed number of matchsticks on this grid.\n\n### Independent sets and weighted kernels\n\nAs another example, consider the following graph:\n\n![](figures/filler20.png) ![Cycle graph with 100 nodes, C_100](figures/cycle100.png)\n\nIt is the so-called\n[_cycle graph_](https://en.wikipedia.org/wiki/Cycle_graph) with\n100\u0026nbsp;nodes, \u003ci\u003eC\u003csub\u003e100\u003c/sub\u003e\u003c/i\u003e. Using CLP(B) constraints, it\nis easy to see that this graph has exactly 792,070,839,848,372,253,127\n_independent sets_, and exactly 1,630,580,875,002 _maximal_\nindependent sets, which are also called _kernels_. The gray nodes in\nthe next picture show one such kernel:\n\n![](figures/filler20.png) ![Maximal independent set of C_100](figures/cycle100_maximum.png)\n\nSuppose that we assign each node \u003ci\u003en\u003csub\u003ej\u003c/sub\u003e\u003c/i\u003e the weight\n\u003ci\u003ew\u003csub\u003ej\u003c/sub\u003e\u0026nbsp;= \u0026nbsp;(-1)\u003csup\u003e\u0026nu;j\u003c/i\u003e, where \u003ci\u003e\u0026nu;j\u003c/i\u003e\ndenotes the number of ones in the binary representation\nof\u0026nbsp;\u003ci\u003ej\u003c/i\u003e. In the above figure, nodes with negative weight are\ndrawn as squares, and nodes with positive weight are drawn as circles.\n\nOnly 5 nodes (1, 25, 41, 73 and 97) of this kernel with 38 nodes have\nnegative weight in this case, for a total weight of 28. In this case,\nthe example shows a kernel with \u003ci\u003emaximum weight\u003c/i\u003e. It is easy to\nfind such kernels with the CLP(B) predicate `weighted_maximum/3`, and\nwe can also compute other interesting facts: For example, there are\nexactly 256 kernels of maximum weight in this case. There are exactly\n25,446,195,000 kernels with exactly 38 nodes. All kernels have between\n34 and 50 nodes. For any fixed number of nodes, the maximum number of\nkernels (492,957,660,000) is attained with 41 nodes, and among these\nkernels, the maximum total weight is 25.\n\nBy negating the coefficients of `weighted_maximum/3`, we can also find\nkernels with _minimum_ weight. For example:\n\n![](figures/filler20.png) ![Kernel of C_100 with minimum weight](figures/cycle100_minimum.png)\n\n## Implementation\n\nThe implementation of `library(clpb)` is based on ordered and reduced\n**Binary Decision Diagrams**\u0026nbsp;(BDDs). BDDs are an important data\nstructure for representing Boolean functions and have many virtues\nthat often allow us to solve interesting tasks efficiently.\n\nFor example, the CLP(B) constraint `sat(card([2],[X,Y,Z]))` is\ntranslated to the following\u0026nbsp;BDD:\n\n![](figures/filler20.png) ![BDD for sat(card([2],[X,Y,Z]))](http://www.metalevel.at/card.svg)\n\nTo inspect the BDD representation of Boolean constraints, set the\nProlog\u0026nbsp;flag `clpb_residuals` to\u0026nbsp;`bdd`. For example:\n\n    ?- set_prolog_flag(clpb_residuals, bdd).\n    true.\n\n    ?- sat(X+Y).\n    node(2)- (v(X, 0)-\u003etrue;node(1)),\n    node(1)- (v(Y, 1)-\u003etrue;false).\n\nUsing `library(clpb)` is a good way to learn more about BDDs. The\nvariable order is determined by the order in which the variables are\nfirst encountered in constraints. You can enforce arbitrary variable\norders by first posting a tautology such as `+[1,V1,V2,...,Vn]`.\n\nFor example:\n\n\u003cpre\u003e\n?- \u003cb\u003esat(+[1,Y,X])\u003c/b\u003e, sat(X+Y).\nnode(2)- (v(Y, 0)-\u003etrue;node(1)),\nnode(1)- (v(X, 1)-\u003etrue;false).\n\u003c/pre\u003e\n\nYou can render CLP(B)'s residual goals as BDDs in SWISH using the\n[**BDD\u0026nbsp;renderer**](http://swish.swi-prolog.org/example/render_bdd.swinb).\n\n## ZDD-based variant of `library(clpb)`\n\nThere is a limited alternative version of `library(clpb)`, based on\nZero-suppressed Binary Decision Diagrams (ZDDs).\n\nPlease see the [**zdd**](zdd) directory for more information. Try the\nZDD-based version for tasks where the BDD-based version runs out of\nmemory. You must use `zdd_set_vars/1` before using `sat/1` though.\n\n## Acknowledgments\n\nI am extremely grateful to:\n\n[**Jan Wielemaker**](http://eu.swi-prolog.org) for providing the\nProlog system that made all this possible in the first place.\n\n[**Ulrich Neumerkel**](http://www.complang.tuwien.ac.at/ulrich/), who\nintroduced me to constraint logic programming and CLP(B) in\nparticular. If you are teaching Prolog, I strongly recommend you check\nout his\n[GUPU\u0026nbsp;system](http://www.complang.tuwien.ac.at/ulrich/gupu/).\n\n[**Nysret Musliu**](http://dbai.tuwien.ac.at/staff/musliu/), my thesis\nadvisor, whose interest in combinatorial tasks, constraint\nsatisfaction and SAT\u0026nbsp;solving highly motivated me to work in this\narea.\n\n[**Mats Carlsson**](https://www.sics.se/~matsc/), the designer and\nmain implementor of SICStus Prolog and its visionary\n[CLP(B)\u0026nbsp;library](https://sicstus.sics.se/sicstus/docs/latest4/html/sicstus.html/lib_002dclpb.html#lib_002dclpb).\nFor any serious use of Prolog and constraints, make sure to check out\nhis elegant and fast system.\n\n[**Donald Knuth**](http://www-cs-faculty.stanford.edu/~uno/) for the\nsuperb treatment of BDDs and\u0026nbsp;ZDDs in his books and programs.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftriska%2Fclpb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftriska%2Fclpb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftriska%2Fclpb/lists"}