Prolog - descending order list - prolog

I am trying to write a function - decListRange(X,List) which give a list in range [X-1:1] by descending order. For example -
decListRange(9,List).
Will give -
List = [8,7,6,5,4,3,2,1].
I tried the following but it goes into infinite loop -
decListRange(1,[]) :- !.
decListRange(X,[H|Rest]) :-
H = X-1, NextX = X - 1 ,decListRange(NextX,Rest).

You have two problems. The first real one is that you need to use is instead of =:
H is X-1
This is needed to trigger arithmetic evaluation. Your second problem isn't a real problem but speaks to a bigger misunderstanding, which is that H and NextX are equivalent. Because Prolog only has bindings and not "assignables" as it were, you should never really need to create two "variables" with the same binding. There's no state being kept around for you to modify later.
Cleaning up both you get this:
decListRange(1, []) :- !.
decListRange(X, [H|Rest]) :-
X > 1,
H is X-1,
decListRange(H, Rest).
Edit 2: a clpfd implementation
:- use_module(library(clpfd)).
declist(N, L) :- N == 1, !, L = []. % green cut
declist(1, []).
declist(N, [N1|Ns]) :-
N #> 1,
N1 #= N - 1,
declist(N1, Ns).
This one has the properties #false mentions below in the comments:
?- declist(3, L).
L = [2, 1] ;
false.
?- declist(3, [2,1]).
true ;
false.
?- declist(N, [3,2,1]).
N = 4.
?- declist(N, X).
N = 1,
X = [] ;
N = 2,
X = [1] ;
N = 3,
X = [2, 1] ;
N = 4,
X = [3, 2, 1] ;
N = 5,
X = [4, 3, 2, 1] .
Edit: a short interlude on the difference between = and is.
In procedural languages = is almost always syntax for assigning a particular value to a variable. In Prolog, variables are bindings, and once established they cannot be directly modified by reassigning the variable a different value. Instead they work more like variables in math and logic, where the variable "stands in" for interesting values, but those values are themselves basically immutable. In Prolog, = essentially asks the unification engine to establish bindings. So if you were to do something like this:
?- name(X, Y) = name(bob, tony).
Prolog responds with variable bindings:
X = bob,
Y = tony.
Once those bindings exist, contradictory bindings will fail and affirmative bindings will succeed:
?- name(X, Y) = name(bob, tony), X = bob.
X = bob,
Y = tony.
?- name(X, Y) = name(bob, tony), X = william.
false.
The unification algorithm itself doesn't know anything about arithmetic. This has the pleasant side-effect that you can use any expression raw. For instance:
?- Expr = X + 3, Z + Q = Expr.
Expr = Z+3,
X = Z,
Q = 3.
This is probably really surprising looking. You may expect that somehow Prolog was smart enough to keep the expression around because it noticed X was a variable or something, but that isn't true either:
?- X = 4, Expr = X + 3, Z + Q = Expr.
X = 4,
Expr = 4+3,
Z = 4,
Q = 3.
Another way of looking at this is that Prolog is considering + to be just another operator, so X+3 is a fact just like add(X, 3) that doesn't necessarily have any special meaning. Whichever way you look at it, the is/2 operator exists to apply arithmetic reasoning and produce a value:
?- X = 4, Expr is X + 3.
X = 4,
Expr = 7.
Notice that Expr has the computed value but none of the original structure:
?- X = 4, Expr is X + 3, Z + Q = Expr.
false.
In practice, if you need to do a lot of reasoning with arithmetic, you will want to use a library like clpfd or clpqr depending on whether you're interested in integers or reals. This library enables you to do more interesting things more easily, like specify that an equation holds for values in a certain range and get those values out.

Related

How can I replace a list in Prolog?

