Skip to content
Snippets Groups Projects
Commit fc0e53ef authored by Michael Leuschel's avatar Michael Leuschel
Browse files

add send more money

parent 32861662
Branches
No related tags found
No related merge requests found
%% Cell type:markdown id:7359298e-63ac-4080-9139-aa90c8043b2a tags: %% Cell type:markdown id:7359298e-63ac-4080-9139-aa90c8043b2a tags:
# Introduction to Prolog # Introduction to Prolog
%% Cell type:markdown id:49fd5211 tags: %% Cell type:markdown id:49fd5211 tags:
### Propositions ### Propositions
Prolog programs consist of <b>clauses</b>. Prolog programs consist of <b>clauses</b>.
A clause is always terminated by a dot (```.```). A clause is always terminated by a dot (```.```).
The simplest clauses are facts. Here we define two propositions to be true: The simplest clauses are facts. Here we define two propositions to be true:
%% Cell type:code id:93e05f7b-a91c-4262-861e-a399e094b710 tags: %% Cell type:code id:93e05f7b-a91c-4262-861e-a399e094b710 tags:
``` prolog ``` prolog
rains. rains.
no_hat. no_hat.
``` ```
%% Output %% Output
%% Cell type:markdown id:b05ae74b tags: %% Cell type:markdown id:b05ae74b tags:
We can now ask the Prolog system whether it rains: We can now ask the Prolog system whether it rains:
%% Cell type:code id:20b05b2c tags: %% Cell type:code id:20b05b2c tags:
``` prolog ``` prolog
?-rains. ?-rains.
``` ```
%% Output %% Output
%% Cell type:markdown id:50c188fa tags: %% Cell type:markdown id:50c188fa tags:
More complicated clauses make use of the implication operator ```:-```. They are also called rules. Logically they stipulate that the left-hand side of the clause must be true if the right-hand side is true. The right-hand side can contain multiple propositions separated by commas. The comma can be read as a logical conjunction (and). More complicated clauses make use of the implication operator ```:-```. They are also called rules. Logically they stipulate that the left-hand side of the clause must be true if the right-hand side is true. The right-hand side can contain multiple propositions separated by commas. The comma can be read as a logical conjunction (and).
%% Cell type:code id:2b8b84a0 tags: %% Cell type:code id:2b8b84a0 tags:
``` prolog ``` prolog
carry_umbrella :- rains, no_hat. carry_umbrella :- rains, no_hat.
``` ```
%% Output %% Output
%% Cell type:code id:4e6314e8 tags: %% Cell type:code id:4e6314e8 tags:
``` prolog ``` prolog
?- carry_umbrella. ?- carry_umbrella.
``` ```
%% Output %% Output
%% Cell type:markdown id:161b0f75 tags: %% Cell type:markdown id:161b0f75 tags:
%% Cell type:markdown id:d7254b1b tags: %% Cell type:markdown id:d7254b1b tags:
### Predicates ### Predicates
Instead of propositions we can also use predicates with arguments within our clauses. The arguments to predicates denote objects for which the predicate is true. Arguments which start with an upper-case letter are logical variables. Below ```X``` is such a variable and it can stand for any object. Instead of propositions we can also use predicates with arguments within our clauses. The arguments to predicates denote objects for which the predicate is true. Arguments which start with an upper-case letter are logical variables. Below ```X``` is such a variable and it can stand for any object.
%% Cell type:code id:1d6eed4f tags: %% Cell type:code id:1d6eed4f tags:
``` prolog ``` prolog
human(sokrates). human(sokrates).
human(schopenhauer). human(schopenhauer).
human(locke). human(locke).
tiger(hobbes). tiger(hobbes).
mortal(X) :- human(X). mortal(X) :- human(X).
mortal(X) :- animal(X). mortal(X) :- animal(X).
animal(X) :- tiger(X). animal(X) :- tiger(X).
``` ```
%% Output %% Output
%% Cell type:markdown id:e645f31e tags: %% Cell type:markdown id:e645f31e tags:
You can now ask questions about logical consequences of your logic program. In simple queries you provide all arguments: You can now ask questions about logical consequences of your logic program. In simple queries you provide all arguments:
%% Cell type:code id:a2ab9e95 tags: %% Cell type:code id:a2ab9e95 tags:
``` prolog ``` prolog
?-human(locke). ?-human(locke).
``` ```
%% Output %% Output
%% Cell type:code id:838bc91a tags: %% Cell type:code id:838bc91a tags:
``` prolog ``` prolog
?- human(hobbes). ?- human(hobbes).
``` ```
%% Output %% Output
%% Cell type:code id:4d3217da tags: %% Cell type:code id:4d3217da tags:
``` prolog ``` prolog
?- animal(hobbes). ?- animal(hobbes).
``` ```
%% Output %% Output
%% Cell type:markdown id:c8d0600e tags: %% Cell type:markdown id:c8d0600e tags:
You can also use variables in queries, and Prolog will find values for the variables so that the result is a logical consequence of you program: You can also use variables in queries, and Prolog will find values for the variables so that the result is a logical consequence of you program:
%% Cell type:code id:93e47505 tags: %% Cell type:code id:93e47505 tags:
``` prolog ``` prolog
?- mortal(X). ?- mortal(X).
``` ```
%% Output %% Output
%% Cell type:markdown id:d82e2815 tags: %% Cell type:markdown id:d82e2815 tags:
In the standard Prolog console you can type a semicolong (```;```) to get more answers. Here in Jupyter we need to use ```jupyter:retry```. In the standard Prolog console you can type a semicolong (```;```) to get more answers. Here in Jupyter we need to use ```jupyter:retry```.
%% Cell type:code id:0c4d96e2 tags: %% Cell type:code id:0c4d96e2 tags:
``` prolog ``` prolog
jupyter:retry jupyter:retry
``` ```
%% Output %% Output
%% Cell type:code id:47e57f93 tags: %% Cell type:code id:47e57f93 tags:
``` prolog ``` prolog
jupyter:retry jupyter:retry
``` ```
%% Output %% Output
%% Cell type:code id:7fd70461 tags: %% Cell type:code id:7fd70461 tags:
``` prolog ``` prolog
jupyter:retry jupyter:retry
``` ```
%% Output %% Output
%% Cell type:code id:81724623 tags: %% Cell type:code id:81724623 tags:
``` prolog ``` prolog
jupyter:retry jupyter:retry
``` ```
%% Output %% Output
%% Cell type:markdown id:3dce4ccd tags: %% Cell type:markdown id:3dce4ccd tags:
Jupyter provides a feature to compute all solutions of a goal and display them in a table: Jupyter provides a feature to compute all solutions of a goal and display them in a table:
%% Cell type:code id:4d656338 tags: %% Cell type:code id:4d656338 tags:
``` prolog ``` prolog
jupyter:print_table(mortal(X)) jupyter:print_table(mortal(X))
``` ```
%% Output %% Output
X | X |
:- | :- |
sokrates | sokrates |
schopenhauer | schopenhauer |
locke | locke |
hobbes | hobbes |
%% Cell type:markdown id:d90546b0 tags: %% Cell type:markdown id:d90546b0 tags:
Prolog also has a built-in predicate called ```findall``` which can be used to find all solutions in one go: Prolog also has a built-in predicate called ```findall``` which can be used to find all solutions in one go:
%% Cell type:code id:a7478245 tags: %% Cell type:code id:a7478245 tags:
``` prolog ``` prolog
?-findall(X,mortal(X),Results). ?-findall(X,mortal(X),Results).
``` ```
%% Output %% Output
%% Cell type:markdown id:74c96ce2 tags: %% Cell type:markdown id:74c96ce2 tags:
### Prolog lists and using append ### Prolog lists and using append
The result is a Prolog list. Lists play an important role in Prolog and they can be written using square brackets. ```[]``` denotes the empty list. The built-in predicate ```append``` can be used to concatenate two lists: The result is a Prolog list. Lists play an important role in Prolog and they can be written using square brackets. ```[]``` denotes the empty list. The built-in predicate ```append``` can be used to concatenate two lists:
%% Cell type:code id:0352f53e tags: %% Cell type:code id:0352f53e tags:
``` prolog ``` prolog
?-append([sokrates,locke],[hobbes],R). ?-append([sokrates,locke],[hobbes],R).
``` ```
%% Output %% Output
%% Cell type:markdown id:fd8a78b7 tags: %% Cell type:markdown id:fd8a78b7 tags:
Lists can contain any kind of object, e.g., numbers but also other lists: Lists can contain any kind of object, e.g., numbers but also other lists:
%% Cell type:code id:9e3be61b tags: %% Cell type:code id:9e3be61b tags:
``` prolog ``` prolog
?-append([1,2,sokrates,3],[4,[sokrates],4],Out). ?-append([1,2,sokrates,3],[4,[sokrates],4],Out).
``` ```
%% Output %% Output
%% Cell type:markdown id:db2baf14 tags: %% Cell type:markdown id:db2baf14 tags:
One nice feature of logic programming is that the input/output relation is not pre-determined. One can run predicates backwards, meaning one can use ```append``` to deconstruct a list: One nice feature of logic programming is that the input/output relation is not pre-determined. One can run predicates backwards, meaning one can use ```append``` to deconstruct a list:
%% Cell type:code id:186fe078 tags: %% Cell type:code id:186fe078 tags:
``` prolog ``` prolog
?-append(X,Y,[1,2,3]). ?-append(X,Y,[1,2,3]).
``` ```
%% Output %% Output
%% Cell type:code id:de721f76 tags: %% Cell type:code id:de721f76 tags:
``` prolog ``` prolog
jupyter:retry. jupyter:retry.
``` ```
%% Output %% Output
%% Cell type:code id:ea9e3961 tags: %% Cell type:code id:ea9e3961 tags:
``` prolog ``` prolog
jupyter:retry. jupyter:retry.
``` ```
%% Output %% Output
%% Cell type:code id:e09505d2 tags: %% Cell type:code id:e09505d2 tags:
``` prolog ``` prolog
jupyter:retry. jupyter:retry.
``` ```
%% Output %% Output
%% Cell type:code id:52857ccd tags: %% Cell type:code id:52857ccd tags:
``` prolog ``` prolog
jupyter:retry. jupyter:retry.
``` ```
%% Output %% Output
%% Cell type:markdown id:aacfbf9d tags: %% Cell type:markdown id:aacfbf9d tags:
Variables can also appear multiple times in clauses or queries. Here we check if we can split a list in half: Variables can also appear multiple times in clauses or queries. Here we check if we can split a list in half:
%% Cell type:code id:12f78859 tags: %% Cell type:code id:12f78859 tags:
``` prolog ``` prolog
?-append(X,X,[a,b,a,b]). ?-append(X,X,[a,b,a,b]).
``` ```
%% Output %% Output
%% Cell type:markdown id:16ffb236 tags: %% Cell type:markdown id:16ffb236 tags:
With the underscore we indicate that we are not interested in an argument; it is an anonymous logical variable. Here we use this to find the last element of a list: With the underscore we indicate that we are not interested in an argument; it is an anonymous logical variable. Here we use this to find the last element of a list:
%% Cell type:code id:99bfae95 tags: %% Cell type:code id:99bfae95 tags:
``` prolog ``` prolog
?-append(_,[X],[a,b,c,d]). ?-append(_,[X],[a,b,c,d]).
``` ```
%% Output %% Output
%% Cell type:markdown id:466ece27 tags: %% Cell type:markdown id:466ece27 tags:
### Family tree example ### Family tree example
We now load a Prolog file describing the family tree of "Game of Thrones". We now load a Prolog file describing the family tree of "Game of Thrones".
%% Cell type:code id:5627c07e tags: %% Cell type:code id:5627c07e tags:
``` prolog ``` prolog
:- consult('prolog_files/1_got_family_tree.pl'). :- consult('prolog_files/1_got_family_tree.pl').
``` ```
%% Cell type:markdown id:068e1fdc tags: %% Cell type:markdown id:068e1fdc tags:
It contains facts for four basic predicates male/1, female/1, child/2 and couple/2. It contains facts for four basic predicates male/1, female/1, child/2 and couple/2.
%% Cell type:code id:428e3101 tags: %% Cell type:code id:428e3101 tags:
``` prolog ``` prolog
?-male(X). ?-male(X).
``` ```
%% Output %% Output
%% Cell type:markdown id:c2a8192b tags: %% Cell type:markdown id:c2a8192b tags:
We an now find the parents of X: We an now find the parents of X:
%% Cell type:code id:5134897e tags: %% Cell type:code id:5134897e tags:
``` prolog ``` prolog
?-male(X),child(X,Y). ?-male(X),child(X,Y).
``` ```
%% Output %% Output
%% Cell type:code id:cd9a4bf2 tags: %% Cell type:code id:cd9a4bf2 tags:
``` prolog ``` prolog
jupyter:retry. jupyter:retry.
``` ```
%% Output %% Output
%% Cell type:markdown id:fa7eb5e5 tags: %% Cell type:markdown id:fa7eb5e5 tags:
Let us now define derived predicates for father and mother: Let us now define derived predicates for father and mother:
%% Cell type:code id:edfb9af1 tags: %% Cell type:code id:edfb9af1 tags:
``` prolog ``` prolog
father(A,B) :- child(B,A),male(A). father(A,B) :- child(B,A),male(A).
mother(A,B) :- child(B,A),female(A). mother(A,B) :- child(B,A),female(A).
``` ```
%% Output %% Output
%% Cell type:code id:e8aaec06 tags: %% Cell type:code id:e8aaec06 tags:
``` prolog ``` prolog
?-father(A,'Sansa Stark'). ?-father(A,'Sansa Stark').
``` ```
%% Output %% Output
%% Cell type:markdown id:53b594a2 tags: %% Cell type:markdown id:53b594a2 tags:
We can visualise the father/mother relationships in graphical way in Jupyter: We can visualise the father/mother relationships in graphical way in Jupyter:
%% Cell type:code id:d4664fd8 tags: %% Cell type:code id:d4664fd8 tags:
``` prolog ``` prolog
parent_relation(A,B,'father') :- father(A,B). parent_relation(A,B,'father') :- father(A,B).
parent_relation(A,B,'mother') :- mother(A,B). parent_relation(A,B,'mother') :- mother(A,B).
``` ```
%% Output %% Output
%% Cell type:code id:08715fa2 tags: %% Cell type:code id:08715fa2 tags:
``` prolog ``` prolog
jupyter:print_transition_graph(parent_relation/3, 1, 2, 3). jupyter:print_transition_graph(parent_relation/3, 1, 2, 3).
``` ```
%% Output %% Output
%% Cell type:markdown id:e2ed5de7 tags: %% Cell type:markdown id:e2ed5de7 tags:
Let us now define the grandfather and grandmother relationships: Let us now define the grandfather and grandmother relationships:
%% Cell type:code id:313194bb tags: %% Cell type:code id:313194bb tags:
``` prolog ``` prolog
grandfather(A,B) :- child(B,C) , child(C,A), male(A). grandfather(A,B) :- child(B,C) , child(C,A), male(A).
grandmother(A,B) :- child(B,C) , child(C,A), female(A). grandmother(A,B) :- child(B,C) , child(C,A), female(A).
``` ```
%% Output %% Output
%% Cell type:code id:e0eed7cc tags: %% Cell type:code id:e0eed7cc tags:
``` prolog ``` prolog
?-grandfather(GF,'Sansa Stark'). ?-grandfather(GF,'Sansa Stark').
``` ```
%% Output %% Output
%% Cell type:markdown id:d0e8eb01 tags: %% Cell type:markdown id:d0e8eb01 tags:
Finally let us use recursion in Prolog to define arbitrary ancestors: Finally let us use recursion in Prolog to define arbitrary ancestors:
%% Cell type:code id:c2615402 tags: %% Cell type:code id:c2615402 tags:
``` prolog ``` prolog
parent(A,B) :- child(B,A). parent(A,B) :- child(B,A).
ancestor(A,B):- parent(A,B). ancestor(A,B):- parent(A,B).
ancestor(A,B):- parent(C,B), ancestor(A,C). ancestor(A,B):- parent(C,B), ancestor(A,C).
``` ```
%% Output %% Output
%% Cell type:code id:d2b8accc tags: %% Cell type:code id:d2b8accc tags:
``` prolog ``` prolog
?-ancestor(GF,'Sansa Stark'). ?-ancestor(GF,'Sansa Stark').
``` ```
%% Output %% Output
%% Cell type:code id:05f68119 tags: %% Cell type:code id:05f68119 tags:
``` prolog ``` prolog
jupyter:print_table(ancestor(X,'Sansa Stark')) jupyter:print_table(ancestor(X,'Sansa Stark'))
``` ```
%% Output %% Output
X | X |
:- | :- |
Eddard Stark | Eddard Stark |
Catelyn Stark | Catelyn Stark |
Rickard Stark | Rickard Stark |
Lyarra Stark | Lyarra Stark |
%% Cell type:markdown id:e6582326 tags:
### Send More Money Puzzle
Prolog is also a natural language to solve constraint satisfaction problems. In particular the CLP(FD) library is very useful here. It allows to solve constraints over finite domains.
%% Cell type:code id:da2e206f tags: %% Cell type:code id:da2e206f tags:
``` prolog ``` prolog
:- use_module(library(clpfd)).
```
%% Cell type:markdown id:8d8c47ed tags:
The library provides a few operators like ```#=```, ```ins``` or ```all_different```:
%% Cell type:code id:cf4ff4dd tags:
``` prolog
?- X #= Y+Z, [Y,Z] ins 0..9.
```
%% Output
%% Cell type:markdown id:25e2db2a tags:
To find solutions one needs to call ```labeling```:
%% Cell type:code id:4f8aee37 tags:
``` prolog
X #= Y+Z, [Y,Z] ins 0..9, labeling([],[Y,Z]).
```
%% Output
%% Cell type:code id:aac2c0ab tags:
``` prolog
X #= Y+Z, [Y,Z] ins 0..9, all_different([X,Y,Z]), labeling([],[Y,Z]).
```
%% Output
%% Cell type:markdown id:ae23fbd6 tags:
Let us now solve the Send More Money puzzle, where we have to find distinct digits such that this equation holds:
```
S E N D
+ M O R E
= M O N E Y
```
%% Cell type:code id:c86fb33e tags:
``` prolog
?- L = [S,E,N,D,M,O,R,Y],
L ins 0..9, % all variables are digits
S#>0, M#>0, % S and M cannot be 1
all_different(L), % all variables are different
1000*S + 100*E + 10*N + D
+ 1000*M + 100*O + 10*R + E
#= 10000*M + 1000*O + 100*N + 10*E + Y,
labeling([], L).
``` ```
%% Output
%% Cell type:code id:deaef138 tags:
``` prolog
juptyer:retry
```
%% Output
%% Cell type:markdown id:5f251e4d tags:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment