{"id":21665914,"url":"https://github.com/triska/clpfd","last_synced_at":"2026-01-04T20:02:09.972Z","repository":{"id":83451293,"uuid":"44907172","full_name":"triska/clpfd","owner":"triska","description":"Constraint Logic Programming over Finite Domains","archived":false,"fork":false,"pushed_at":"2020-01-07T09:24:31.000Z","size":843,"stargazers_count":173,"open_issues_count":1,"forks_count":11,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-01-25T08:09:34.559Z","etag":null,"topics":["clp","constraint-programming","constraints","integer-arithmetic","prolog","teaching"],"latest_commit_sha":null,"homepage":"https://www.metalevel.at/prolog/clpfd","language":"Prolog","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/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":"2015-10-25T11:27:08.000Z","updated_at":"2025-01-14T15:16:16.000Z","dependencies_parsed_at":"2023-10-15T16:56:15.857Z","dependency_job_id":null,"html_url":"https://github.com/triska/clpfd","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%2Fclpfd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpfd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpfd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/triska%2Fclpfd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/triska","download_url":"https://codeload.github.com/triska/clpfd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244563633,"owners_count":20472893,"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":["clp","constraint-programming","constraints","integer-arithmetic","prolog","teaching"],"created_at":"2024-11-25T11:18:40.002Z","updated_at":"2026-01-04T20:02:04.926Z","avatar_url":"https://github.com/triska.png","language":"Prolog","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CLP(FD) \u0026mdash; Constraint Logic Programming over Finite Domains\n\nCLP(FD), Constraint Logic Programming over Finite Domains, is\navailable in SWI-Prolog as\n[**library(clpfd)**](http://eu.swi-prolog.org/man/clpfd.html).\n\nThis repository contains usage examples that illustrate important\nconcepts and principles of the CLP(FD) library.\n\n[clpfd.pdf](clpfd.pdf) is a _shortened version_ of the library\ndocumentation, intended as supplementary lecture material.\n\nRead [**The Power of Prolog**](https://www.metalevel.at/prolog) for\nmore information, and in particular the introduction to [declarative\ninteger arithmetic](https://www.metalevel.at/prolog/clpfd).\n\nSee also the successor library, [**CLP(Z)**](https://github.com/triska/clpz).\n\nIn the following, it is assumed that you have put the following\ndirective in your `.swiplrc` initialisation file:\n\n    :- use_module(library(clpfd)).\n\nPutting this directive in your initialisation file is the recommended\nway to make integer constraints available in **all your programs**.\nThis is advisable because almost all Prolog programs also reason about\nintegers in one way or another.\n\n## ERROR: is/2: Arguments are not sufficiently instantiated\n\nDoes an error like the following seem familiar to you?\n\n\u003cpre\u003e\n?- 3 is 1+Y.\n\u003cb\u003eERROR: is/2: Arguments are not sufficiently instantiated\u003c/b\u003e\n\u003c/pre\u003e\n\nCLP(FD) puts an end to such low-level limitations:\n\n\u003cpre\u003e\n?- 3 #= 1+Y.\n\u003cb\u003eY = 2.\u003c/b\u003e\n\u003c/pre\u003e\n\nWhen learning Prolog, use *constraints* to free your mind from\nprocedural considerations, and focus on a *declarative* reading!\n\n## Using CLP(FD) constraints\n\nCLP(FD) is an instance of the general CLP(.) scheme, extending logic\nprogramming with reasoning over specialised domains.\n\nIn the case of CLP(FD), the domain is the set of _integers_.\n\nCLP(FD) constraints like\n[`(#=)/2`](http://eu.swi-prolog.org/pldoc/doc_for?object=%23%3D%20/%202),\n[`(#\\=)/2`](http://eu.swi-prolog.org/pldoc/doc_for?object=%23%5C%3D%20/%202),\nand\n[`(#\u003c)/2`](http://eu.swi-prolog.org/pldoc/doc_for?object=%23%3C%20/%202)\nare meant to be used as pure alternatives for lower-level arithmetic\nprimitives over integers. Importantly, they can be used in *all\ndirections*.\n\nFor example, we can use CLP(FD) constraints to obtain a version of\n`n_factorial/2` that can be used as a true relation:\n\n    n_factorial(0, 1).\n    n_factorial(N, F) :-\n            N #\u003e 0,\n            N1 #= N - 1,\n            F #= N * F1,\n            n_factorial(N1, F1).\n\nThis works in all directions, for example:\n\n    ?- n_factorial(47, F).\n    258623241511168180642964355153611979969197632389120000000000 ;\n    false.\n\nand also:\n\n    ?- n_factorial(N, 1).\n    N = 0 ;\n    N = 1 ;\n    false.\n\nand also in the most general case:\n\n    ?- n_factorial(N, F).\n    N = 0,\n    F = 1 ;\n    N = F, F = 1 ;\n    N = F, F = 2 ;\n    N = 3,\n    F = 6 .\n\n## Example programs\n\nThis repository contains several example programs. The main predicates\nare all completely pure and can be used as true relations. This means\nthat you can use the *same* program to:\n\n* *find* a single solution\n* *enumerate* all solutions\n* *complete* partially instantiated solutions\n* *validate* fully instantiated solutions.\n\nTo get an idea of the power, usefulness and scope of CLP(FD)\nconstraints, I recommend you work through the examples in the\nfollowing order:\n\n1. [**n_factorial.pl**](n_factorial.pl): Shows how to use CLP(FD)\n   constraints for **declarative integer arithmetic**, obtaining very\n   general programs that can be used in all directions. Declarative\n   integer arithmetic is the simplest and most common use of CLP(FD)\n   constraints. They are easy to understand and use this way, and\n   often increase generality and logical purity of your code.\n\n2. [**sendmory.pl**](sendmory.pl): A simple cryptoarithmetic puzzle.\n   The task is to assign one of the digits 0,...,9 to each of the\n   letters S,E,N,D,M,O,R and Y in such a way that the following\n   calculation is valid, and no leading zeroes appear:\n\n            S E N D\n          + M O R E\n          ---------\n        = M O N E Y\n\n   This example illustrates several very important concepts:\n\n   * It is the first example that shows **residual constraints** for the\n     most general query. They are equivalent to the original query.\n\n   * It is good practice to separate the **core relation** from\n     `labeling/2`, so that termination and determinism can be observed\n     without an expensive search for concrete solutions. See the\n     [CLP(FD) documentation](http://eu.swi-prolog.org/man/clpfd.html)\n     for more information about this subject.\n\n   * You can use this example to illustrate that the CLP(FD) system is able\n     to **propagate** many things that can also be found with human\n     reasoning. For example, due to the nature of the above calculation and\n     the prohibition of leading zeroes, `M` is necessarily 1.\n\n3. [**sudoku.pl**](sudoku.pl): Uses CLP(FD) constraints to model and solve\n   a simple and well-known puzzle. This example is well suited for\n   understanding the impact of different **propagation strengths**: Use it\n   to compare\n   [`all_different/1`](http://eu.swi-prolog.org/pldoc/man?predicate=all_different/1)\n   and\n   [`all_distinct/1`](http://eu.swi-prolog.org/pldoc/man?predicate=all_distinct/1)\n   on different puzzles:\n\n   ![](figures/filler.png) ![Sudoku with all_different/1](figures/sudoku_all_different.png) ![](figures/filler20.png) ![Sudoku with all_distinct/1](figures/sudoku_all_distinct.png)\n\n   The small dots in each cell indicate how many elements are pruned\n   by different **consistency techniques**. In many Sudoku puzzles,\n   using `all_distinct/1` makes labeling unnecessary. Does this mean that\n   we can forget `all_different/1` entirely?\n\n4. [**magic_square.pl**](magic_square.pl): CLP(FD) formulation of [*magic\n   squares*](http://mathworld.wolfram.com/MagicSquare.html). This is a good\n   example to learn about **symmetry breaking** constraints: Consider how\n   you can eliminate solutions that are rotations, reflections etc. of\n   other solutions, by imposing suitable further constraints. For example,\n   the following two solutions are essentially identical, since one can be\n   obtained from the other by reflecting elements along the main diagonal:\n\n   ![](figures/filler.png) ![Magic square solution](figures/magic_square1.png) ![](figures/filler20.png) ![Magic square transposed](figures/magic_square2.png)\n\n   Can you impose additional constraints so that you get only a single\n   solution in such cases, without losing any solutions that do not\n   belong to the same equivalence class? How many solutions are there\n   for N=4 that are unique up to isomorphism?\n\n5. [**magic_hexagon.pl**](magic_hexagon.pl): Uses CLP(FD) to describe a\n   [*magic hexagon*](http://mathworld.wolfram.com/MagicHexagon.html) of\n   order 3. The task is to place the integers 1,...,19 in the following\n   grid so that the sum of all numbers in a straight line (there are lines\n   of length 3, 4 and 5) is equal to 38. One solution of this task is shown\n   in the right picture:\n\n   ![](figures/filler.png) ![Magic hexagon grid](figures/magic_hexagon.png) ![](figures/filler20.png) ![Magic hexagon solution](figures/magic_hexagon_solution.png)\n\n   This is an example of a task that looks very simple at first, yet\n   is almost impossibly hard to solve manually. It is easy to solve\n   with CLP(FD) constraints though. Use the constraint solver to show\n   that the solution of this task is unique up to isomorphism.\n\n6. [**n_queens.pl**](n_queens.pl): Model the so-called [*N-queens\n   puzzle*](https://en.wikipedia.org/wiki/Eight_queens_puzzle) with CLP(FD)\n   constraints. This example is a good candidate to experiment with\n   different **search strategies**, specified as options of\n   [`labeling/2`](http://eu.swi-prolog.org/pldoc/man?predicate=labeling/2).\n   For example, using the labeling strategy `ff`, you can easliy find\n   solutions for 100 queens and more. Sample solutions for 8 and 50 queens:\n\n   ![](figures/filler.png) ![Solution for 8 queens](figures/queens8_solution.png) ![](figures/filler20.png) ![Solution for 50 queens](figures/queens50_solution.png)\n\n   Try to find solutions for larger N. Reorder the variables so that\n   `ff` breaks ties by selecting more central variables first.\n\n7. [**knight_tour.pl**](knight_tour.pl): Closed Knight's Tour using CLP(FD)\n   constraints. This is an example of using a more complex **global\n   constraint** called\n   [`circuit/1`](http://eu.swi-prolog.org/pldoc/man?predicate=circuit/1).\n   It shows how a problem can be transformed so that it can be expressed\n   with a global constraint. Sample solutions, using an 8x8 and a 16x16\n   board:\n\n   ![](figures/filler.png) ![Closed knight's tour on an 8x8 board](figures/knight8_solution.png) ![](figures/filler20.png) ![Closed knight's tour on a 16x16 board](figures/knight16_solution.png)\n\n   Decide whether `circuit/1` can also be used to model tours that are\n   not necessarily closed. If not, why not? If possible, do it.\n\n8. [**tasks.pl**](tasks.pl): A task scheduling example, using the\n   [`cumulative/2`](http://eu.swi-prolog.org/pldoc/man?predicate=cumulative/2)\n   global constraint. The `min/1` labeling option is used to minimize\n   the total duration.\n\n   ![](figures/filler.png) ![Task scheduling](figures/tasks.png)\n\n\n## Animations\n\nWhen studying Prolog and CLP(FD) constraints, it is often very useful\nto show *animations* of search processes. An instructional example:\n\n[**N-queens animation**](https://www.metalevel.at/queens/): This\nvisualizes the search process for the N-queens example.\n\nYou can use similar PostScript instructions to create [custom\nanimations](https://www.metalevel.at/postscript/animations) for\nother examples.\n\n## Propagation strength of CLP(FD) constraints\n\nSince integer arithmetic is in general *undecidable*, CLP(FD)\nconstraints are necessarily *incomplete*. This means that you cannot,\nin general, take the fact that a CLP(FD) constraint *succeeds* as an\nindication that there are any solutions. Therefore, you need to use\n[`call_residue_vars/2`](http://eu.swi-prolog.org/pldoc/man?predicate=call_residue_vars/2)\nto see if any constraints are still pending. For example:\n\n    declarative_false :-\n            X #\u003c Y,\n            Y #\u003c X.\n\nWith the above program, we get:\n\n    ?- declarative_false.\n    true.\n\nhowever, it is in fact `false`, because there are no solutions! The\ntoplevel has omitted important constraints that are still pending. You\ncan make them visible by wrapping the goal in `call_residue_vars/2`:\n\n    ?- call_residue_vars(declarative_false, Vs).\n    Vs = [X1, X2],\n    X1#=\u003cX2+ -1,\n    X2#=\u003cX1+ -1.\n\nThere is a solution only *if* you can satisfy these residual goals.\nCan\u0026nbsp;you?\n\n## Defaulty syntax and monotonicity\n\n### Default execution mode: Defaulty syntax\n\nWe have now seen several examples of CLP(FD) constraints being true\nrelations that can be used in all directions.\n\nAlas, some non-relational deficiencies still remain in the default\nmode of `library(clpfd)`. For example, consider the interaction:\n\n\u003cpre\u003e\n?- X = 1+1, X #= 2.\n\u003cb\u003eX = 1+1\u003c/b\u003e.\n\u003c/pre\u003e\n\nand contrast it with exchanging the two goals:\n\n\u003cpre\u003e\n?- X #= 2, X = 1+1.\n\u003cb\u003efalse\u003c/b\u003e.\n\u003c/pre\u003e\n\nThis difference is obvisouly undesirable: It breaks *commutativity*\nthat we expect from logical conjunction. Even worse, this breaks\n**monotonicity**: By *adding* a further constraint, we obtain new\nsolutions:\n\n\u003cpre\u003e\n?- \u003cb\u003eX = 1+1\u003c/b\u003e, X #= 2, X = 1+1.\n\u003cb\u003eX = 1+1\u003c/b\u003e.\n\u003c/pre\u003e\n\nHow can such problematic cases even arise? The reason is that CLP(FD)\nexpressions are *defaulty*: In CLP(FD) expressions, a logical\n*variable* is always regarded as standing for a concrete *integer*,\nalthough declaratively, it also stands for other\nCLP(FD)\u0026nbsp;expressions that *also* make a given constraint true. For\nexample, when we post the constraint:\n\n    ?- X #= 2.\n\nthen we get the *single* solution `X = 2`. It is clear though that,\nfrom a declarative point of view, `X = 1+1`, `X = 0+2`, `X = 3-1+0`\nand other CLP(FD)\u0026nbsp;expressions are also perfectly admissible\nsolutions. However, the constraint solver impurely *commits* to\ntreating each CLP(FD)\u0026nbsp;variable as standing for a single integer.\n\nThe way to avoid defaultyness is, as always, to equip all entities\nwith a *dedicated functor*. This way, the cases can be cleanly\ndistinguished.\n\n### Dedicated syntax for CLP(FD) variables\n\nFor this reason, `library(clpfd)` features a **dedicated syntax** to\nmark variables that stand for **concrete integers**. This is\naccomplished by wrapping them with\u0026nbsp;`#/1` (preferred)\nor\u0026nbsp;`?/1`. For example:\n\n    ?- #(X) #= 2.\n    X = 2.\n\nIf we consistently use this syntax in CLP(FD) constraints, then the\ndiscrepancy above cannot arise:\n\n\u003cpre\u003e\n?- X = 1+1, #(X) #= 2.\n\u003cb\u003eERROR\u003c/b\u003e: Type error: `integer' expected, found `1+1' (a compound)\n\u003c/pre\u003e\n\nand after exchanging the goals:\n\n\u003cpre\u003e\n?- #(X) #= 2, X = 1+1.\n\u003cb\u003efalse\u003c/b\u003e.\n\u003c/pre\u003e\n\nNote that a `type error` can be replaced by silent failure, so the two\ncases are now really declaratively equivalent.\n\n### Ensuring monotonicity: `clpfd_monotonic`\n\nIf you set the Prolog flag `clpfd_monotonic` to `true`, then CLP(FD)\nis **monotonic**: In that mode, you get a clean `instantiation error`\nif you use a variable *without* the `#/1`\u0026nbsp;wrapper in\nCLP(FD)\u0026nbsp;constraints.\n\nFor example:\n\n\u003cpre\u003e\n?- set_prolog_flag(clpfd_monotonic, true).\ntrue.\n\n?- X #= 2.\n\u003cb\u003eERROR:\u003c/b\u003e Arguments are not sufficiently instantiated\n\n?- #(X) #= 2.\nX = 2.\n\u003c/pre\u003e\n\nSet `clpfd_monotonic` to `true` to enjoy the utmost relational\nbenefits of CLP(FD).\n\n## An impure alternative: Low-level integer arithmetic\n\nSuppose for a moment that CLP(FD) constraints were not available in\nyour Prolog system, or that you do not want to use them. How do we\nformulate `n_factorial/2` with more primitive integer arithmetic?\n\nIn our first attempt, we simply replace the declarative CLP(FD)\nconstraints by lower-level arithmetic predicates and obtain:\n\n    n_factorial(0, 1).\n    n_factorial(N, F) :-\n            N \u003e 0,\n            N1 is N - 1,\n            F is N * F1,\n            n_factorial(N1, F1).\n\nUnfortunately, this does not work at all, because lower-level\narithmetic predicates are *moded*: This means that their arguments\nmust be sufficiently instantiated at the time they are invoked. In\nfact, SWI-Prolog does not even compile the above code but yields an\nerror at compilation time. Therefore, we must reorder the goals\nand\u0026nbsp;\u0026mdash; somewhat annoyingly\u0026nbsp;\u0026mdash; change this for\nexample to:\n\n    n_factorial(0, 1).\n    n_factorial(N, F) :-\n            N \u003e 0,\n            N1 is N - 1,\n            n_factorial(N1, F1),\n            F is N * F1.\n\nNaive example queries inspired more by *functional* than by\n*relational* thinking may easily mislead us into believing that this\nversion is working correctly:\n\n    ?- n_factorial(6, F).\n    F = 720 ;\n    false.\n\nAnother example:\n\n    ?- n_factorial(3, F).\n    F = 6 ;\n    false.\n\nBut what about *more general* queries? For example:\n\n    ?- n_factorial(N, F).\n    N = 0,\n    F = 1 ;\n    ERROR: n_factorial/2: Arguments are not sufficiently instantiated\n\nUnfortunately, this version thus cannot be directly used to enumerate\nmore than one solution, which is another severe drawback in comparison\nwith the pure version.\n\nYou can make the deficiency a lot worse by arbitrarily adding\na\u0026nbsp;`!/0` somewhere. Using `!/0` is a quite reliable way to destroy\nalmost all declarative properties of your code in most cases, and this\nexample is no exception:\n\n    n_factorial(0, 1) :- !.\n    n_factorial(N, F) :-\n            N \u003e 0,\n            N1 is N - 1,\n            n_factorial(N1, F1),\n            F is N * F1.\n\nThis version appears in several places. The fact that the following\ninteraction *incorrectly* tells us that there is exactly one solution of\nthe factorial relation is apparently no cause for concern there:\n\n    ?- n_factorial(N, F).\n    N = 0,\n    F = 1.\n\nZero and one are the only important integers in any case, if you are\nmostly interested in programming at a very low level.\n\nFor more usable and general programs, I therefore recommend you stick\nto CLP(FD) constraints for integer arithmetic. You can place pure\ngoals in any order without changing the declarative meaning of your\nprogram, just as you would expect from logical conjunction. For\nexample:\n\n    n_factorial(0, 1).\n    n_factorial(N, F) :-\n            N #\u003e 0,\n            N1 #= N - 1,\n            n_factorial(N1, F1),\n            F #= N * F1.\n\nReordering pure goals can change **termination properties**, but it\ncannot incorrectly lead to failure where there is in fact a solution.\nTherefore, we get with the above CLP(FD) version for example:\n\n    ?- n_factorial(N, 3).\n    \u003cloops\u003e\n\nAnd now we can reason completely declaratively about the code: Knowing\nthat (a)\u0026nbsp;CLP(FD) constraints are *pure* and can thus be reordered\nquite liberally and (b)\u0026nbsp;that posting CLP(FD) constraints *always\nterminates*, we *know* that placing CLP(FD) constraints earlier can at\nmost *improve*, never *worsen* the desirable termination properties.\n\nTherefore, we change the definition to the version shown initially:\n\n    n_factorial(0, 1).\n    n_factorial(N, F) :-\n            N #\u003e 0,\n            N1 #= N - 1,\n            F #= N * F1,\n            n_factorial(N1, F1).\n\nThe sample query now terminates:\n\n    ?- n_factorial(N, 3).\n    false.\n\nUsing CLP(FD) constraints has allowed us to improve the termination\nproperties of this predicate by purely declarative reasoning.\n\n## Current and future work\n\nAll current and future development of this library takes place as\n[**CLP(Z)**](https://github.com/triska/clpz) for\n[SICStus\u0026nbsp;Prolog](https://sicstus.sics.se/).\n\nFor ISO conformance, higher performance and professional support, it\nis strongly recommended that you obtain a copy of SICStus\u0026nbsp;Prolog\nand use it for all serious Prolog development.\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[**Tom Schrijvers**](http://people.cs.kuleuven.be/~tom.schrijvers/),\nwho has generously contributed several important constraint libraries\nto SWI-Prolog\n([`dif/2`](http://eu.swi-prolog.org/pldoc/man?predicate=dif/2)!!),\nand from whom I learned a lot.\n\n[**Ulrich Neumerkel**](http://www.complang.tuwien.ac.at/ulrich/), who\nintroduced me to constraint logic programming and was the first and\nmost determined tester of my library, filing hundreds of comments. If\nyou are teaching Prolog, I recommend you check out his [GUPU\nsystem](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 and constraint\nsatisfaction highly motivated me to work in this area.\n\n[**Mats Carlsson**](https://www.sics.se/~matsc/), the designer and main\nimplementor of SICStus Prolog and its superb [CLP(FD)\nlibrary](https://sicstus.sics.se/sicstus/docs/latest4/html/sicstus.html/lib_002dclpfd.html#lib_002dclpfd).\nFor any serious use of CLP(FD) constraints, make sure to check out his\nelegant and fast system.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftriska%2Fclpfd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftriska%2Fclpfd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftriska%2Fclpfd/lists"}