Can't check equality with unknowns in Prolog

74 Views Asked by At

When trying with a simple program to find numbers that multiply to make 100, I can check for set values, like prod_hundred(2, 50), but if I want to find a value with prod_hundred(4, X), I get :

Arguments are not sufficiently instantiated
In:
   [1] 4*_1680=:=100

I know this is because I can't use '=:=' to evaluate with unknowns, but with == it just compares "2*50" to "100", instead of evaluating 2*50

Code:

prod_hundred(X, Y) :- X*Y =:= 100.

?- prod_hundred(4, X).

Arguments are not sufficiently instantiated
In:
   [1] 2*_1680=:=100
3

There are 3 best solutions below

0
TessellatingHeckler On BEST ANSWER

"Solve for X" is harder than evaluating 2*50 to get the result; it needs math knowledge of how to rearrange the equation to 100/4 = X. Classic Prolog doesn't have that built in, you would have to code it yourself.

But that kind of thing is in newer constraint solver libraries such as clpfd in SWI Prolog which gives you #= and can solve by finding integer answers to number problems:

:- use_module(library(clpfd)).

prod_hundred(X, Y) :- 
    X*Y #= 100.

Then:

?- prod_hundred(4, X).
X = 25
1
brebs On
makes_mult(Tot, X, Y) :-
    between(1, Tot, X),
    divmod(Tot, X, Y, 0).

Result in swi-prolog:

?- time(findall((X, Y), makes_mult(100, X, Y), Tuples)).
% 220 inferences, 0.000 CPU in 0.000 seconds (100% CPU, 575084 Lips)
Tuples = [(1,100),(2,50),(4,25),(5,20),(10,10),(20,5),(25,4),(50,2),(100,1)].
0
Nicholas Carey On

Try

factor(F,N) :- integer(N),
  L is N // 2 ,
  ( between(1,L,F) ; N ),
  0 =:= N rem F
  .
  
factors(X,Y,Z) :- integer(Z),
  factor(X,Z),
  factor(Y,Z),
  Z is X * Y
  .

prod_hundred(X,Y) :- factors(X,Y,100).