Search code examples
prologpredicateequationclpq

How do I work with equations that are passed on in the goal/query of prolog?


I have this scenario wherein I get a linear equation in the Prolog query like below:

?- myquery( 3X + 5Y = 10, Result).

So my query has an equation 3X + 5Y = 10, which in general assumes the form AX + BY = C, where A=3, B=5 and C=10.

Now, in my prolog program, I am trying to define a predicate that can take in the expression mentioned in the query above. That is, I somehow want to get A, B and C values and also the operator involved (in the above case the plus operator) stored and then used on the logic that I define withing the program. I am wondering how this can be done.

To be more generic, the question is how do I identify the constants and the operator involved in an equation that is passed on through the goal/query?


Solution

  • The following transcript may prove illuminating:

    32 ?- Term = (3*_X + 5*_Y = 10), functor(Term,F,A).
    
    Term = 3*_G527+5*_G530=10
    F = =
    A = 2 
    
    33 ?- Term = (3*_X + 5*_Y = 10), arg(Arg,Term,Val).
    
    Term = 3*_G459+5*_G462=10
    Arg = 1
    Val = 3*_G459+5*_G462 ; % user pressed ';' interactively
    
    Term = 3*_G459+5*_G462=10
    Arg = 2
    Val = 10 ; % user pressed ';' interactively
    
    No
    35 ?- Term = (3*_X + 5*_Y = 10), arg(1,Term,Val1), functor(Val1,F1,A1),
          arg(2,Val1,Val12).
    
    Term = 3*_G693+5*_G696=10
    Val1 = 3*_G693+5*_G696
    F1 = +
    A1 = 2
    Val12 = 5*_G696 
    

    The last query reads: for Term as given, 1st arg of Term is Val1, the functor of Val1 is F1 with arity A1 (meaning, it has A1 args - subparts - itself), and 2nd arg of the term in Val1 is stored under Val12 name. To clarify, any symbolic data in Prolog is in the form of fff(aa,bb,cc,...) where fff is some name, called functor, and the "arguments" in that expression can be accessed through the arg call.

    That means that the original expression (3*_X + 5*_Y = 10) is actually stored in Prolog as '='( '+'( '*'(3,_X), '*'(5,_Y)), 10). When you get to the atomic parts (functors with arity 0), you can check them further:

    47 ?- arg(1,(3*X),V), functor(V,F,A), number(V).
    
    X = _G441
    V = 3
    F = 3
    A = 0 
    
    Yes
    

    EDIT: to answer your other question (from the comments):

    1 ?- (3*_X + 5*_Y = 10) = (A*X + B*Y = C).
    
    A = 3
    X = _G412
    B = 5
    Y = _G415
    C = 10 
    
    Yes
    

    If you insist on not writing out the multiplication sign * explicitly, you will have to represent your terms as strings, and to analyze that string. That would be a much more involved task.

    EDIT: another thing to try is =.. predicate, called "Univ":

    4 ?- (3*_X + 5*_Y = 10) =.. X.
    
    X = [=, 3*_G454+5*_G457, 10] 
    
    Yes
    5 ?- (3*_X + 5*_Y = 10) =.. X, X=[X1,X2,X3], X2 =.. Y.
    
    X = [=, 3*_G545+5*_G548, 10]
    X1 = =
    X2 = 3*_G545+5*_G548
    X3 = 10
    Y = [+, 3*_G545, 5*_G548] 
    
    Yes