I think it's very easy but I have no idea how to do that.
I tried by attribuition, doing a list receive another list but don't work.
% H is the head of a coordenate and T the tail
% E is the element that will be placed in the position T
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],H,T,E,NewTray) :-
H is 1,replace(L1,T,E,N),L1 = N;
H is 2,replace(L2,T,E,N),L2 = N;
...
H is 10,replace(L10,T,E,N),L10 = N;
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
I need that L1 be the N in this clause, I don't know how I can create a clause to modify the L1 inside the clause findLine. I thought in create clause to remove all elements and add the new ones one by one and call this at the attribuition place:
%L is the list, C a counter and N the new list
rewrite(L,C,N) :-
Q is C,
removeByIndex(Q,L,R),
(Q \== 0 -> rewrite(R,Q-1,N), !.
removeByIndex(0,[_|T],T):- !.
removeByIndex(I,[H|T],R):- X is I - 1, removeByIndex(X, T, Y), insert(H, Y, R).
But I continous with the same problem: the L1 are not modified :(
The idea is modify a line and replace on the tray.
PS: I'm sorry for my english, but the prolog topics are almost inative in the portuguese forum
I'm really unsure what you're trying to accomplish here, but I can point to a few things that strike me as symptoms of a misunderstanding.
First of all, you bind all the variables at the top and then you have essentially a bottom-out else case that looks like this:
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
Well, you never assign to NewTray in any of your other cases, so NewTray is going to be uninstantiated most of the time. That does not seem likely to be what you intend to me.
Second, your cases have this structure:
H is 1,replace(L1,T,E,N),L1 = N;
First mistake here is that H is 1; is/2 is for evaluating arithmetic expressions; there's no difference between this and H = 1, and the equivalence of L1 and N means that this whole predicate could probably be written as:
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],1,T,E,_) :-
replace(L1,T,E,L1).
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],2,T,E,_) :-
replace(L2,T,E,L2).
findLine(Line, _, _, Line).
I'm still confused by what you're trying to do, looking at that.
I suspect that you think L1 will have some value on the way into the relation and suddenly have a new, different value after the relation is used. That is emphatically not the case: variables in Prolog are bound exactly once; your assignment L1 = N or whatever is not going to cause L1 to "receive a new value" (because such a thing cannot happen in Prolog); instead it informs Prolog that L1 and N should be bound to the same value. What this means depends on circumstances; if they are both ground and not equal it will cause your predicate to fail, for instance, but if either of them is non-ground they will accept the value of the other.
I'm looking at what you're doing here and I can't help but think that you're essentially trying to do this:
replace([], _, _, []).
replace([H|T], 1, X, [X|T]).
replace([H|T], N, X, [H|Replaced]) :-
N > 1, succ(N0, N), replace(T, N0, X, Replaced).
Use it like this:
?- replace([1,2,3,4,5], 3, foo, Result).
Result = [1, 2, foo, 4, 5]
I just can't for the life of me figure out what you're trying to do, and I don't know why you're bothering to bind all the variables in your list at once if you don't need them all at once.
Anyway, I hope this helps! Maybe if you show us more of what you're trying to do it will be more clear how we can help.
Edit: Elaboration on = and unification
Let's mess around with = and see what happens:
?- X = 3.
X = 3.
Probably nothing surprising about this.
?- 3 = X.
X = 3.
Unification is different from assignment. As you can see, it is not directional. This line would not have worked in any other language.
?- X = [1,Y,3].
X = [1, Y, 3].
Notice that Prolog has no issues with having variables remain free.
?- X = [1,Y,3], Y = 2.
X = [1, 2, 3],
Y = 2.
Now, because Y is the same in both positions, when you bound Y to 2, the middle value in X became 2 as well. There are data structures unique to Prolog that make use of this feature (difference lists).
?- X = [1,Y,3], Q = X, Q = [1,2,3].
X = Q, Q = [1, 2, 3],
Y = 2.
Now what makes this interesting is that we did not explicitly tell Prolog that Y is 2. Prolog inferred this by unification. You can see some more examples of that here:
?- X = [H|T], H = 3, T = [4,5].
X = [3, 4, 5],
H = 3,
T = [4, 5].
So here we said, X is composed of H and T and then told it what H and T are. But Prolog's unification doesn't care much about the order you do things:
?- X = [H|T], X = [1,2,3].
X = [1, 2, 3],
H = 1,
T = [2, 3].
Unification is transitive.
So what happens when Prolog cannot unify?
?- X = [1,Y,3], Q = X, Q = [1,2,3], Y = 4.
false.
Y has to be 2 for the first step, but it has to be 4 for the last step. Once a variable is bound, there's no changing it. This is just a more complex way of saying:
?- X = 2, X = 4.
false.
Prolog does not have "assignables", just variables.

#< Symbol In Prolog

