Custom printing functions with sympy - sympy

I would like to do some math with sympy. However, working with functions gives a very messy output.
Take the example of the chain rule.
import sympy as sym
def ddt (s):
return sym.diff(s, t)
x, y, z, t = sym.symbols("x y z t")
a = sym.Function('a')(x,y,z,t)
b = sym.Function('b')(x,y,z,t)
c = sym.Function('c')(a, b)
print (ddt(c))
This prints all the dependencies of the variables:
Derivative(a(x, y, z, t), t)*Derivative(c(a(x, y, z, t), b(x, y, z, t)), a(x, y, z, t)) + Derivative(b(x, y, z, t), t)*Derivative(c(a(x, y, z, t), b(x, y, z, t)), b(x, y, z, t))
Anyway of removing the dependencies? (x,y,z,t) do not appear in the output:
And get something like:
Derivative(a, t)*Derivative(c, a) + Derivative(b, t)*Derivative(c, b)
https://latex.codecogs.com/svg.image?\frac{\partial&space;a}{\partial&space;t}\frac{\partial&space;c}{\partial&space;a}&space;+&space;\frac{\partial&space;b}{\partial&space;t}\frac{\partial&space;c}{\partial&space;b}&space;

You have to create a custom printer, which quickly become a tedious job. A basic implementation is this:
from sympy.printing import StrPrinter
from sympy.core.function import AppliedUndef
class MyStrPrinterPrinter(StrPrinter):
""" Extended Latex printer with new options:
1. applied_no_args=False: wheter applied undefined function should be
rendered with their arguments. Default to False.
"""
def __init__(self, settings=None):
self._default_settings.update({
"applied_no_args": False,
}
)
super().__init__(settings)
def _print_Function(self, expr):
if isinstance(expr, AppliedUndef) and self._settings["applied_no_args"]:
return expr.func.__name__
return super()._print_Function(expr)
def my_str(expr, **settings):
return MyStrPrinterPrinter(settings).doprint(expr)
def myprint(expr):
print(my_str(expr, applied_no_args=True))
Then, on your code:
import sympy as sym
sym.init_printing(
def ddt (s):
return sym.diff(s, t)
x, y, z, t = sym.symbols("x y z t")
a = sym.Function('a')(x,y,z,t)
b = sym.Function('b')(x,y,z,t)
c = sym.Function('c')(a, b)
myprint(ddt(c))
# out: Derivative(a, t)*Derivative(c, a) + Derivative(b, t)*Derivative(c, b)
Theoretically, you could execute this line of code at the beginning of your code block, and then it should use the new printer:
sym.init_printing(str_printer=my_str)
Unfortunately, I'm unable to get it working on Jupyter. That's why I created the myprint function.

Related

How to populate a list in prolog at the end of recursion?

I'm trying to implement a cantor set using prolog. The problem is defined in this link. I have implemented the code like this.
create_cantor_set(X, Y, D, List):-
cantor(D, X, Y, Temp), % Depth, X, Y, temporary list
reverse(List, Temp).
% base condition
cantor(1, X, Y, [[X|Y]|_]).
cantor(D, X, Y, Temp):-
X1 is X + ((Y - X) / 3),
Y1 is Y - ((Y - X) / 3),
decrement(D, D1),
cantor(D1, X, X1, [[X|X1]|Temp]),
cantor(D1, Y1, Y, [[Y1|Y]|Temp]).
% Decrement helper
decrement(N, N1):-
N1 is N-1.
However, I'm getting an output like this:
List = [] ;
List = [_4770] ;
List = [_4770, _4776] ;
List = [_4770, _5442, _4776] ;
List = [_4770, _5442, _5448, _4776] ;
List = [_4770, _5442, _6114, _5448, _4776]
I'm not able to understand why it is giving placeholder variables rather than the actual values.
I'm trying to add the set [X|Y] when D = 0. The answer should be one final list. Thank you for your help.
EDIT:
sample query: create_cantor_set(0, 1, 2, List).
expected output: [[0, 0.333],[0.666, 1]]
div_interval(N, X-Y, Xn-Yn) :-
Xn is X/N, Yn is Y/N.
add_interval(A, X-Y, Xa-Ya) :-
Xa is X + A, Ya is Y + A.
step_cantor(Ii, Io) :-
maplist(div_interval(3), Ii, Io1),
maplist(add_interval(2/3), Io1, Io2),
union(Io1, Io2, Io).
cantor(0, [0-1]).
cantor(N, X) :-
N > 0, N1 is N - 1, cantor(N1, X1),
step_cantor(X1, X).
cantor_len(S, L) :-
foldl([X-Y, A, O]>>(O is (A+Y-X)), S, 0, L).
I am representing an interval [a, b] with a pair a-b.
?- cantor(0, X), cantor_len(X, Y).
X = [0-1],
Y = 1
?- cantor(1, X), cantor_len(X, Y).
X = [0-0.3333333333333333, 0.6666666666666666-1.0],
Y = 0.6666666666666666
?- cantor(2, X), cantor_len(X, Y).
X = [0-0.1111111111111111, 0.2222222222222222-0.3333333333333333, 0.6666666666666666-0.7777777777777777, 0.8888888888888888-1.0],
Y = 0.4444444444444444

Prolog - Finding adjacent elements in a list

I'm trying to define a predicate adjacent(X, Y, Zs) that is true if X and Y are adjacent in a list. My code is currently this:
adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
adjacent(X,Y, Tail).
It works for the basic case of adjacent(c, d, [a, b, c, d, e]), but due to the base case, every other case returns true as well, and I'm stuck on that.
The other problem is that if X is not equal to the first part of the list's head, then it skips past both X and Y and goes to the next 'X'; e.g., if c isn't equal to a, then it skips past both a and b and checks if c is equal to c. This is problematic when, for example, the list is
[a, c, d, e]
because it ends up never checking c (I believe).
I'm pretty lost on how to reconcile the two issues and turn my logical understanding of what needs to occur into code.
EDIT: Thanks to Christian Hujer's answer, my base case mistake has been corrected, so now I'm just stuck on the second issue.
In the original solution attempt:
adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
adjacent(X,Y, Tail).
As #ChristianHujer points out, the first clause should not be there because it isn't true. The empty list should have no adjacent elements.
The second clause is also problematic. It shows that X and Y are adjacent in the list, but then recurses and doesn't just succeed. A proper clause should be:
adjacent(X, Y, [X,Y|_]).
Which says that X and Y are adjacent in the list if they're the first two elements in the list, regardless of what the tail is. This also forms a proper base case. Then your general, recursive clause should take care of the rest of the cases:
adjacent(X, Y, [_|Tail]) :-
adjacent(X, Y, Tail).
This says that X and Y are adjacent in [_|Tail] if they're adjacent in Tail. This takes care of the second problem you were encountering.
Thus, the whole solution would be:
adjacent(X, Y, [X,Y|_]).
adjacent(X, Y, [_|Tail]) :-
adjacent(X, Y, Tail).
This will succeed as many times as X and Y appear together, in that order, in the list.
This is also naturally solvable with a DCG (although #repeat's append/3 based solution is more concise):
adjacent(X, Y) --> ..., [X, Y], ... .
... --> [] | [_], ... .
adjacent(X, Y, L) :- phrase(adjacent(X, Y), L).
| ?- adjacent(b, c, [a,b,c,d]).
true ? a
(1 ms) no
| ?-
I think your base case is wrong. In your situation, you want recursion to terminate with a false predicate, not with a true predicate. And it's logical: In an empty list, there are no adjacent elements. Never.
In this answer we try to keep it simple—by building on append/3:
adjacent(E0, E1, Es) :-
append(_, [E0,E1|_], Es).
Sample query:
?- adjacent(X, Y, [a,b,c,d,e]).
X = a, Y = b ;
X = b, Y = c ;
X = c, Y = d ;
X = d, Y = e ;
false.
The auxiliary predicate adjacent_/5 always "lags behind" by exactly two (list items):
adjacent(X0, X1, [E0,E1|Es]) :-
adjacent_(Es, E0, E1, X0, X1).
adjacent_([], E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
if_(E0+E1 = X0+X1,
true,
adjacent_(Es, E1, E2, X0, X1)).
Using SWI-Prolog we run:
?- set_prolog_flag(double_quotes, chars).
true.
?- adjacent(a, b, "abab").
true.
?- adjacent(b, c, "abcd").
true.
?- adjacent(X, Y, "abcd").
X = a, Y = b
; X = b, Y = c
; X = c, Y = d.
Edit
The corrected definition of adjacent_/5 gives right answers for the following queries, too:
?- adjacent(X, X, [A,B,C]).
X = A, A = B
; X = B, B = C, dif(f(C,C),f(A,A)).
?- adjacent(a, X, "aab").
X = a
; X = b.
?- adjacent(a, b, "aab").
true.
Here is a definition that I believe is in the long term preferable to #repeat's solution:
adjacent(X0, X1, [E0,E1|Es]) :-
adjacent_(Es, E0, E1, X0, X1).
adjacent_([], E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
if_(( E0 = X0, E1 = X1 ),
true,
adjacent_(Es, E1, E2, X0, X1)).
Using a reified and:
','(A_1, B_1, T) :-
if_(A_1, call(B_1, T), T = false).
;(A_1, B_1, T) :-
if_(A_1, T = true, call(B_1, T)).

Replace a single occurrence of an element in a list in Prolog

I am given a list, an element to be replaced and the replacement for that element. I managed to do it for all occurrences of the element in that list:
replace([],X,Y,[]).
replace([X|T], X, Y, Z) :-
replace(T, X, Y, Z1),
Z = [Y|Z1].
replace([H|T], X, Y, [H|Z]) :-
replace(T, X, Y, Z).
However now I must only replace the first occurrence of that element.
My thought process writing:
replace([X|T], X, Y, Z) :-
replace(T, X, Y, Z1),
Z = [Y|Z1].
was:
Z is the result of [X|T],X,Y if Z1 is the result of T,XY and Z = [Y|Z1]. Following the same thought process I tried writing the function that only replaces the first occurrence of the element like so:
An idea for implementing only the first occurrence would be from a replace/4 to go in a replace/5 where I count if I replaced or not like so:
replace_single(L,X,Y,Z) :-
replace2(L,X,Y,0,Z).
replace2([],X,Y,C,[]).
replace2([X|T], X, Y, C, Z) :-
\+ (C = 0),
replace2(T, X, Y, C, Z1),
Z = [X|Z1],
C is 1.
replace2([H|T], X, Y, C, [H|Z]) :-
replace2(T, X, Y, C, Z).
Obviously it will not work, I am a little bit lost. Could someone give me a tip or so of how I could think to solve the problem or the solution itself?
We define replace/4 based upon same_length/2, append/3, maplist/2, and prolog-dif:
replace(Xs,X,Y,Ys) :-
same_length(Xs,Ys),
append(Prefix,[X|Suffix],Xs),
maplist(dif(X),Prefix),
append(Prefix,[Y|Suffix],Ys).
Sample queries:
?- replace(Xs,2,two,[1,two,3,4,5,1,2,3,4,5,1,2]).
Xs = [1,2,3,4,5,1,2,3,4,5,1,2]
; false.
?- replace([1,2,3,4,5,1,2,3,4,5,1,2],2,two,Ys).
Ys = [1,two,3,4,5,1,2,3,4,5,1,2]
; false.
Another approach would be to use a DCG:
rep1(X, Y, [Z|T]) --> [Z], { dif(Z, X) }, rep1(X, Y, T).
rep1(X, Y, [Y|T]) --> [X], rest(T).
rep1(_, _, []) --> [].
rest([]) --> [].
rest([H|T]) --> [H], rest(T).
| ?- phrase(rep1(a, 1, L), [a,b,c,a,d]).
L = [1,b,c,a,d] ? ;
| ?- phrase(rep1(a, 1, [x, y, 1, b]), L).
L = [x,y,1,b] ? a
L = [x,y,a,b]
You can write your predicate as:
replace(X, Y, L, R) :- phrase(rep1(X, Y, R), L).
Another way to do it will be:-
replace(E1,L1,E2,L2) :-
same_length(L1,L2),
append(BeforeElement,[E1|AfterElement],L1),
append(BeforeElement,[E2|AfterElement],L2).
where BeforeElement stands for prefix of the list before the element and After Element stands for suffix of the list after the element.

A recursive function returns a none type although the computed type is tuple

I tried to implement a Python version of the de Boor algorithm:
cvx=lambda a, b, t: (1-t) * a + t * b
cvxP=lambda (P, Q, t): (cvx(P[0], Q[0], t), cvx(P[1], Q[1], t))
def omega(u, k, t):
return map(lambda j: (t-u[j])/(u[j+k]-u[j]), xrange(1,k+1))
def cvxList( d, alpha):
return map(cvxP, zip(d[:-1], d[1:], alpha))
def DeBoor(d, u, k, t):
#evaluates a point c(t) on an arc of B-spline curve
# of degree k, defined by:
# u_1<=... u_k<u_{k+1}<=...u_{2k} the sequence of knots
# d_0, d_1, ... d_k de Boor points
# t in [u_k, u_{k+1})
if (k>0):
#print d, u, k
DeBoor(cvxList(d, omega(u, k,t)), u[1:-1], k-1,t )
else:
#print d[0], type(d[0])
return d[0]
The function DeBoor computes a point as a tuple.
However when I check the type for the cpt=DeBoor(args)
it is displayed as NoneType:
d=[(0.16, 0.18), (0.22, 0.84), (0.83, 0.74), (0.80, 0.16)]
u=[j for j in range(7)]
k=3
cpt=DeBoor(d, u, k, 3.5)
print cpt, type(cpt)
>>>(0.5231250000000001, 0.7641666666666667) <type 'tuple'>
>>>None <type 'NoneType'>
I cannot figure out why is not passed the right type to cpt.
Your recursive call isn't returning anything:
if (k>0):
return DeBoor(...)

How to prevent generation of substitions

Sympy sometimes automatically generates substitutions in my experessions:
How can I prevent this? Or, how can I remove the substitution from the expression?
from sympy import *
R, T = symbols('R T', cls=Function)
u = symbols('u', cls=Function)
x, y, z= symbols('x y z')
R(u(x,y)).diff(x)
gives
Derivative(u(x, y), x)*Subs(Derivative(R(_xi_1), _xi_1), (_xi_1,), (u(x, y),))
I'd like to have
Derivative(u(x, y), x)*Derivative(R(u(x, y), (u(x, y)))
PS: http://docs.sympy.org/latest/modules/core.html#subs says "When evaluating derivatives at a point that is not a symbol, a Subs object is returned."
The following will give you what you ask for
>>> s=R(u(x,y)).diff(x)
>>> s.replace(Subs, lambda a,b,c: a.xreplace(dict(zip(b,c))))
(It will revert to a Subs instance if you apply the doit method.)