Why can't I compare two atom like this? - prolog

So basically here is some Prolog code I wrote, using GNU-Prolog 1.4.4.
A is 1,
B = (A == 2),
B == no.
A is 2,
B = (A == 2),
B == no.
What I am expecting is when A is 2, then B == no returns no, when A is 1, then B == no returns yes.
However, to my surprise, both two code snippets return no, which leaving me the impression that B == no works in an unexpected way..
So basically how can I write the code in the way I want?
Could anyone give me some help?

The line
B = (A == 2)
does not compute A==2 in any way and assign the result to B. It just unifies the term B (a variable) with the term (A==2). The result of the unification is that B is now A==2. You can check yourself by omitting B==no:
?- A is 1, B=(A==2).
A = 1,
B = (1==2) ?
yes
If you really want that B unifies with the atoms yes resp. no you can use an if-then-else construct:
( A == 2 -> B = yes
; otherwise -> B = no)

Related

How do I understand the logic behind this Prolog problem?

I am trying to understand how to solve the following problem in Prolog. Given the following Prolog code, list all solutions in order for the query c(X,Y,Z).
a(1).
a(2).
b(a).
c(A,B,C) :- a(A),d(B,C).
c(A,B,C) :- b(A),d(B,C).
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
I loaded up SWI Prolog to try it out myself, but I am unsure how it reaches the conclusion:
X = Y, Y = Z, Z = 1 ;
X = Y, Y = 1,
Z = 2 ;
X = 2,
Y = Z, Z = 1 ;
X = Z, Z = 2,
Y = 1 ;
X = a,
Y = Z, Z = 1 ;
X = a,
Y = 1,
Z = 2.
Starting small, I tried to query just d(B,C). with the same code, leading to the following conclusion:
Y = Z, Z = 1 ;
Y = 1,
Z = 2.
I understand how to get the Y=1 and Z=1,2, but I am unsure how the code leads to Y=Z. If anyone could help me with the logic to reach these conclusions, that would be well appreciated!
Let's start by looking at the predicates a/1 and b/1: We expect them to produce two and one answer(s) respectively and indeed that is the case:
?- a(X).
X = 1 ? ;
X = 2
?- b(X).
X = a
Next let's look at the predicate d/2 but without the cut, that is:
d(B,C) :- a(B),a(C).
d(B,_) :- b(B).
If we query this predicate:
?- d(B,C).
Prolog will start with the first rule of the predicate d/2, that is d(B,C) :- a(B),a(C). and tries to prove the first goal a(B). That succeeds with the substitution B = 1. So Prolog goes on to prove the goal a(C). Again that succeeds with the substitution C = 1. Prolog then reports the first solution to the query:
?- d(B,C).
B = C = 1 ?
So we ask if there are any more solutions by pressing ;:
?- d(B,C).
B = C = 1 ?;
Now Prolog tries to find another solution for a(C) and finds the substitution C = 2:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ?
Again we ask if there's more:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
Now Prolog fails to find another solution for a(C), so it backtracks to the first goal and tries to find an alternative solution for a(B) and succeeds with the substitution B = 2. So it goes on to prove the second goal a(C) to which again the substitution C = 1 is found. So Prolog reports this new solution.
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ?
We ask for yet more solutions:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
So Prolog looks for another solution for a(C) and finds C = 2. So it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ?
We press ; again
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
And Prolog looks for other solutions for a(C) but can't find any. So it backtracks to the goal a(B) and again fails to produce new answers here. So those are all solutions for the first rule of d/2. Prolog now goes on and tries to find a solution for the second rule d(B,_) :- b(B).. This rule only contains one goal: b(B) and Prolog finds a substitution: B = a, so it answers:
?- d(B,C).
B = C = 1 ?;
B = 1,
C = 2 ? ;
B = 2,
C = 1 ? ;
B = C = 2 ? ;
B = a
?-
And there are no more solutions. Let's observe that while Prolog traverses the proof tree as seen above, every time alternative substitutions can't be ruled out a choice point is created and in the course of the search for answers Prolog can backtrack to these choicepoints to look for alternative solutions. Every time an answer in the above query ended with ? Prolog still had some choice points left to explore and by pressing ; we asked it to explore them.
Now let's move our attention back to your posted version of d/2 with the cut in the first rule:
d(B,C) :- a(B),!,a(C).
d(B,_) :- b(B).
What a cut does is to prune away choice points back to where it was when the predicate that contains it was called. So it is essentially throwing away untried alternatives, thereby committing Prolog to the first substitution(s) it finds. So if we issue the query again with this version:
?- d(B,C).
Prolog again starts with the first rule, looking for a solution for a(B), successfully substituting B = 1 encountering the cut, therefore committing to this solution and then searching for a proof for a(C), again successfully substituting C = 1. Prolog then answers:
?- d(B,C).
B = C = 1 ?
indicating that there are open choice points. Again we want more:
?- d(B,C).
B = C = 1 ? ;
Prolog finds another substitution C=2 for the goal a(C) and reports:
?- d(B,C).
B = C = 1 ? ;
B = 1,
C = 2
?-
But this time the query terminates. That is because the choicepoint for an alternative solution for the goal a(B) was pruned away thereby leaving us without the solutions B = 2, C = 1 and B = C = 2. Furthermore the choicepoint that would have led to the second rule being explored was also pruned away thereby robbing us of the solution B = a. Cuts that prune away correct solutions as seen above are often referred to as red cuts in the literature.
Note that by cutting away actual solutions this program is not logically correct anymore. With the above query you asked for all solutions of the predicate d/2 but got only two of them. However, if you ask for the other solutions specifically, the respective queries still succeed:
?- d(2,1).
yes
?- d(2,2).
yes
?- d(a,_).
yes
?-
Returning to your original question, let's compare the query ?- c(X,Y,Z). with both versions of d/2. To make comparisons easier, the variables X, Y and Z are replaced with A, B and C just like they occur in the predicate definitions:
% cut-free version % version with the cut:
?- c(A,B,C). ?- c(A,B,C).
A = B = C = 1 ? ; A = B = C = 1 ? ;
A = B = 1, A = B = 1,
C = 2 ? ; C = 2 ? ;
A = C = 1,
B = 2 ? ;
A = 1,
B = C = 2 ? ;
A = 1,
B = a ? ;
A = 2, A = 2,
B = C = 1 ? ; B = C = 1 ? ;
A = C = 2, A = C = 2,
B = 1 ? ; B = 1 ? ;
A = B = 2,
C = 1 ? ;
A = B = C = 2 ? ;
A = 2,
B = a ? ;
A = a, A = a,
B = C = 1 ? ; B = C = 1 ? ;
A = a, A = a,
B = 1, B = 1,
C = 2 ? ; C = 2
A = a,
B = 2,
C = 1 ? ;
A = a,
B = C = 2 ? ;
A = B = a
For the sake of brevity I'm not going to iterate through the steps of the proof, but let's observe a few key things: Firstly, in both rules of c/3 the predicate d/2 is called by the same goal d(B,C) and we have already looked at that goal in detail for both versions. Secondly, we can observe that both rules of c/3 are taken into regard in the search for answers with both versions of the predicate by seeing all three substitutions, A = 1, A = 2 and A = a appearing in both answer-sets. So the cut doesn't prune away the choice point here. Thirdly, the three solutions of d/2 that are pruned away by the cut: B = 2, C = 1, B = 2, C = 2 and B = a are missing in the answers for all three substitutions of A in the version with the cut. And finally, the version of c/3 with the cut is also not logically correct, as the most general query does not give you all the answers but you can query for the thrown away solutions directly and Prolog will find them, e.g.:
?- c(1,2,1).
yes
?- % etc.
Try the query trace, c(X,Y,Z).