I want to know what #< means in Prolog?
I encountered this symbol in this line of code while reading about the Bridge and Torch Problem:
select_one_or_two(L, [Sel1,Sel2], L2) :-
select(Sel1, L, NewL),
select(Sel2, NewL, L2),
Sel1 #< Sel2.
The comparative operators that start with # are more general than the ones that don't. With operators such as </2, you can only compare numeric values and expressions (involving literal numerics and variables that are instantiated with numeric values). So, with </2 you can do this:
?- X = 2, Y = 3, X + Y < 2*Y.
X = 2,
Y = 3.
?- X = 2, Y = 3, X + Y > 2*Y.
false.
?-
But you will get an error in the following cases if the expressions don't evaluate to a known numeric:
?- Y = 3, X + Y < 2*Y.
ERROR: </2: Arguments are not sufficiently instantiated
Or:
?- a < b.
ERROR: </2: Arithmetic: `a/0' is not a function
However, using #</2 you can compare lots of different types of objects in prolog. The comparison evaluation follows the rules described in the link that #Ankur gave. To understand these rules, you'll need to know what Prolog terminology means, such as term, functor, atom, etc (see, for example, Prolog Terms)
Looking at some examples:
?- a #< b.
true.
?- a(1) #< a(2).
true.
?- b(1) #< a(2).
false.
?- 20 #< a.
true.
These are pretty straight-forward, following the rules. Here's a more interesting case (from above):
?- Y = 3, X + Y #< 2*Y.
false.
Why would X + Y be considered "not less than" 2*Y? Prolog would internally look at this as:
`+(X,3) #< *(2,3).`
(Note Y is instantiated to 3.) These are compound terms (they aren't individual atoms or variables). If we look through the comparison rules, the matching rule is:
Compound terms are first checked on their arity, then on their functor
name (alphabetically) and finally recursively on their arguments,
leftmost argument first.
The arity of both terms is 2. The functor names are + and * respectively. Those are different. And in teh ASCII collating sequence, + comes after *. Therefore it is not true that + "is less than" *, and therefore not true that +(X,3) #< *(2,3). Thus, it is not true that Y = 3, X + Y #< 2 * Y.
Note also that #</2 doesn't evaluate numeric expressions. So even with X and Y instantiated as values, you will get:
?- X = 2, Y = 3, X + Y #< 2*Y.
false.
Whereas, when we had </2 here, this is true, since the expression X + Y < 2*Y, when evaluated, is true. When variables are simply unified, it understands that, however, so you would have:
| ?- X #< Y.
yes
But on the other hand:
| ?- X = 2, Y = 1, X #< Y.
no
In this case X #< Y is seen as 2 #< 1 due to the unification of X with 2 and Y with 1 and the numeric rule kicks in.
Having said all that, the use of #</2 in the predicate select_one_or_two enables that predicate to be usable on lists of all sorts of objects, not just numbers or fully instantiated numeric expressions. If it had used </2, then the following would work:
?- select_one_or_two([2,1,3], X, Y).
X = [2, 3],
Y = [1] ;
X = [1, 2],
Y = [3] ;
X = [1, 3],
Y = [2] ;
false.
But the following fails:
?- select_one_or_two([b,a,c], X, Y).
ERROR: </2: Arithmetic: `b/0' is not a function
?-
However, with the #< operator, it works:
?- select_one_or_two([b,a,c], X, Y).
X = [b, c],
Y = [a] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
false.

Prolog cut operator behaviour

I have these clauses:
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).
When I run the query c(X,Y,Z) the answers are:
X = 1, Y = 1, Z = 1 ;
X = 1, Y = 1, Z = 2 ;
X = 2, Y = 1, Z = 1 ;
X = 2, Y = 1, Z = 2 ;
X = a, Y = 1, Z = 1 ;
X = a, Y = 1, Z = 2.
So basically, the cut operator (in here d(B,C) :- a(B),!,a(C).) ignores the most recent choice points, i.e. it does not do a further search for d() and a(). I though that the cut ignores ALL previous choice points and won't do any backtracking.
Can someone explain the exact behavior and why am I wrong?
Because I did not immediately understand your explanation of what the cut is doing, I looked at your code. My reading went roughly as follows:
c(A,B,C) is true when:
a(A) and d(B,C),
or b(A) and d(B,C)
d(B,C) is true when a(B), but only for the first a(B) you encounter, and don't look for any other d(B,C) definitions that you might find below this one.
My reading went like this because my interpretation of the cut is: commit to the choices made before encountering the cut within this predicate body, and discard clauses for this predicate below the clause containing the cut.
I hope this is at least remotely helpful.
I did some reading and the cut is working as follows:
1. Kills off the parent choice-point
2. Commits to all the choices made going through the rule
Thus :
1. d(B,_) :- b(B). is not explored
2. B in d(B,C) :- a(B),!,a(C). is irrevocably bound to 1.

What does this wildcard do in this prolog scenario?

I've come across this code:
connectRow(_,_,0).
connectRow([spot(_,R,_,_)|Spots],R,K) :- K1 is K-1, connectRow(Spots,R,K1).
/*c*/
connectRows([]).
connectRows(Spots) :-
connectRow(Spots,_,9),
skip(Spots,9,Spots1),
connectRows(Spots1).
How does the wildcard in the connectRow(Spots,_,9) work? How does it know which values to check and how does it know that it checked all the possible values?
Edit: I think I understand why this works but I'd like it if someone could verify this for me:
When I "call" the connectRow with the wildcard it matches the wildcard with the "R" in the connectRow predicate. Could this be it?
The _ is just like any other variable, except that each one you see is treated as a different variable and Prolog won't show you what it unifies with. There's no special behavior there; if it confuses you about the behavior, just invent a completely new variable and put it in there to see what it does.
Let's talk about how Prolog deals with variables. Here's an experiment you can follow along with that should undermine unhelpful preconceived notions if you happen to have them.
?- length([2,17,4], X)
X = 3.
A lot of Prolog looks like this and it's easy to fall into the trap of thinking that there are designated "out" variables that work like return values and designated "in" variables that work like parameters. After all:
?- length([2,17,4], 3).
true.
?- length([2,17,4], 5).
false.
Here we begin to see that something interesting is happening. A faulty intuition would be that Prolog is somehow keeping track of the input and output variables and "checking" in this case. That's not what's happening though, because unification is more general than that. Observe:
?- length(X, 3).
X = [_G2184, _G2187, _G2190].
We've now turned the traditional parameter/return value on its head: Prolog knows that X is a list three items long, but doesn't know what the items actually are. Believe it or not, this technique is frequently used to generate variables when you know how many you need but you don't need to have them individually named.
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G2196],
Y = 1 ;
X = [_G2196, _G2199],
Y = 2 ;
X = [_G2196, _G2199, _G2202],
Y = 3
It happens that the definition of length is very general and Prolog can use it to generate lists along with their lengths. This kind of behavior is part of what makes Prolog so good at "generate and test" solutions. You define your problem logically and Prolog should be able to generate logically sound values to test.
All of this variation springs from a pretty simple definition of length:
length([], 0).
length([_|Rest], N1) :-
length(Rest, N0),
succ(N0, N1).
The key is to not read this like a procedure for calculating length but instead to see it as a logical relation between lists and numbers. The definition is inductive, relating the empty list to 0 and a list with some items to 1 + the length of the remainder of the list. The engine that makes this work is called unification.
In the first case, length([2,17,4], X), the value [17,4] is unified with Rest, N0 with 2 and N1 with 3. The process is recursive. In the final case, X is unified with [] and Y with 0, which leads naturally to the next case where we have some item and Y is 1, and the fact that the variable representing the item in the list doesn't have anything in particular to unify with doesn't matter because the value of that variable is never used.
Looking at your problem we see the same sort of recursive structure. The predicates are quite complex, so let's take them in pieces.
connectRow(_, _, 0).
This says connectRow(X, Y, 0) is true, regardless of X and Y. This is the base case.
connectRow([spot(_, R, _, _)|Spots], R, K) :-
This rule is matching a list of spots of a particular structure, presuming the first spot's second value (R) matches the second parameter.
K1 is K-1, connectRow(Spots, R, K1).
The body of this clause is essentially recurring on decrementing K, the third parameter.
It's clear now that this is basically going to generate a list that looks like [spot(_, R, _, _), spot(_, R, _, _), ... spot(_, R, _, _)] with length = K and no particular values in the other three positions for spot. And indeed that's what we see when we test it:
?- connectRow(X, Y, 0).
true ;
(infinite loop)^CAction (h for help) ? abort
% Execution Aborted
?- connectRow(X, Y, 2).
X = [spot(_G906, Y, _G908, _G909), spot(_G914, Y, _G916, _G917)|_G912] ;
(infinite loop)^CAction (h for help) ? abort
So there seem to be a few bugs here; if I were sure these were the whole story I would say:
The base case should use the empty list rather than matching anything
We should stipulate in the inductive case that K > 0
We should use clpfd if we want to be able to generate all possibilities
Making the changes we get slightly different behavior:
:- use_module(library(clpfd)).
connectRow([], _, 0).
connectRow([spot(_, R, _, _)|Spots], R, K) :-
K #> 0, K1 #= K-1, connectRow(Spots, R, K1).
?- connectRow(X, Y, 0).
X = [] ;
false.
?- connectRow(X, Y, 1).
X = [spot(_G906, Y, _G908, _G909)] ;
false.
?- connectRow(X, Y, Z).
X = [],
Z = 0 ;
X = [spot(_G918, Y, _G920, _G921)],
Z = 1 ;
X = [spot(_G918, Y, _G920, _G921), spot(_G1218, Y, _G1220, _G1221)],
Z = 2
You'll note that in the result we have Y standing in our spot structures, but we have weird looking automatically generated variables in the other positions, such as _G918. As it happens, we could use _ instead of Y and see a similar effect:
?- connectRow(X, _, Z).
X = [],
Z = 0 ;
X = [spot(_G1269, _G1184, _G1271, _G1272)],
Z = 1 ;
X = [spot(_G1269, _G1184, _G1271, _G1272), spot(_G1561, _G1184, _G1563, _G1564)],
Z = 2
All of these strange looking variables are there because we used _. Note that all of the spot structures have the exact same generated variable in the second position, because Prolog was told it had to unify the second parameter of connectRow with the second position of spot. It's true everywhere because R is "passed along" to the next call to connectRow, recursively.
Hopefully this helps explain what's going on with the _ in your example, and also Prolog unification in general.
Edit: Unifying something with R
To answer your question below, you can unify R with a value directly, or by binding it to a variable and using the variable. For instance, we can bind it directly:
?- connectRow(X, 'Hello, world!', 2).
X = [spot(_G275, 'Hello, world!', _G277, _G278), spot(_G289, 'Hello, world!', _G291, _G292)]
We can also bind it and then assign it later:
?- connectRow(X, R, 2), R='Neato'.
X = [spot(_G21, 'Neato', _G23, _G24), spot(_G29, 'Neato', _G31, _G32)],
R = 'Neato'
There's nothing special about saying R=<foo>; it unifies both sides of the expression, but both sides can be expressions rather than variables:
?- V = [2,3], [X,Y,Z] = [1|V].
V = [2, 3],
X = 1,
Y = 2,
Z = 3.
So you can use R in another predicate just as well:
?- connectRow(X, R, 2), append([1,2], [3,4], R).
X = [spot(_G33, [1, 2, 3, 4], _G35, _G36), spot(_G41, [1, 2, 3, 4], _G43, _G44)],
R = [1, 2, 3, 4] ;
Note that this creates opportunities for backtracking and generating other solutions. For instance:
?- connectRow(X, R, 2), length(R, _).
X = [spot(_G22, [], _G24, _G25), spot(_G30, [], _G32, _G33)],
R = [] ;
X = [spot(_G22, [_G35], _G24, _G25), spot(_G30, [_G35], _G32, _G33)],
R = [_G35] ;
X = [spot(_G22, [_G35, _G38], _G24, _G25), spot(_G30, [_G35, _G38], _G32, _G33)],
R = [_G35, _G38] ;
Hope this helps!

Prolog: pythagorean triple

I have this code that uses an upper bound variable N that is supposed to terminate for X and Y of the pythagorean triple. However it only freezes when it reaches the upper bound. Wasn't sure how to use the cut to stop the backtracking. Code is:
is_int(0).
is_int(X) :- is_int(Y), X is Y+1.
minus(S,S,0).
minus(S,D1,D2) :- S>0, S1 is S-1, minus(S1,D1,D3), D2 is D3+1.
pythag(X,Y,Z,N) :- int_triple(X,Y,Z,N), Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :- is_int(S), minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
Will be called, for example with,
?- pythag(X,Y,Z,20).
First, let us test your solution:
?- pythag(X,Y,Z,20).
X = 4, Y = 3, Z = 5
; X = 3, Y = 4, Z = 5
; X = 8, Y = 6, Z = 10
; X = 6, Y = 8, Z = 10
; X = 12, Y = 5, Z = 13
; X = 5, Y = 12, Z = 13
; X = 12, Y = 9, Z = 15
; X = 9, Y = 12, Z = 15
; X = 15, Y = 8, Z = 17
; X = 8, Y = 15, Z = 17
; X = 16, Y = 12, Z = 20
; X = 12, Y = 16, Z = 20
; loops.
Looks perfect to me! All answers are correct solutions! ... up to and including this last solution. After that, your program loops.
Before we try to identify the problem, just hold on for a moment: You must be pretty patient to go through 12 (that is: twelve) answers only to find that loop. Do you think that this method will also work for bigger cases? How many answers are you willing to look at before you give up? Isn't there a simpler way to find out about the problem?
There is one interesting observation here: The answers found have (almost) nothing to do with the looping of the program! That is: By looking at the answers, you get (frequently – as in this case) no clue about the actual cause of the loop! So why not turn off all the answers and concentrate on the relevant part! In fact, we can do this as follows:
?- pythag(X,Y,Z,20), false.
loops.
Now, all answers have been removed due to the goal false. What remains is just the final outcome: either termination, or non-termination, or some error. Nothing else. This should facilitate our observations about termination a bit - no more blinding answers scrolling over the screen. Note that this does not solve the problem in general. After all, how long are we willing to wait? 1s ? 1m?
The actual reason of non-termination can be best understood by looking at a relevant failure slice. That is a fragment of the program whose non-termination implies the non-termination of the whole program. See this answer for more details. Here is the relevant failure slice of your program for query pythag(X,Y,Z,20), false:
pythag(X,Y,Z,N) :-
int_triple(X,Y,Z,N), false,
Z*Z =:= X*X + Y*Y.
int_triple(X,Y,Z,N) :-
is_int(S), false,
minus(S,X,S1), X>0, X<N,
minus(S1,Y,Z), Y>0, Y<N.
is_int(0) :- false.
is_int(X) :-
is_int(Y), false,
X is Y+1.
Note that there are not many things left of your program. E.g., the actual equation is gone (that's more or less the logic part...). Still, this fragment is relevant. And as long as you do not change something within that fragment, the problem will persist! That is guaranteed for a pure monotonic program as this one...
Here is my preferred solution: It uses length/2 and between/3, two frequently supported predicates of the Prolog prologue.
pythag2(X,Y,Z,N) :-
length(_, N),
between(1,N,X),
between(1,N,Y),
between(1,N,Z),
Z*Z =:= X*X + Y*Y.
I was recently as well thinking about a Prolog solution to
find Pythagorean triples. I came up with a slightly different
code. Assume we have a function:
isqrt(a) = floor(sqrt(a))
It is then enough to enumerate x and y, and to check whether
x*x+y*y is the square of some z. Namely to check for:
h = x*x+y*y, z = isqrt(h), z*z = h ?
The function isqrt can be implemented via bisection. For
symmetry breaking we can enumerate y after x. Assuming
N = 99 the resulting code is:
% between(+Integer, +Integer, -Integer)
between(Lo, Hi, _) :-
Lo > Hi, !, fail.
between(Lo, _, Lo).
between(Lo, Hi, X) :-
Lo2 is Lo+1, between(Lo2, Hi, X).
% bisect(+Integer, +Integer, +Integer, -Integer)
bisect(Lo, Hi, X, Y) :-
Lo+1 < Hi, !,
M is (Lo+Hi) // 2,
S is M*M,
(S > X -> bisect(Lo, M, X, Y);
S < X -> bisect(M, Hi, X, Y);
M = Y).
bisect(Lo, _, _, Lo).
% pythago(-List)
pythago(X) :-
X = [A,B,C],
between(1, 99, A),
between(A, 99, B),
H is A*A+B*B,
bisect(0, H, H, C),
C =< 99, H =:= C*C.
There should be 50 such Pythagorean tripples, see also Sloan's A046083:
?- findall(-, pythago(_), L), length(L, N).
N = 52.
One might like to cross check with the following
CLP(FD) solution.
:- use_module(library(clpfd)).
% pythago3(-List)
pythago3(X) :-
X = [A,B,C],
X ins 1..99,
A*A+B*B #= C*C,
A #=< B,
label(X).
It gives the same number of solutions:
?- findall(-, pythago3(_), L), length(L, N).
N = 50.

Resources