/* SIMPLIFY.
   The aim of the predicate simplify is to reshuffle expressions which
   are sums of unknowns (represented by Prolog atoms) and integers so
   that all the unknowns are at the start and the sum of all the
   integers is at the end, e.g.
         x+3+y+4+z      gets reshuffled to      x+y+z+7
   This is (a) useful in mathematical manipulations by computer
   and     (b) an illustration of a useful technique called
               "difference pairs".

   To summarise the idea: a structure such as +(a,+(b,c)) could be
   drawn as
                 +
                / \
               a   +
                  / \
                 b   c

   The idea is that when constructing such things you can represent
   intermediate stages as the "difference" of
                 +
                / \
               a   +
                  / \
                 b   Zend
   and the variable Zend. To move to the next stage, you just have
   to instantiate Zend as something; if the next stage is also
   intermediate, why not another "difference pair", e.g. Zend =
                 +
                / \
               c   Zend2
   with Zend2 uninstantiated, and so on.
   The predicate normalise defined below shows the idea in practice:
   in  normalise(Formula,V,Vend,N,Nend)
   the unknowns (Prolog atoms) are collected in the difference pair
   of V and Vend, and the integers are collected in the difference
   pair of N and Nend. The predicate simplify tidies up the final
   answer by instantiating the variable end of the structure in which
   the unknowns are collected to the structure in which the integers
   were collected. Note that in the body of simplify, the last argument
   of the call of normalise is 0 - this instantiates the variable at the
   trailing end of the integer-collecting structure, so that the goal
         Vend is N
   succeeds and evaluates the structure as the sum of all the integers!
*/

simplify(Formula,V) :-
         normalise(Formula,V,Vend,N,0),
         Vend is N.

normalise(A+B,V,Vend,N,Nend) :-
         !,
         normalise(A,V,Vsofar,N,Nsofar),
         normalise(B,Vsofar,Vend,Nsofar,Nend).
normalise(Atom,Atom+Vend,Vend,N,N) :-
         atom(Atom),
         !.
normalise(Integer,V,V,Integer+N,N) :-
         integer(Integer).