Prolog: Find Minimum again and again until the list is empty

How can I repeatedly extract minimum number until the list is empty?
I want to find a minimum number, then exclude it from the original list, then find a minimum again and again, until the list becomes empty.
Input:
?- Find_Minimum([2, 1, 4, 3, 5], C)
Output:
C = 1
C = 2
C = 3
C = 4
C = 5
False
Here a simple solution using sort/2 (in SWI):
minimum(L,E):-
sort(L,LSorted),
pick(LSorted,E).
pick([H|_],H).
pick([_|T],E):-
pick(T,E).
?- minimum([2,1,4,3,5],E).
E = 1
E = 2
E = 3
E = 4
E = 5
false
Keep in mind that sort/2 removes duplicates. If you want to keep them use for instance msort/2 (in SWI). For an even simpler solution you can use member/2:
minimum(L,E):-
sort(L,LSorted),
member(E,LSorted).
?- minimum([2,1,4,3,5],E).
E = 1
E = 2
E = 3
E = 4
E = 5
I would had written - more or less - the same answer as #damianodamiano (+1), but tried nevertheless to code something more 'direct' than sorting. It turns out the outcome is rather technical...
:- module(minext, [minext/2,minext/3]).
minext(L,M) :-
minext(L,T,R),
( M=T
; minext(R,M)
).
minext(L,X,R) :-
select(X,L,R),
\+((
member(Y,R),
Y<X
)), !.

Prolog - System of equations solver

