5

I'm starting learning Prolog and I want a program that given a integer P gives to integers A and B such that P = A² + B². If there aren't values of A and B that satisfy this equation, false should be returned

For example: if P = 5, it should give A = 1 and B = 2 (or A = 2 and B = 1) because 1² + 2² = 5.

I was thinking this should work:

giveSum(P, A, B) :- integer(A), integer(B), integer(P), P is A*A + B*B.

with the query:

giveSum(5, A, B).

However, it does not. What should I do? I'm very new to Prolog so I'm still making lot of mistakes.

Thanks in advance!

mat
  • 40,498
  • 3
  • 51
  • 78
Kevin
  • 685
  • 1
  • 7
  • 16

2 Answers2

6

integer/1 is a non-monotonic predicate. It is not a relation that allows the reasoning you expect to apply in this case. To exemplify this:

?- integer(I).
false.

No integer exists, yes? Colour me surprised, to say the least!

Instead of such non-relational constructs, use your Prolog system's CLP(FD) constraints to reason about integers.

For example:

?- 5 #= A*A + B*B.
A in -2..-1\/1..2,
A^2#=_G1025,
_G1025 in 1..4,
_G1025+_G1052#=5,
_G1052 in 1..4,
B^2#=_G406,
B in -2..-1\/1..2

And for concrete solutions:

?- 5 #= A*A + B*B, label([A,B]).
A = -2,
B = -1 ;
A = -2,
B = 1 ;
A = -1,
B = -2 ;
etc.

CLP(FD) constraints are completely pure relations that can be used in the way you expect. See for more information.

Other things I noticed:

  • use_underscores_for_readability_as_is_the_convention_in_prolog instead ofMixingTheCasesToMakePredicatesHardToRead.
  • use declarative names, avoid imperatives. For example, why call it give_sum? This predicate also makes perfect sense if the sum is already given. So, what about sum_of_squares/3, for example?
mat
  • 40,498
  • 3
  • 51
  • 78
  • Thank you very much for your response. I have a few questions. It would be awesome if you could answer them. What does 'a non-monotonic predicate' mean, what does /1 or /3 mean and what does the label() function do? On the Internet I read "Assign a value to each variable in Vars. Labeling means systematically trying out values for the finite domain variables Vars until all of them are ground." for the function labeling(), but I don't really understand it. Also thanks for noticing bad practice, I changed the name and will use underscores and declarative names in the future. – Kevin Jul 21 '16 at 10:42
  • 1
    Please file separate questions for this. They are all worth discussing on their own: 1) definition of monotonicity and 2) what is "labeling"? Only one of your question is simple enough to be answered in a comment: `f/3` is a **predicate indicator** denoting a predicate called `f` with 3 *arguments*. Note that we always talk about **predicates**, which are *more general* than *functions*. Great for the names! Finding and using good, declarative names that do justice to the predicates' **generality** is a very important aspect when programming in Prolog, and probably one of the harder ones. – mat Jul 21 '16 at 11:49
1

For efficiency sake, Prolog implementers have choosen - many,many years ago - some compromise. Now, there are chances your Prolog implements advanced integer arithmetic, like CLP(FD) does. If this is the case, mat' answer is perfect. But some Prologs (maybe a naive ISO Prolog compliant processor), could complain about missing label/1, and (#=)/2. So, a traditional Prolog solution: the technique is called generate and test:

giveSum(P, A, B) :-
  ( integer(P) -> between(1,P,A), between(1,P,B) ; integer(A),integer(B) ),
  P is A*A + B*B.

between/3 it's not an ISO builtin, but it's rather easier than (#=)/2 and label/1 to write :)

Anyway, please follow mat' advice and avoid 'imperative' naming. Often a description of the relation is better, because Prolog it's just that: a relational language.

CapelliC
  • 59,646
  • 5
  • 47
  • 90