I'm an absolute beginner to prolog. I've just read a basic tutorial and tried to solve a quick problem on my own. The problem is this, find possible number combinations that lead to a sum. I'm expecting something like this:
sum(A,B,11).
This should result in values for A and B that would sum them upto 10.
My initial code was this:
sum(A,B,C):-
C is A + B.
But I do not get any results with this. I get the following.
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] 11 is _3302+_3304
ERROR: [7] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
What am I missing in my understanding of Prolog?
The standard is/2 predicate requires an evaluable arithmetic expression for second argument. Thus, in your case, you will need to generate possible values for A and B so that A + B can be computed. To make it practical, you will need to restrict the range of possible values. For example:
?- between(1,7,A), between(1,7,B), sum(A,B,11).
A = 4,
B = 7 ;
A = 5,
B = 6 ;
A = 6,
B = 5 ;
A = 7,
B = 4 ;
false.
As you progress on your learning of Prolog, you may eventually be interested in learning about constraint solvers.
This should result in values for A and B that would sum them upto 10.
If you consider negative numbers as well, there are infinite possible results: .. -100+111, -2+13, -1+12, 0+11, 1+10, 2+9, 150+-139 ...
Your program will confirm the sum, and perform the calculation given the inputs for A and B:
?- sum(2,9,11).
true
?- sum(2,9,C).
C = 11
but even if you leave out one of them, it can't solve it.
?- sum(A,9,11).
is/2: Arguments are not sufficiently instantiated
You are hoping Prolog will intuit that you mean "numbers between 0 and 11 which sum to 11" but Prolog sees a potentially infinite search space, and nowhere to start searching, and no way to narrow it down.
Paulo Moura's answer will generate the numbers in the range, and test them all, and show which pairs satisfy A + B = C. He mentions constraint solvers, which are libraries available for popular Prolog implementations and they have a more general way of solving problems like this. Constrain the solution space in some way ("A and B are positive integers"), as many constraints as you know, and then they apply those rules to reason about numbers, apply more techniques to find the answers without searching every imaginable number:
% load the 'clpfd' code
:- use_module(library(clpfd)).
% define a sum using the imported #= instead of "is"
mysum(A, B, C) :-
C #= A + B.
% declare that A and B are positive,
% and solve for A and B values.
?- mysum(A, B, 11), A in 0..sup, B in 0..sup, label([A,B]).
In this case it ends up being more code, but if you're generally hoping for Prolog to solve numeric calculations for you, you will likely have to go in this direction rather than using between() and making all the number lists yourself.
Related
I would expect that the following should always be true if a comparison backtrack, right? unless it goes into an infinite loop!
?- Y=2 , random:random(1,3,X), X =\= Y.
Y = 2,
X = 1.
?- Y=2 , random:random(1,3,X), X =\= Y.
false.
but I got false!
In general, my question is why doesn't comparison backtrack?
Thanks for all the answers. My confusion seemed to come primarily from my expectation of random keep generating new-random numbers, so I confused that comparison was not backtracking, instead, the reason was that random does its thing only once and fails afterwards.
I was unaware of semi-determinate nature of some predicates.
But now I can be on a lookout ;) for cases like this. thanks again.
In your example, there is nothing to backtrack.
All predicates you are using in these examples ((=)/2, random/3 and (=\=)/2) are semi-deterministic: This means that they either fail, or succeed exactly once.
In other words, they can all succeed at most once.
Therefore, if at least one of these predicates fails, then the query fails.
To generate a succession of pseudo-random numbers on backtracking, use for example repeat/0.
Warning: random/3 is an impure predicate: It may yield different solutions even though the query is exactly the same. It may lead to failure on one invocation, and to success on another. This complicates testing and reasoning about your code considerably.
Prolog works with what are called Horn-clauses. This means that each term individually, for example Y=2, is a separate goal in a question to be answered. The result will be yes or no for each goal, and if all goals answer yes, the question is answered with yes.
What your code asks is as follows:
%Is Y equal to 2 or can it be made equal?
%Yes, Y is a variable and can be assigned the numerical atom 2
Y=2 ,
%Give me a random number between 1 and 3.
%Is X equal to the random number or can it be made equal?
%Yes, X is a variable and can be assigned the outcome atom of random:random
random:random(1,3,X),
%is the term contained within X NOT equivalent to Y?
X =\= Y.
You can check out existing comparison predicates in for example the SWI documentation or on Learn Prolog Now!.
Depending on your implementation you can use trace and write to output the actual atoms in the variables, allowing you to explore how your program actually works.
?- trace, (Y=2 , random:random(1,3,X), write(X),nl, X =\= Y). %SWI-Prolog
SWI-prolog online editor
Infinite recursion looks like p(P) :- p(P).. It has a call to the question it is supposed to solve inside the answer itself, meaning to solve for p(P) it will check p(P), which never ends.
Backtracking only happens when Prolog has choicepoints. Choicepoints are points where in the decision tree, there are MULTIPLE POSSIBLE WAYS to satisfy the question Prolog is currently processing. Prolog works from top to bottom, then left to right.
Think of a cars salesman who gets asked "which car is the best for me?". He has more than one possible car to sell you, so he'll start showing you different cars that meet your criteria. The car needs to have a transport capacity of a volume over 400 liters? All cars that don't satisfy this condition are not presented as a solution.
Prolog does a depth-first search, meaning it goes down to the first answer it finds, then checks whether there's other ways to answer it. If there is no result, the answer is no. If there is at least one solution, the answer is yes and you get all possible answers for your question. This way you only get results that satisfy a whole chain of goals you've set.
I think this will help.
% Generate random value from Min to Max(with backtrack)
rand_backtrack(Min,Max,RandVal):-
create_list(Min,Max,List),
randomize_list(List,Randomized),
length(Randomized,Len),
% Choose one Variable from Randomized (From first element to last).
% When backtrack occured, next element is chosen.
between(1,Len,Idx),
nth1(Idx,Randomized,RandVal).
% create integer order list
% [Min,Min+1,Min+2,....,Max]
create_list(Max,Max,[Max]):-!.
create_list(Min,Max,[Min|Rest]):-
Min1 is Min+1,
create_list(Min1,Max,Rest).
% shuffle List.
% result always changes.
% ex.randomize_list([1,2,3,4,5,6],R) R=[4,2,6,1,3,5]
%
randomize_list([Val],[Val]):-!.
randomize_list(List,[RandVal|RestRandomized]):-
length(List,Len),
random(1,Len,RandIdx),
nth1(RandIdx,List,RandVal),
select(RandVal, List, Rest),
!,
randomize_list(Rest,RestRandomized).
?- rand_backtrack(3,19,A).
A = 6 ;
A = 4 ;
A = 8 ;
A = 13 ;
A = 15 ;
A = 16 ;
A = 9 ;
A = 18 ;
A = 7 ;
A = 3 ;
A = 12 ;
A = 10 ;
A = 17 ;
A = 11 ;
A = 14 ;
A = 5 ;
A = 19.
I have following code:
:-use_module(library(clpfd)).
afn(A,B,C):-
C #= B*A.
It works all right with integers but not with decimal numbers:
43 ?- afn(20, 10, C).
C = 200.
44 ?- afn(20, -10, C).
C = -200.
45 ?- afn(20, -10.5, C).
ERROR: Domain error: `clpfd_expression' expected, found `-10.5'
46 ?-
How can I work with decimals also here? Thanks.
Edit: I find following works with decimals:
afn(A,B,C):-
C is B * A.
67 ?- afn(20.895, 40.5, C).
C = 846.2475.
Is 'is' a correct approach ?!
CLP(FD) implements reasoning over integers.
To extend declarative arithmetic to decimal numbers, you have basically two options:
use a dedicated constraint solver over rationals. See CLP(Q).
scale all numbers so that only integers arise and continue using CLP(FD).
I have seen both approaches successfully applied. Option (2) is sometimes preferable because CLP(FD) is more widely available, and also because you can successfully solve non-linear constraints with it over finite domains.
EDIT: In your case, a suitable query could look like:
?- afn(200, -105, C).
C = -21000.
At the end, you have to scale the results again. This way, you can simulate decimals via integers.
Note that resorting to floats is not a good solution at all, since you cannot really trust the results. Therefore, either use rational numbers or integers, as long as more advanced formats are not yet widely available in Prolog systems.
You have to distinguish
Functional (or "moded") arithmetic. This is the one you are familiar with from other programming languages: You know which of your arguments are input and which is output, and you simply compute the output from the inputs. That's what you get from is/2 (which is part of standard Prolog), and if that's all you want to do, stick with it.
?- A=3, B=1.5, C is B * A.
C = 4.5
?- A=3, C=4.5, C is B * A.
instantiation fault <<< input B not kown
Relational arithmetic. Here, you state an equation or inequation that must hold between the variables involved. There is no notion of input/output arguments. The system's job is instead to make sure that all the stated relations hold at the time a solution for the variables is presented.
There are many different ways to implement relational arithmetic, and many methods only work for subsets of the problem (e.g. only integers, or only linear expressions), therefore these features are typically provided in the form of libraries.
One available implementation of general relational arithmetic over the real numbers is ECLiPSe's library(ic) (see 2, 3), which represents real numbers as floating point intervals:
?- A=3, C=4.5, C $= B * A.
B = 1.5__1.5 <<< precise result
?- C $= B * A, C=1, A=10.
B = 0.099999999999999992__0.1 <<< imprecise but accurate result
There are 2 delayed goals.
?- ln(X) $>= sin(X).
X = X{0.36787944117144228 .. 1.0Inf} <<< partially solved
There are 3 delayed goals.
Having said that, using interval arithmetic and interpreting results correctly is not always straightforward, that's why the kind of workarounds suggested by #mat can be useful (when applicable).
I #> 0, I #< 10, indomain(I).
The previous code obviously does the following:
I = 1 ;
I = 2 ;
I = 3 ;
I = 4 ;
I = 5 ;
I = 6 ;
I = 7 ;
I = 8 ;
I = 9.
The following code does not work (arguments are not sufficiently instantiated):
I #> 0, indomain(I).
Now I understand that there are in this case an infinite number of possible bindings for I, and that CLPFD works for finite domains as its name suggests.
However I don't understand why this limitation exists in this particular case. Isn't it possible to enumerate possible solutions from smallest to biggest norm, and get the following:
I = 1 ;
I = 2 ;
I = 3 ;
.
.
.
Even for problems where there are more than one variables, say:
0 #< I, I #< J, label([I,J]).
Why wouldn't it be possible to implement it such that the following behavior occurs:
I = 1,
J = 2 ;
I = 1,
J = 3 ;
I = 2,
J = 3 ;
I = 1,
J = 4 ;
.
.
.
In short: why doesn't CLPFD still work for infinite domains if those domains are easily countable using amplitude?
The reason for this is that CLP(FD) preserves the following important property:
If a predicate p(Vs) terminates universally, then ?- p(Vs), label(Vs). also terminates universally.
A goal G terminates universally iff ?- G, false. terminates.
Why is this so important? Because a CLP(FD) program typically consists of two parts:
posting all constraints
the search for solutions.
It is often easy to show, by simple inspection, that the modeling part (1) terminates universally. But (2) is the tough part that usually takes most of the computation time, and often we do not know a priori whether there even is a single solution. The search part may run for days, months or years without yielding results.
Many Prolog beginners describe a search task, run it, and after a few seconds complain that Prolog is slow. In reality, as it turns out, they often accidentally write programs that do not terminate, and can never find a solution.
For such reasons, it is encouraging that if you can only show (as you typically can, and also rather easily) that part (1) terminates, then your whole program—part (1) and part (2)—also terminates.
You are completely right that any countably infinite search space can be systematically covered to any finite extent in one of the ways you are describing. However, doing so would break this fundamental invariant. You must be able to count on the following property for the above reasoning to apply:
label/1, labeling/2 and indomain/1 always terminate.
In SWI-Prolog and YAP, this is ensured by design. In other systems it holds to varying degrees.
There is no reason to not allow infinite domains enumeration in CLP(FD). Since
as user:mat has correctly observed the constraints itself terminate, an infinite enumeration might find a solution if a solution exists.
So basically we have:
The constraints terminate universally, i.e. (#=)/2, (#=<)/2, etc.. give
true or false when completely instantiated, and don't diverge.
And we then observe:
The labeling of constraints terminates existentially, i.e. it finds
a solution to a problem after some time if we can also enumerate multiple
infinite domains in a fair way.
So the main problem is to enumerate multiple infinite domains in a fair way, since when we don't enumerate in a fair way, we might go astray in a subset of the domain and not find a solution even if there exists one. The following approaches to enumerate multiple infinite domains come to mind:
1) Unpair Function
Use a function unpair: N -> NxN, and enumerate the argument of this function only. This is an old Mathematica technique described here: An Elegant Pairing Function . Drawback you need to compute the square root each time.
2) Fair Conjunction
Use a fair conjunction to combine infinite enumerators. This is a technique applied in functional programming, see for example here: Backtracking, Interleaving, and Terminating Monad Transformers . Drawback the connective doesn't work in constant memory space, you spawn more and more instances of the right hand side enumerator.
3) Extra Variable
Use an extra variable H and an extra constraint for example H=abs(X1)+..+abs(Xn) for cantor pairing. You can then enumerate this variable and let the constraint solver do the rest of the work. Advantage for certain values you might have early pruning.
In Jekejeke Minlog we have recently opted for variant 3. Here is an example run to enumerate Pythagorean triples:
?- use_module(library(finite/clpfd)).
?- [X,Y,Z] ins 1..sup, X*X+Y*Y #= Z*Z, label([X,Y,Z]).
X = 3,
Y = 4,
Z = 5 ;
X = 4,
Y = 3,
Z = 5 ;
X = 6,
Y = 8,
Z = 10 ;
X = 8,
Y = 6,
Z = 10
In general when using infinite labeling one will attempt to solve a Diophantine Equation, which do not have always a solution and this is even not decidable, which we know after Hilbert's Tenth problem came up. So a guarantee of universal termination is even not possible.
On the other hand if there is a solution, you might find it after some time, provided the solution is not too big and will exceed the computer limitations in memory space and computation time. But this shouldn't crash your computer, a decent Prolog system implementation should gracefully return to the top-level. You can also interrupt the interpreter or stop demanding further solutions.
Bye
I am a novice in prolog programming, i use swi-prolog. Now I'm stucked by some math problems
as we know the predicate :A is 3+3.works well,the answer is A=6.
but if I want to find two digits (A and B) from 0~9 that a+b=6
6 is A+B does't work. so I want to know if there is a easy way to do this? And what if I want to find 3 digits (A,B and C)from 0~9 that A+B+C=13 how to do this ?
the simpler way, working in every Prolog implementation: declare a predicate digit/1 (the notation predicate/N means that predicate has N arguments)
digit(D) :- member(D, [0,1,2,3,4,5,6,7,8,9]).
then you can ask
?- digit(A),digit(B),6 is A+B.
A = 0,
B = 6 ;
A = 1,
B = 5 ;
...
since sum is symmetric, maybe you want to reduce the duplicate solution with
?- digit(A),digit(B),A=<B,6 is A+B.
Using library(clpfd) you can avoid defining your digit/1 predicate, and gain a lot of functionality:
?- [library(clpfd)].
true.
?- [A,B,C] ins 0..9, A+B+C #= 13, label([A,B,C]).
A = 0,
B = 4,
C = 9 ;
A = 0,
B = 5,
C = 8
...
note that now the incognite can stay to the left of the 'assignment'...
My advice to you as a Prolog novice is this:
First things first!
Use clpfd! You can start right now by reading the tag information section on tag clpfd.
Pick up the habit of starting new file with extension .pl with the following line:
:- use_module(library(clpfd)).
Use clpfd everytime you want to express Prolog relations over integers: Every. Single. Time.
Witness that clpfd is already widely available and that it is still gaining ground.
Realize that you will profit the most if you learn clpfd first—not 1970's style (is)/2!
Why? (is)/2 is a low-level feature best used by constraint solver implementors.
Doing math with prolog is interesting.
This looks like an assignment and I would not like to solve it, but I will try to help you find the answer yourself.
Given the restricted range of your problem you could probably define every integer from 0 to 9 by creating a simple prolog programm.
Keep in mind that you can define also functions like:
add3(A, B, C,SUM) :- SUM is A + B + C.
You could try to solve the problem by an Equation Solver.
See this answer:
Equation solver in SWI-Prolog
Or using Constraint Logic Programming.
http://www.swi-prolog.org/man/clpqr.html
Playing with Prolog for the first time and while I thought I knew what it basically is good for, I find it hard to get anything done in it. So, I tried to find the easiest possible task and even fail to accomplish that.
I think it is due to me not knowing how prolog data types (numbers) are supposed to work or they have special syntax.
So, my first attempt to classify even numbers was:
even(0).
even(X) :- even(X-2).
Result: stack overflow for the query: even(2).
So I thought well if this is not it, then maybe it is:
even(0).
even(X+2) :- even(X).
Result of even(2): false.
So my simple question is: How to write such simple things in prolog? Is it all not working because i use numbers?
Why not do it the normal way:
is_even(X) :-
X /\ 0x1 =:= 0.
If you want to enumerate non-negative even numbers upon backtracking when the argument is not bound, this is a different thing altogether. It is probably easy to just say:
even(X) :-
between(0, infinite, X),
is_even(X).
You can use the second definition like this:
?- even(X).
X = 0 ;
X = 2 ;
X = 4 ;
X = 6 . % and so on
There are some differences between is_even/1 and even/1:
is_even/1 will work for any integer, positive or negative
is_even/1 will, surprisingly enough, work for expressions that evaluate to integers, too, for example, X = 3, ..., is_even(X + 1). This is because =:= accepts an arithmetic expression on either side.
even/1 uses between/3, so the domain of X and error conditions are the same as for the third argument of between/3.
As a consequence, even/1 does not work with negative integers or arithmetic expressions.
But wait, there's more!
Apparently, between(0, infinite, X) is not something you can do in almost any Prolog apart from SWI. So, instead, you can use another predicate that will enumerate positive integers (list lengths):
even_f(X) :-
length(_, X),
is_even(X).
(Thank you to #false for this)
Use is/2 to force the arithmetic evaluation. On their own, Prolog terms are just structural symbolic entities, X-2 is a compound term of arity 2, -(X,2):
3 ?- write_canonical( X-2 ).
-(_,2)
true.
But is is for arithmetic expressions:
4 ?- Z is 5-2.
Z = 3.
Your definition should thus be
even(X):- X=:=0 -> true
; X > 0 -> Y is X-2, even(Y).
The drawback of such definition is that it can't be called in a generative fashion, like even(X) to get all the evens generated one after the other.
It is only good for checking a given number. For simplicity, it ignores the negative numbers and always fails for them.