I trying to create compact code in prolog that sovles systems of equations.
For example, in this case, the assumptions must be
A+B-C-D=4, A+B+C+D=14, A-B+C-D=2.
I'm trying to have it where it solves all combinations possible for A, B, C, and D but satisfies all 3 equations. They can only be #'s 0-9 though but somehow show all possible solutions/combinations.
So after running the query, it would output something like
Crypto(A,B,C,D)
A = 8, B = 1, C = 0, D = 5.
^That would be one solution. But I need to show all possible.
I'm kind of lost as to how to satisfy all 3 in Prolog. Thank you.
You can solve it by taking out one element from the domain of the variables and assign it to them such that every variable has a different number assigned to it. It's a brute force method.
takeout(X, [X|R], R).
takeout(X, [Y|Xs], [Y|Ys]):- takeout(X, Xs, Ys).
aas(X,L,L1):- takeout(X,L,L1).
crypto(A,B,C,D):-
L=[0,1,2,3,4,5,6,7,8,9],
aas(A,L,L1),aas(B,L1,L2),aas(C,L2,L3),aas(D,L3,_),
A+B-C-D=:=4,
A+B+C+D=:=14,
A-B+C-D=:=2,
nl.
aas(X,L,L1). used for assigning values to the variables.
takeout function is used for taking out one element and return a list excluding the element taken out.
OUTPUT
?- crypto(A,B,C,D).
A = 3,
B = 6,
C = 5,
D = 0
A = 5,
B = 4,
C = 3,
D = 2
A = 7,
B = 2,
C = 1,
D = 4
A = 8,
B = 1,
C = 0,
D = 5
This program prints all the possible solutions to that equation A+B-C-D=4, A+B+C+D=14, A-B+C-D=2. Hope this answers your question.

How to solve this puzzle in Prolog? (robbery)

