Any Symbolic Expression Lib?

Hello,
Does anyone know of a good symbolic expression library to do things like:

  • format an arithmetic expression to a normal form
  • simplify expression
  • factorize expression
  • symbolic differentiation
  • symbolic integration
  • etc

???

The only remotly relevant thing I found was a library for logtalk: Pack logtalk -- logtalk-3.89.1/examples/symdiff/NOTES.md

One time, I learned Term Rewriting System (TRS) in prolog, which is a very nice technique, but it was kind of a let down to realize that without the correct rules, the system is kind of useless.
Maybe somebody know of a good set of TRS rules to transform an arithmetic expression into a Normal Form or something else ?

[edit]
Here is a summary of all the resources linked in this thread:

How else could it work? :grinning_face:

I would also be interested in such a thing.

library(clpBNR)) does implement some of these components to varying degrees:

  1. Public interface partial_derivative/3 symbolically partially differentiates expressions with respect to a variable, e.g.,
?- partial_derivative(X**2,X,PD).
PD = 2*X.

This predicate is useful in implementing meta-contractors for narrowing intervals (often better than simple splitting, e.g., for finding roots of polynomials) and solving differential equations (boundary value problems).

  1. Due to the inherent dependancy issue with interval arithmetic, there’s some motivation to simplify constraint expressions. This is done in a private predicate clpBNR:simplify/2, e.g.,
?- clpBNR:simplify(X+X,Exp).
Exp = 2*X.

I found this (simplify/2) to be quite difficult to implement and it’s not very good IMO (which is the main reason I didn’t make it public) although it helps in a few common cases for this particular application.

So this is just a very minimal start on your list, but it’s in the source code (clpBNR/ia_utilities.pl and clpBNR/ia_simplify.pl) if it’s of any use. Of course, a lot depends on how one defines “normal form”, “simplify”, and “factorize”.

Many years ago I implemented a quick prototipe for symbolic differentiation, you can find it here: GitHub - damianoazzolini/symbolicdiff: Symbolic differentiation and more
It surely can be improved, but this can be a starting point.

FYI

PRESS: PRolog Equation Solving System

Same here :slight_smile:

Rumors say that SWI-Prolog can interface to Python. So, what is needed to execute, from swipl, something like

>>> import sympy as sym
>>> x = sym.Symbol('x')
>>> y = sym.Symbol('y')
>>> x + y + x - y
2*x

and get the 2*x back in Prolog?

For my problem I need to deal with variables which can be constrained, rather than names (i.e., atoms). So

?- clpBNR:simplify(X+Y+X-Y,Exp).
Exp = 0*Y+2*X.

I can’t prematurely reduce 0*Y to 0, because Y could be infinite (in extended set of reals), in which case 0*Y is undefined. If I know Y is finite, then:

?- Y::real,clpBNR:simplify(X+Y+X-Y,Exp).
Exp = 2*X,
Y::real(-1.0e+16, 1.0e+16).

That said, the simplification algorithm should be equivalent for the most part, so I hope there’s something out there that’s an improvement on my hack.

Thanks Eric. This is a rather large repo to get your head around but there is https://github.com/maths/PRESS/blob/026ff5d5e2a572fd05e4313792a177dab6682660/util/tidy.pl from Richard O’Keefe .ca 1984 which covers the same territory as clpBNR:simplify. I need to spend more time to see if it’s any better than what I have and if it can be adapted to suit my needs.

1 Like

Just seen on Reddit:

… which points at the code at Definite clause grammars and symbolic differentiation

For symbolic automatic differentiation you can look at this paper https://arxiv.org/pdf/2305.07878 that appeared in ICLP 2023 with code at GitHub - birthevdb/ad-prolog-code

1 Like

Hello everybody,

Thank you all for your different resources.
I think I will edit my top comment to summarize a list of all the link provided in this thread, so that people can easily explore them.

If I had infinite time, I would love to consolidate an easily installable pack to do these things…

By the way, I’m quite sure that clpfd has something similar to what clpBNR has.
Has anybody become familiar with that code ?

Perhaps a little too “simple” in that it doesn’t simplify the total expression, e.g., using the SWISH implementation:

?- simplify(x+y+x-y,E).
E = x+y+x-y

?- simplify(x+x+y-y,E).
E = number(2)*x+y-y

Simplification is hard (IMO).

Here is a stub to interface sympy

sympy.pl:

:- module(sympy, [sympy/2]).

:- use_module(library(janus)),
    py_import(sympy, []).

sympy(A, R) :-
    sym(A, S),
    mys(S, R).

:- discontiguous sym/2, mys/2.

sym(A, S) :-
    atom(A),
    !, py_call(sympy:'Symbol'(A), S).

mys(S, A) :-
    py_call(S:is_symbol, @(true)),
    !, py_call(S:name, A).

sym(A, S) :-
    integer(A),
    !, py_call(sympy:'Integer'(A), S).

mys(S, A) :-
    py_call(S:is_integer, @(true)),
    !, py_call(int(S), A).

sym(A + B, S) :-
    !, sym(A, A1),
    sym(B, B1),
    py_call(operator:add(A1, B1), S).

mys(S, A + B) :-
    py_call(sympy:'Add', Add),
    py_call(isinstance(S, Add), @(true)),
    !, py_call(S:args, A0-B0),
    mys(A0, A),
    mys(B0, B).

sym(A * B, S) :-
    !, sym(A, A1),
    sym(B, B1),
    py_call(operator:mul(A1, B1), S).

mys(S, A * B) :-
    py_call(sympy:'Mul', Mul),
    py_call(isinstance(S, Mul), @(true)),
    !, py_call(S:args, A0-B0),
    mys(A0, A),
    mys(B0, B).

Example:

1 ?- [sympy].
true.

2 ?- sympy(x + y + 1 + x + y + -1, S).
S = 2*x+2*y ;

There’s a choice point at the end, unclear why.

Press asterisk (i.e. Shift + 8, on most keyboards) to see the location of the choicepoint.

Thanks, found them. Yes, indeed, a number of cuts are needed. Inserted above. I hate the fact that the code is 100% procedural. But let’s say it straight: it’s math, and math is procedural :sweat_smile:

>>> import sympy
>>> x = sympy.Symbol('x')
>>> f = sympy.Piecewise((x**2, x > 2), (1 + x, x <= 2))
>>> f.subs(x, 1), f.subs(x, 2), f.subs(x, 3)
(2, 3, 9)

Calling this from swipl via janus seems feasible, so I guess you wonder if that is also found in native prolog libraries (?)

Something equivalent using mixed boolean, numeric, and reified constraints (e.g., clpBNR):

?- {(X>2,F==X**2) xor (X=<2,F==X+1)}, member(X,[1,2,3]).
X = 1,
F = 2 ;
X = 2,
F = 3 ;
X = 3,
F = 9.

I think you could extend to “undefined” if it could be represent by a real value or, alternatively, result in failure.