possible bug in source code for symdiff.pl for Introduction to Prolog for Mathematicians

View: New views
3 Messages — Rating Filter:   Alert me  

possible bug in source code for symdiff.pl for Introduction to Prolog for Mathematicians

by Benjamin L.Russell :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

When I try to follow the section "Example of top-level interpreter" (http://burks.bton.ac.uk/burks/language/prolog/pms/node18.htm) in the online textbook Introduction to Prolog for Mathematicians (http://burks.bton.ac.uk/burks/language/prolog/pms/pms.htm), I am unable to get the example given in the book to work as shown.

Here is the section from the book that I am trying to follow (see http://burks.bton.ac.uk/burks/language/prolog/pms/node18.htm):

--
Example of top-level interpreter

Example, using the simple differentiator in symdiff.pl (http://burks.bton.ac.uk/burks/language/prolog/pms/symdiff.pl):

?- d( x^2, x, Result ).
Result = 2 * 1 * x ^ (2 - 1)

d does not simplify its result. The predicate simp does, and we can combine them as if in the tail of a clause:

?- d( x^2, x, Result ), simp( Result, SimplifiedResult ).
Result = 2 * 1 * x ^ (2 - 1)
SimplifiedResult = 2 * x

All the variables that appear in questions are existentially quantified
--

The above-mentioned symdiff.pl was not available at the above-mentioned URL of http://burks.bton.ac.uk/burks/language/prolog/pms/symdiff.pl, but I found one at http://www.j-paine.org/prolog/mathnotes/files/symdiff.pl.

After loading symdiff.pl (whose source code is given later in this message) in SWI-Prolog version 5.6.55, the first example above,

1 ?- d( x^2, x, Result ).

works, returning

Result = 2 * 1 * x ^ (2 - 1)

However, the second example above,

2 ?- d( x^2, x, Result ), simp( Result, SimplifiedResult ).

returns the following error message:

ERROR: numeric/1: Undefined procedure: real/1
ERROR:     However, there are definitions for:
ERROR:         read/1
ERROR:         read/1
ERROR:         read/2
   Exception: (8) simp(2*1*x^ (2-1), _G514) ?

Here is a transcript of the entire session (starting with double-clicking on symdiff.pl to invoke SWI-Prolog) (notice the warning messages at the beginning of the session):

--
Warning: c:/documents and settings/benjamin/my documents/prolog/test/symdiff.pl:62:
        Singleton variables: [X]
Warning: c:/documents and settings/benjamin/my documents/prolog/test/symdiff.pl:144:
        Singleton variables: [X]
Warning: c:/documents and settings/benjamin/my documents/prolog/test/symdiff.pl:146:
        Singleton variables: [X]
Warning: c:/documents and settings/benjamin/my documents/prolog/test/symdiff.pl:148:
        Singleton variables: [X]
Warning: c:/documents and settings/benjamin/my documents/prolog/test/symdiff.pl:160:
        Singleton variables: [X]
% c:/Documents and Settings/Benjamin/My Documents/Prolog/Test/symdiff.pl compiled 0.00 sec, 8,672 bytes
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 5.6.55)
Copyright (c) 1990-2008 University of Amsterdam.
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

1 ?- d( x^2, x, Result ).
Result = 2*1*x^ (2-1) .

2 ?- d( x^2, x, Result ), simp( Result, SimplifiedResult ).
ERROR: numeric/1: Undefined procedure: real/1
ERROR:     However, there are definitions for:
ERROR:         read/1
ERROR:         read/1
ERROR:         read/2
   Exception: (8) simp(2*1*x^ (2-1), _G514) ?
--

Also, for reference, here is the source code for symdiff.pl:

--
  /*---------------------------------------------------------*/
  /*                                                         */
  /*                       'SYMDIFF'                         */
  /*                                                         */
  /*  Symbolic Differentiation and Algebraic Simplification  */
  /*                                                         */
  /*    The declarative semantics of Prolog are a powerful   */
  /*  tool for problems involving symbolic manipulation.     */
  /*    In this example the rules for differentiation are    */
  /*  expressed as a set of clauses, where, provided that    */
  /*  the head matches the expression in question, the body  */
  /*  furnishes the appropriate result. This result in turn  */
  /*  is passed to the simplifying clauses which operate on  */
  /*  the same principle, but obviously correspond to a      */
  /*  different set of (simplifying) rules.                  */
  /*                                                         */
  /*---------------------------------------------------------*/


/*  This is the main predicate. */        

symdiff :-
   nl,
   write('SYMDIFF : Symbolic Differentiation and '),
   write('Algebraic Simplification. Version 1.0'), nl,
   symdiff1.


  /*  symdiff1 controls the main processing; It prompts  */
  /*  the user for data, differentiates the input,       */
  /*  simplifies the result and then displays it on      */
  /*  the terminal.                                      */

symdiff1  :-
   write('Enter a symbolic expression, or "stop" '),
   read(Exp),
   process( Exp ).


process( stop ) :- !.

process( Exp ) :-
   write('Differentiate w.r.t. :'),
   read(Wrt),
   d( Exp, Wrt, Diff ),
   simp( Diff, Sdiff ), nl,
   write('Differential w.r.t '), write(Wrt),
   write(' is '),
   write(Sdiff), nl, nl,
   symdiff1.



  /*  The following clauses constitute the differentiation   */
  /*  rules, some of which are recursive. Note too the use   */
  /*  of the cut which ensures that once a special case has  */
  /*  been identified, backtracking will not attempt to find */
  /*  an alternative solution.                               */

d( X, X, 1 ):- !.                  /* d(X) w.r.t. X is 1      */

d( C, X, 0 ):- atomic(C).          /* If C is a constant then */
                                   /* d(C)/dX is 0            */

d( U+V, X, A+B ):-                 /* d(U+V)/dX = A+B where   */
   d( U, X, A ),                   /* A = d(U)/dX and         */
   d( V, X, B ).                   /* B = d(V)/dX             */

d( U-V, X, A-B ):-                 /* d(U-V)/dX = A-B where   */
   d( U, X, A ),                   /* A = d(U)/dX and         */
   d( V, X, B ).                   /* B = d(V)/dX             */

d( C*U, X, C*A ):-               /* d(C*U)/dX = C*A where     */
   atomic(C),                    /* C is a number or variable */
   C \= X,                       /* not equal to X and        */
   d( U, X, A ), !.              /* A = d(U)/dX               */

d( U*V, X, B*U+A*V ):-           /* d(U*V)/dX = B*U+A*V where */
   d( U, X, A ),                 /* A = d(U)/dX and           */
   d( V, X, B ).                 /* B = d(V)/dX               */

d( U/V, X, (A*V-B*U)/(V*V) ):- /* d(U/V)/dX = (A*V-B*U)/(V*V) */
   d( U, X, A),                /* where A = d(U)/dX and       */
   d( V, X, B).                /*       B = d(V)/dX           */

d( U^C, X, C*A*U^(C-1) ):-       /* d(U^C)/dX = C*A*U^(C-1)   */
   atomic(C),                    /* where C is a number or    */
   C\=X,                         /* variable not equal to X   */
   d( U, X, A ).                 /* and d(U)/dX = A           */

d( U^C, X, C*A*U^(C-1) ):-       /* d(U^C)/dX = C*A*U^(C-1)   */
   C = -(C1), atomic(C1),        /* where C is a negated number or  */
   C1\=X,                        /* variable not equal to X   */
   d( U, X, A ).                 /* and d(U)/dX = A           */

d( sin(W), X, Z*cos(W) ):-       /* d(sin(W))/dX = Z*cos(W)   */
   d( W, X, Z).                  /* where Z = d(W)/dX         */

d( exp(W), X, Z*exp(W) ):-       /* d(exp(W))/dX = Z*exp(W)   */
   d( W, X, Z).                  /* where Z = d(W)/dX         */

d( log(W), X, Z/W ):-            /* d(log(W))/dX = Z/W        */
   d( W, X, Z).                  /* where Z = d(W)/dX         */

d( cos(W), X, -(Z*sin(W)) ):-    /* d(cos(W))/dX = Z*sin(W)   */
   d( W, X, Z).                  /* where Z = d(W)/dX         */



  /*  The following clauses are rules for the simplification  */
  /*  of the result of the differentiation process. For       */
  /*  example, multiples of zero are dropped, terms gathered  */
  /*  together where possible and factorisation is attempted. */
  /*  (It should be noted that in this program only adjacent  */
  /*  terms are candidates for simplification.)               */

simp( X, X ):-          /* an atom or number is simplified */
   atomic(X), !.

simp( X+0, Y ):-        /* terms of value zero are dropped  */
   simp( X, Y ).

simp( 0+X, Y ):-        /* terms of value zero are dropped  */
   simp( X, Y ).

simp( X-0, Y ):-        /* terms of value zero are dropped  */
   simp( X, Y ).

simp( 0-X, -(Y) ):-     /* terms of value zero are dropped  */
   simp( X, Y ).

simp( A+B, C ):-        /* sum numbers */
   numeric(A),
   numeric(B),
   C is A+B.

simp( A-A, 0 ).         /* evaluate differences */

simp( A-B, C ):-        /* evaluate differences */
   numeric(A),
   numeric(B),
   C is A-B.

simp( X*0, 0 ).         /* multiples of zero are zero */

simp( 0*X, 0 ).         /* multiples of zero are zero */

simp( 0/X, 0 ).         /* numerators evaluating to zero are zero */

simp( X*1, X ).         /* one is the identity for multiplication */

simp( 1*X, X ).         /* one is the identity for multiplication */

simp( X/1, X ).         /* divisors of one evaluate to the numerator */

simp( X/X, 1 ) :- !.

simp( X^1, X ) :- !.

simp( X^0, 1 ) :- !.

simp( X*X, X^2 ) :- !.

simp( X*X^A, Y ) :-
   simp( X^(A+1), Y ), !.

simp( X^A*X, Y ) :-
   simp( X^(A+1), Y ), !.

simp( A*B, X ) :-       /* do evaluation if both are numbers  */
   numeric( A ),
   numeric( B ),
   X is A*B.

simp( A*X+B*X, Z ):-    /* factorisation and recursive */
   A\=X, B\=X,          /* simplification              */
   simp( (A+B)*X, Z ).

simp( (A+B)*(A-B), X^2-Y^2 ):-   /* difference of two squares */
   simp( A, X ),
   simp( B, Y ).

simp( X^A/X^B, X^C ):-     /* quotient of numeric powers of X */
   numeric(A), numeric(B),
   C is A-B.

simp( A/B, X ) :-       /* do evaluation if both are numbers  */
   numeric( A ),
   numeric( B ),
   X is A/B.

simp( A^B, X ) :-       /* do evaluation if both are numbers  */
   numeric( A ),
   numeric( B ),
   X is A^B.

simp( W+X, Q ):-        /* catchall */
   simp( W, Y ),
   simp( X, Z ),
   ( W \== Y ; X \== Z ), /* ensure some simplification has taken place */
   simp( Y+Z, Q ).

simp( W-X, Q ):-        /* catchall */
   simp( W, Y ),
   simp( X, Z ),
   ( W \== Y ; X \== Z ), /* ensure some simplification has taken place */
   simp( Y-Z, Q ).

simp( W*X, Q ):-        /* catchall */
   simp( W, Y ),
   simp( X, Z ),
   ( W \== Y  ; X \== Z ), /* ensure some simplificaion has taken place */
   simp( Y*Z, Q ).

simp( A/B, C ) :-
   simp( A, X ),
   simp( B, Y ),
   ( A \== X ; B \== Y ),
   simp( X/Y, C ).

simp( X^A, C ) :-
   simp( A, B ),
   A \== B,
   simp( X^B, C).

simp( X, X ).           /* if all else fails... */              


numeric(A) :- integer(A).

numeric(A) :- real(A).
--

Any ideas on what's wrong, and how this bug can be fixed?

Benjamin L. Russell
_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: possible bug in source code for symdiff.pl for Introduction to Prolog for Mathematicians

by Bart Demoen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


the line

numeric(A) :- real(A).

should be

numeric(A) :- float(A).



maybe even better would be to replace all calls to numeric/1 with calls to
the builtin number/1
and delete the definition of numeric/1

Cheers

Bart Demoen

_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog

Re: possible bug in source code for symdiff.pl for Introduction to Prolog for Mathematicians

by Benjamin L.Russell :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thank you!  Replacing

numeric(A) :- real(A).

with

numeric(A) :- float(A).

in symdiff.pl worked:

--
2 ?- d( x^2, x, Result ), simp( Result, SimplifiedResult ).
Result = 2*1*x^ (2-1),
SimplifiedResult = 2*x .
--

In addition, replacing all calls to numeric/1 with calls to the builtin number/1 and deleting the definition of numeric/1 also worked:

--
1 ?- d( x^2, x, Result ).
Result = 2*1*x^ (2-1) .

2 ?- d( x^2, x, Result ), simp( Result, SimplifiedResult ).
Result = 2*1*x^ (2-1),
SimplifiedResult = 2*x .
--

I wonder why they defined numeric/1 in the first place?

Benjamin L. Russell

--- On Tue, 6/3/08, Bart Demoen <Bart.Demoen@...> wrote:

> From: Bart Demoen <Bart.Demoen@...>
> Subject: Re: [SWIPL] possible bug in source code for symdiff.pl for Introduction to Prolog for Mathematicians
> To: dekudekuplex@...
> Cc: swi-prolog@...
> Date: Tuesday, June 3, 2008, 7:54 PM
> the line
>
> numeric(A) :- real(A).
>
> should be
>
> numeric(A) :- float(A).
>
>
>
> maybe even better would be to replace all calls to
> numeric/1 with calls to
> the builtin number/1
> and delete the definition of numeric/1
>
> Cheers
>
> Bart Demoen
_______________________________________________
SWI-Prolog mailing list
SWI-Prolog@...
https://mailbox.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
LightInTheBox - Buy quality products at wholesale price