Three suspects are involved in a robbery, Alice, Bob, Carl. At least one of them are guilty.
Here are the conditions:
If A is guilty, he has exactly 1 accomplice.
If B is guilty, he has exactly 2 accomplices.
Who are guilty?
How can I write a Prolog script to solve this problem which guilty(X) gives the gangs?
Here is a solution using clpb :
:- use_module(library(clpb)).
solve(A,B,C) :-
% there is a least one guilty
sat(A + B + C),
% If A is guilty, he has exactly 1 accomplice.
sat(A =< B # C),
% if B is guilty, he has exactly 2 accomplices.
sat(B =< A * C),
% Assigns truth values to the variables such that all constraints are satisfied.
labeling([A,B,C]).
Now we get :
?- solve(A,B,C).
A = B, B = 0,
C = 1 ;
A = C, C = 1,
B = 0.
The answer A = B, B = 0, C = 1 means that C is guilty the other one that A and C are guilties.
Let's encode the state of our world as three numbers, A, B, and C.
Each number will be either 1 (guilty) or 0 (innocent).
The conditions are:
at_least_one(A,B,C):- 0 < A+B+C.
one_accomplice(A,B,C):- A == 1 -> 1 is ....... ; true.
two_accomplices(A,B,C):- B == 1 -> ....... ; true.
The three rules holding together is
ok(A,B,C):- at_least_one(A,B,C),
one_accomplice(A,B,C),
...... .
Now we can find out the gangs, as
the_guilty([A,B,C]):-
( A = 0 ; A = 1 ),
....
....
ok( ..... ).
The last thing is to report the three given numbers as names of people. We know that the first number is for "Alice", the second is for "Bob", etc.
Prolog is easy.

Given original string and encoded string, how to induce encoding?

Suppose I have an original string and an encoded string , like the following:
"abcd" -> "0010111111001010", then one possible solution would be that "a" matches with "0010", "b" matches with "1111", "c" matches with "1100", "d" matches with "1010".
How to write a program, that given these two strings, and figure out possible encoding rules?
My first scratch looks like this:
fun partition(orgl, encode) =
let
val part = size(orgl)
fun porpt(str, i, len) =
if i = len - 1 then
[substring(str, len * (len - 1), size(str) - (len - 1) * len)]
else
substring(str, len * i, len)::porpt(str, i + 1, len)
in
porpt(encode, 0, part)
end;
But obviously it can not check whether the two substrings match the identical character, and there are many other possibilities other than proportionally partitioning the strings.
What should be the appropriate algorithms for this problem?
P.S. Only prefix code is allowed.
What I have learned has not really got into serious algorithms yet, but I did some searching about backtracking and wrote my second version of the code:
fun partition(orgl, encode) =
let
val part = size(orgl)
fun backtrack(str, s, len, count, code) =
let
val current =
if count = 1 then
code#[substring(str, s, size(str) - s)]
else
code#[substring(str, s, len)]
in
if len > size(str) - s then []
else
if proper_prefix(0, orgl, code) then
if count = 1 then current
else
backtrack(str, s + len, len, count - 1, current)
else
backtrack(str, s, len + 1, count, code)
end
in
backtrack(encode, 0, 1, part, [])
end;
Where the function proper_prefix would check prefix code and unique mapping. However, this function does not function correctly.
For example, when I input :
partition("abcd", "001111110101101");
The returned result is:
uncaught exception Subscript
FYI, the body of proper_prefix looks like this:
fun proper_prefix(i, orgl, nil) = true
| proper_prefix(i, orgl, x::xs) =
let
fun check(j, str, nil) = true
| check(j, str, x::xs) =
if String.isPrefix str x then
if str = x andalso substring(orgl, i, 1) = substring(orgl, i + j + 1, 1) then
check(j + 1, str, xs)
else
false
else
check(j + 1, str, xs)
in
if check(0, x, xs) then proper_prefix(i + 1, orgl, xs)
else false
end;
I'd try a back-tracking approach:
Start with an empty hypothesis (i.e. set all encodings to unknown). Then process the encoded string character by character.
At every new code character, you have two options: Either append the code character to the encoding of the current source character or go to the next source character. If you encounter a source character that you already have an encoding for, check if it matches and go on. Or if it doesn't match, go back and try another option. You can also check the prefix-property during this traversal.
Your example input could be processed as follows:
Assume 'a' == '0'
Go to next source character
Assume 'b' == '0'
Violation of prefix property, go back
Assume 'a' == '00'
Go to next source character
Assume 'b' == '1'
...
This explores the range of all possible encodings. You can either return the first encoding found or all possible encodings.
If one were to naively iterate all possible translations of abcd → 0010111111001010, this possibly leads to a blow-up. Simple iteration also appears to lead to a lot of invalid translations one would have to skip:
(a, b, c, d) → (0, 0, 1, 0111111001010) is invalid because a = b
(a, b, c, d) → (0, 0, 10, 111111001010) is invalid because a = b
(a, b, c, d) → (0, 01, 0, 111111001010) is invalid because a = c
(a, b, c, d) → (00, 1, 0, 111111001010) is one possibility
(a, b, c, d) → (0, 0, 101, 11111001010) is invalid because a = b
(a, b, c, d) → (0, 010, 1, 11111001010) is another possibility
(a, b, c, d) → (001, 0, 1, 11111001010) is another possibility
(a, b, c, d) → (0, 01, 01, 11111001010) is invalid because b = c
(a, b, c, d) → (00, 1, 01, 11111001010) is another possibility
(a, b, c, d) → (00, 10, 1, 11111001010) is another possibility
...
If all character strings contain each character exactly once, then this blow-up of results is the answer. If the same character occurs more than once, this further constrains the solution. E.g. matching abca → 111011 could generate
(a, b, c, a) → (1, 1, 1, 011) is invalid because a = b = c, a ≠ a
(a, b, c, a) → (1, 1, 10, 11) is invalid because a = b, a ≠ a
(a, b, c, a) → (1, 11, 0, 11) is invalid because a = b, a ≠ a
(a, b, c, a) → (11, 1, 0, 11) is one possibility
... (all remaining combinations would eventually prove invalid)
For a given hypothesis, you can choose the order in which to verify your constraints. Either
See if any mappings overlap. (I think this is what Nico calls the prefix property.)
See if any character that occurs more than once actually occurs in both places in the bit string.
An algorithm using this search strategy will have to find an order of checking constraints in order to try to a hypothesis as soon possible. My intuition tells me that a constraint a → β is worth investigating sooner if the bit string β is long and if it occurs many times.
Another strategy is ruling out that a particular character can map to any bit string of/above/below a certain length. For example, aaab → 1111110 rules out a mapping to any bit string of length above 2, and abcab → 1011101 rules out a mapping to any bit string of length different than 2.
For the programming part, try and think of ways to represent hypotheses. E.g.
(* For the hypothesis (a, b, c, a) → (11, 1, 0, 11) *)
(* Order signifies first occurrence *)
val someHyp1 = ([(#"a", 2), (#"b", 1), (#"c", 1)], "abca", "111011")
(* Somehow recurse over hypothesis and accumulate offsets for each character, e.g. *)
val someHyp2 = ([(#"a", 2), (#"b", 1), (#"c", 1)],
[(#"a", 0), (#"b", 2), (#"c", 3), (#"a", 4)])
And make a function that generates new hypotheses in some order, and a function that finds if a hypothesis is valid.
fun nextHypothesis (hyp, origStr, encStr) = ... (* should probably return SOME/NONE *)
fun validHypothesis (hyp, origStr, encStr) =
allStr (fn (i, c) => (* is bit string for c at its
accumulated offset in encStr? *)) origStr
(* Helper function that checks whether a predicate is true for each
character in a string. The predicate function takes both the index
and the character as argument. *)
and allStr p s =
let val len = size s
fun loop i = i >= len orelse p (i, String.sub (s, i)) andalso loop (i+1)
in loop 0 end
An improvement over this framework would be to change the order in which to explore hypotheses, since some search paths can rule out larger amounts of invalid mappings than others.

Resources