4

I have a prolog program with given grammar:

sum --> [+], mult, sum | mult | num.
mult --> [*], num, xer.
xer --> [x] | [^], [x], num.
num --> [2] | [3] ... etc

I have an abstract tree representation of my expressions. For example: mul(num(2),var(x)) which equals [*,2,x] is valid. I want to be able to create all expressions that satisfies a given x and solution. Using

allExpressions(Tree, X, Solution).

For example:

?- allExpressions(Tree, 2, 6)
Tree = mul(num(3),x)
Tree = sum(num(2),mul(num(2),var(x))
etc.

Due to my grammar it will obviously not be an unlimited set of equations for this. I have already programmed an evaluation(Tree, X, Solution) which calculates the answer given the X-variable. So what I need help to is to generate the possible set of equations for given x-variable and solution.

Any ideas to how I approach this? Thanks

false
  • 10,264
  • 13
  • 101
  • 209
knordbo
  • 552
  • 3
  • 7
  • As stated below, it works as desired with more recent versions of SWI-Prolog. To make it work for older versions, add the constraint `N1 #< N` among the first lines of the clause for exponentiation. – mat Nov 16 '13 at 20:19
  • @mat I added the line, but still my output is only one line for each of my testcases. Do you see anything wrong? Also, do you know a simple way to make num work for all integers >= 2 instead of stating them like 2 | 3 | 4 | 5 ... etc? – knordbo Nov 16 '13 at 21:54
  • It works for me with SWI >= 6.5.2 with the code you show now. Of course you have to press SPACE for additional solutions after the first one. You can easily describe concrete integers in a DCG for example with `num --> [N], { between(2,5,N) }.`. – mat Nov 16 '13 at 22:06
  • Thanks a lot, my bug was in the way i represented num, between worked fine! – knordbo Nov 16 '13 at 22:17

1 Answers1

4

That's easy: Since all of your arithmetic operations can only increase the value of expressions, it is simple to limit the depth when searching for solutions. Simply describe inductively what a solution can look like. You can do it for example with SWI-Prolog's finite domain constraints for addition and multiplication like this:

:- use_module(library(clpfd)).

expression(var(x), X, X).
expression(num(N), _, N) :- phrase(num, [N]).
expression(mul(A,B), X, N) :-
        N1 * N2 #= N,
        N1 #> 1,
        N2 #> 1,
        expression(A, X, N1),
        expression(B, X, N2).
expression(sum(A,B), X, N) :-
        N1 + N2 #= N,
        N1 #> 1,
        N2 #> 1,
        expression(A, X, N1),
        expression(B, X, N2).

I leave the other operations as an exercise.

Example query and some results:

?- expression(Tree, 2, 6).
Tree = mul(var(x), num(3)) ;
Tree = mul(num(2), num(3)) ;
    [...solutions omitted...]
Tree = sum(num(2), mul(num(2), var(x))) ;
Tree = sum(num(2), mul(num(2), num(2))) ;
    [...solutions omitted...]
Tree = sum(sum(num(2), num(2)), num(2)) ;
false.

+1 for using a clean, non-defaulty representation for expression trees (var(x), num(N) etc.), which lets you use pattern matching when reasoning about it.

mat
  • 40,498
  • 3
  • 51
  • 78
  • Thanks for a good answer, which seems very logical. However when implementing this, `?- expression(Tree,2,6).` gives me only one answer `Tree = num(6).` I used your implementation with the additional [^] operator. Any idea what I did wrong? – knordbo Nov 16 '13 at 17:35
  • Actually, ?- Tree = mult(var(x), num(3)) is the only thing I get, check my code in the edit! – knordbo Nov 16 '13 at 17:55
  • You probably are not using the most recent git version of SWI-Prolog. With older versions, you must add the constraint `N1 #< N` to the clause for exponentiation to let the constraint solver know that `N1` is smaller than `N`. In more recent versions, it no longer needs this hint and deduces this on its own. Once you add this additional constraint to your last clause or upgrade your SWI version, it should work for you. – mat Nov 16 '13 at 20:44