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.