I am required to write a prolog predicate count(X,Y,D,N) without using lists that should count the number of elements between two integers X and Y inclusive. However, it should only count those values that are divisible by D.
For example, count(3,6,2,N) should return N = 2 because 4 and 6 are divisible by 2, but 3 and 5 are not.
Recursion is your friend here (as is the case with most things Prolog).
A helper predicate that takes an additional parameter that acts as an accumulator is useful here:
Something like this should do you:
count( X, Y, D, N ) :- count( X, Y, D, 0, N ) .
count( X , Y , D , T , N ) :- X =< Y, % If X <= Y ...
( X rem D =:= 0 % - and X is divisible by D
-> T1 is T+1 % - then increment T
; T1 = T % - otherwise don't
), % and
X1 is X+1, % - increment X
count( X1, Y, D, T1, N ). % - recurse down
count( X , Y , _ , N , N ) :- X > Y. % IF X > Y, we're done: unify the accumulator with the result.
The above is tail-recursive and is for all intents and purposes optimized into iteration. The more classic recursive solution is something like this:
count( X, Y, _, 0 ) :- X > Y .
count( X, Y, D, N ) :- X =< Y ,
X1 is X+1,
count( X1, Y, D, T ),
( 0 =:= X rem D -> N is T+1 ; N = T )
.
I now would like to run tarai, which reads in Prolog as follows. A test case would be to run ?- tarai(12,6,0,X). This is quite a hard test case, for example GNU Prolog crashes with this test case.
tarai(X, Y, Z, R) :-
X > Y ->
X1 is max(0,X-1), tarai(X1, Y, Z, Rx),
Y1 is max(0,Y-1), tarai(Y1, Z, X, Ry),
Z1 is max(0,Z-1), tarai(Z1, X, Y, Rz),
tarai(Rx, Ry, Rz, R);
R = Y.
I am mostly interested whether the test case can be run over a fully declarative version of some miniKanren code for tarai. Optionally I would be interested in running some test cases backwards.
I am a little bit at loss. I managed to install guile, a scheme variant, and can run the miniKanren test cases successfully. But miniKanren has no integer numbers, so what could be done?
Note that this algorithm only has one solution if it's exists and is deterministic. You may pass scheme variables as x,y,z directly to the kanren tarai function, there is no unification for those hence implementing the logic for X,Y,Z can be done without kanren variables. The R values however needs to be logic variables and you need to get the bounded values in the tarai(Rx,Ry,Rz,R) form e.g. lookup the value of Rx,Ry,Rz and feed those into the tarai function. Also you need to make sure that this form is executed after the first three forms has finished (which is easy to do because there is no pure multiple choices) so that you know that Rx,Ry,Rz is bounded. Also note that this algorithm might depend on execution order in order to be executed efficiently but again the determinism means that this point is straightforward to satisfy. Note that A -> B ; C translates here simply to schemes (if A B C) because A = X > Y is deterministic. So the code could look something like this in pseudocode
(define (tarai x y z r)
(lambda ()
(fresh (rx ry rz)
(if (> x y)
(conda
( (conda ((tarai (- x 1) y z rx)
(tarai (- y 1) z x ry)
(tarai (- z 1) x y rz)))
(project (rx ry rz) (tarai rx ry rz r))))
(== r y)))))
To do the deterministic verison in guile-log scheme macro interface see links on this site you can implement it with memoization as (without memoization the solution blows the variable stack on guile-log)
(define tarai
(memo
(<lambda> (x y z r)
(if (> x y)
(<var> (rx ry rz)
(<and>
(tarai (max (- x 1) 0) y z rx)
(tarai (max (- y 1) 0) z x ry)
(tarai (max (- z 1) 0) x y rz)
(tarai (<lookup> rx) (<lookup> ry) (<lookup> rz) r)))
(<=> r y)))))
scheme#(guile-user)> ,time (<run> 1 (r) (tarai 12 6 0 r))
$13 = (12)
;; 0.293411s real time, 0.290711s run time. 0.000000s spent in GC.
scheme#(guile-user)>
I tried running for example tarai(12,X,0,12) with clpfd, but it's to complex for it. And memoizing does not work with attributed variables for swipl. So the best solution atm that I can find is to use the deterministic memoized tarai with something like
tarai2(X,Y,Z,W) :-
(var(X)->between(0,20,X);true),
(var(Y)->between(0,20,Y);true),
(var(z)->between(0,20,Z);true),
tarai(X,Y,Z,W).
then all solutions Y,Z in that range with tarai2(12,Y,Z,12) can easilly be found.
The question was refrased to ask for how to implement a more general version of the tarai function in the prolog spec that allows variables in x,y,z fields. The technique here can be implemented in prolog with e.g. clpfd finite domain solver and something similar is needed for kanren (se comment discussions above e.g. the reference to numbers.scm). The key thing is to nuke -> and use guards for all cases and we will assume that operators >o =o <=o is all defined for variables (e.g. for var X, X > 0 will constrain X to be values 1,2,3,...). Also we will asume that '-o' is defined for variables as well of this kind using interval arithmetics constraints via a special 'iso'. Using this we can define tarai as the code below (this can be simplified if max and min is also defined as constraints but here we implement those via inequalities and a dived of cases in stead).
(define (taray x y z w)
(lambda ()
(conde ((<o x y)
(fresh (rx ry rz)
(conde
((conde
((>o x 0)
(fresh (xx)
(conde
((iso xx (-o x 1))
(tarai xx y z rx)))))
((== x 0) (tarai 0 y z rx)))
(conde
((>o y 0)
(fresh (yy)
(conde
((iso yy (-o y 1))
(tarai yy z x ry)))))
((== y 0) (tarai 0 z x ry)))
(conde
((>o z 0)
(fresh (zz)
(conde
((iso zz (-o z 1))
(tarai zz x y rz)))))
((== z 0) (tarai 0 x y r<)))
(tarai rx ry rz r)))))
((>=o x y) (== x y))))))
I'm the developer of guile-log a logic programming environment on guile scheme that has both minikanren constructs and prolog constructs and one can mix them. It also has a clpfd library ported so here you can do the following (unfourtunately atm it does not work (a bug i'm working on)). Assume that clpfd is imported. (,, ;; is interleaving kanren like ops). Replacing ,, with , and ;; with ; you get code that can run on for example swi prolog using the clpfd library.
tarai(X,Y,Z,W) :-
(
X #> Y ,
(
(
((X #> 0 , XX #= X - 1, tarai(XX,Y,Z,RX)) ;;
(X = 0 , tarai(0,Y,Z,RX))) ,,
((Y #> 0 , YY #= Y - 1, tarai(YY,Z,X,RY)) ;;
(Y = 0 , tarai(0,Z,X,RY))) ,,
((Z #> 0 , ZZ #= Z - 1, tarai(ZZ,X,Y,RZ)) ;;
(Z = 0 , tarai(0,X,Y,RZ)))
) ,,
tarai(RX,TY,RZ,R)
)
) ;;
(X #=< Y, R=Y).
This is a slow implementation that is declarative and uses numbers.scm (as suggested by the author of the question) and minkanren.
(load "minkanren.scm)
(load "numbers.scm")
(define one (build-num 1))
(define zero (build-num 0))
(define (tarai x y z r)
(conde
((<=o x y) (== r y))
((<o y x)
(fresh (rx ry rz)
(conde
((fresh (xx)
(conde
((<o zero x) (minuso x one xx) (tarai xx y z rx))
((== zero x) (tarai zero y z rx))))
(fresh (yy)
(conde
((<o zero y) (minuso y one yy) (tarai yy z x ry))
((== zero y) (tarai zero z x ry))))
(fresh (zz)
(conde
((<o zero z) (minuso z one zz) (tarai zz x y rz))
((== zero z) (tarai zero x y rz))))
(tarai rx ry rz r)))))))
If the derivation direction is reversed (so wee add numbers) we can still solve due to the declarative style,
tarai(4,2,Z,4):, (you need to make binaries of the number) will lead to
Y = [0, 1],
W = [0, 0, 1],
Z = [0, 0, 1],
X = [0, 0, 1].
And supposedly if tabling is added:
tarai(12,6,0,W):
Z = (),
X = [0, 0, 1, 1],
Y = [0, 1, 1],
W = [0, 0, 1, 1].
For example if I want to get all possible natural number pairs that sum to 10, how would I get prolog to do that?
If my code is something like this:
sumsTo10(X,Y):-
Z is X+Y,
Z == 10.
Then yes, if I ask if 5 and 5 sum to 10 I get a true as an answer, but I'd like something like this:
?-sumsTo10(A,B).
[1,9]
[2,8]
....
You can use the Constraint Logic Programming library over Finite Domains (clpfd) for that:
:- use_module(library(clpfd)).
sumsTo10(X,Y):-
[X,Y] ins 1..10,
X + Y #= 10,
label([X,Y]).
This then generates:
?- sumsTo10(X,Y).
X = 1,
Y = 9 ;
X = 2,
Y = 8 ;
X = 3,
Y = 7 ;
X = 4,
Y = 6 ;
X = Y, Y = 5 ;
X = 6,
Y = 4 ;
X = 7,
Y = 3 ;
X = 8,
Y = 2 ;
X = 9,
Y = 1.
The first line specifies that both X and Y are in the 1..10 domain (that is 10 inclusive, but that does not matter). The second line is a constraint: it restricts the fact that X + Y should be equal (#=) to 10. This only adds the constraint: it will not ground X and Y to values where this actually holds, but from the moment X and Y are (partially) grounded, and the constraint is not met, it will fail. If you for instance set X to 10, it will derive that Y can only be 0, but since Y is in the interval 1..10, that is not possible hence the system will fail.
Finally by using label([X,Y]) we will assign values in the domain to X and Y such that the constraint holds.
Your Prolog could provide between/3. Then
?- between(1,10,X), between(1,10,Y), X+Y =:= 10.
X = 1,
Y = 9 ;
X = 2,
Y = 8 ;
X = 3,
Y = 7
...
This question already has answers here:
Value of bindings in SML?
(2 answers)
Closed 6 years ago.
Could someone please help. I don't get the sequence of evaluation here and how we got values of "ans". e.g. in the first example there's no value of y and I'm not sure whether this returns a pair or calls x ! (fn y => y x). It would be very helpful if you can Trace each expression.
val x = 1
val f = (fn y => y x)
val x = 7
val g = (fn y => x - y)
val ans = f g
val ans = 6 : int
=====================================
fun f p =
let
val x = 3
val y = 4
val (z,w) = p
in
(z (w y)) + x
end
val x = 1
val y = 2
val ans = f((fn z => x + z), (fn x => x + x + 0))
val ans = 12 : int
There are a few things which help make problems like this much clearer
when trying understand an alien function Lexical scoping works.
add in types to the parameters and return values without modifying the program, the compiler will tell you if you get it wrong...
replace anonymous functions with named ones.
rename variable bindings that have the same names but refer to different lexical scope.
remove variable bindings that only get used once.
binding a value to a name does not actually perform any computation,
so is merely for the benefit of the reader, if it is not doing that job
it merely serves to obfuscate, then by all means remove it.
fun f (y1 : int -> 'a) = y1 1 : 'a;
fun g (y2 : int) = 7 - y2 : int;
val ans : int = f g;
so g is given as a parameter to f, f calls g giving it the parameter x having the value 1 making y2 = 1, which g subtracts 7 - 1 returning 6.
the return value of g is an int, thus f's 'a type when g is applied to it is an int.
for the 2nd one clean it up a bit, I pulled the anonymous fn's out into their own and named values and call f (foo, bar) to make it more readable...
fun f p =
let val x = 3
val y = 4
val (z, w) = p
in (z (w y)) + x end
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
Finally, we can get rid of the let values which are only used once
and replace the (z,w) = p with just (z, w) as a parameter to the function which should be much easier to follow
fun f (z, w) = (z (w 4)) + 3
fun foo z = z + 1;
fun bar x = x * 2;
val ans = f(foo, bar);
val ans = ((4 * 2) + 1) + 3
I'm trying to implement a program that takes a variable with multiple values and evaluates all the values. For instance:
foo(X,R) :-
X > 2,
Z is R + 1,
R = Z.
This program might not be valid, but it will help me ask the question regardless.
My question: If X has multiple values, how would I increment the counter for each value X > 2?
In order to instantiate X to increasingly larger integers you can use the following:
?- between(0, inf, X).
X = 0 ;
X = 1 ;
X = 2 ;
X = 3 ;
X = 4 ;
<ETC.>
PS1: Notice that you have to instantiate R as well since it is used in the arithmetic expression Z is R + 1.
PS2: Notice that your program fails for all instantiations of X and R since R =\= R + 1 for finite R. The for instance means that the following query will not terminate:
?- between(0, inf, X), foo(X, 1).
Alternatively, the program can be rewritten in library CLP(FD) (created by Markus Triska):
:- use_module(library(clpfd)).
foo(X,R):-
X #> 2,
Z #= R + 1,
R #= Z.