Is there any way in prolog to ask questions like 4 is 2^X, and then get back X=2? I've tried to use =, ==, =:= all without success (getting either just false or arguments not sufficiently instantiated).
6
votes
It seems like this might be the real question you were asking in your recent, similar question. Perhaps delete the other, unless it yielded some useful answers?
- Shon
I realize that now, I'm sorry for sort of double-posting! There was some really good answers in that one too, though...
- user1833443
4 Answers
7
votes
With SWI-Prolog and the library(clpfd) you can ask question like that.
?- use_module(library(clpfd)).
% library(apply_macros) compiled into apply_macros 0,00 sec, 39 clauses
% library(assoc) compiled into assoc 0,03 sec, 143 clauses
% library(clpfd) compiled into clpfd 0,11 sec, 1,456 clauses
true.
?- 4 #= 2 * X.
X = 2.
2
votes
You can use between/3 to generate integers:
?- between(1,1000,Y), X is 2 ^ Y, X == 4.
Y = 2,
X = 4 ;
false.
?- between(1,1000,Y), X is 2 ^ Y, X == 32.
Y = 5,
X = 32 ;
false.
You can also use inf for the second argument of between/3, but without some limiting condition that will cause these queries to loop after they give their first answer. (numlist/3, is another option, in case you find it makes more sense to work with lists of numbers instead of generating a new number each time it backtracks).
Writing a general purpose predicate for this might look like,
within_range(Low-High, X=Operation) :-
between(Low, High, V1),
between(Low, High, V2),
Operation =.. [_, V1, V2],
Y is Operation,
Y = X.
Of course, this only works with 2 place operations without considerable tweaking. Some example queries:
?- within_range(1-100, 8=X*Y).
X = 1,
Y = 8 ;
X = 2,
Y = 4 ;
X = 4,
Y = 2 ;
X = 8,
Y = 1 ;
false.
?- within_range(1-100, 8=14-X).
X = 6 ;
false.
2
votes
you can check instantiation status of a variable
% E is X^Y
% here are accepted patterns
%
% exp(+,+,-)
% exp(-,+,+)
% exp(+,-,+)
%
exp(X,Y,E) :-
var(E)
-> E is X^Y % note: will throw an error if either X or Y are not bound to number
; var(X)
-> compute_base_of_exp_here(Y,E,X) % note: as above, with E in place of X
; var(Y)
-> ( X =:= e % we are lucky, only natural logarithms are available as ISO builtin
-> Y is log(X)
; X =:= 2 % again, we could be lucky, log2 can be rather easy to compute...
-> compute_log2_here(E,Y)
; compute_some_complex_math_here(X,E,Y)
)
; E is X^Y . % no vars?
but this is going to be a rather difficult route, without appropriate builtins...
1
votes