I have this code in in Python with SymPy:
import sympy
from sympy import symbols, Matrix
phi = symbols('phi')
x = symbols('x')
y = symbols('y')
N1 = sympy.cos(phi)
N2 = sympy.sin(phi)
N3 = -sympy.sin(phi)
N4 = sympy.cos(phi)
N1.subs('phi', sympy.Float(0.785))
N2.subs('phi', sympy.Float(0.785))
N3.subs('phi', sympy.Float(0.785))
N4.subs('phi', sympy.Float(0.785))
x=4
y=2
UVG = Matrix(2, 1, [x, y])
T = Matrix(2, 2, [N1, N2, N3, N4])
UVL = T*UVG
print("hi")
In debug mode the substitution of x =4 and y = 2 do seem to be working however the subs function does not seem to work for phi which is not being updated to an actual numerical value. I can see the output in my debug window where the value of UVL is showing as:
Matrix([[2*sin(phi) + 4*cos(phi)], [-4*sin(phi) + 2*cos(phi)]])
Is there a way for SymPy to get the value of phi to change to an actual floating point or decimal type number so that I can get my transformed x and y back out?
I tried:
N1.subs('phi', sympy.Float(0.785))
N2.subs('phi', sympy.Float(0.785))
N3.subs('phi', sympy.Float(0.785))
N4.subs('phi', sympy.Float(0.785))
and
N1.subs(phi, sympy.Float(0.785))
N2.subs(phi, sympy.Float(0.785))
N3.subs(phi, sympy.Float(0.785))
N4.subs(phi, sympy.Float(0.785))
and
phi = 0.785
none of which seem to work at all in terms of changing phi to a floating point or decimal value or similar type.
SymPy objects are mostly immutable so the result of subs is a new immutable object, not a change to the original object. Several forms of subs all work
But if you want to work with that new value of N1 you have to store it to a new variable. Consider:
>>> from sympy import Tuple
>>> from sympy.abc import x
>>> t = Tuple(2*x, 1/x)
>>> x.subs(x, 2)
2
>>> t # unchanged, containing symbolic x
(2*x, 1/x)
>>> t.subs(x, 1) # replace value of x (=symbol x) with 1 in t
(2, 1)
>>> x = x.subs(x,1) # making x a value, no longer a symbol
>>> t.subs(x, 1) # same as t.subs(1, 1) => no change
(2*x, 1/x)
>>> _ == t
True
The reason it "worked" with x and y is because you defined their values before you used them so you saw the numerical values that you assigned to them in the expression in which they were used.
T = Matrix(2, 2, [N1, N2, N3, N4]).subs('phi',0.785)
from:
https://docs.sympy.org/latest/modules/matrices/common.html?highlight=subs#sympy.matrices.common.MatrixCommon.subs
Related
from sympy import Sum, Eq
from sympy.abc import n,x
import random
def polynomial(x):
i = 0
def random_value(i):
return random.choice([i for i in range(-10,10) if i not in [0]])
eq = Sum(random_value(i)*x**n, (n,0,random_value(i)))
display(Eq(eq,eq.doit(), evaluate=False))
polynomial(x)
polynomial(x)
With this code, the coefficients are always the same.
Also, I am not sure if the algebra evaluations are correct for b < 0 .
One way is to use IndexedBase to generate symbolic-placeholder coefficients, and then substitute them with numerical coefficients.
from sympy import Sum, Eq, Matrix, IndexedBase
from sympy.abc import n, x
import random
def polynomial(x):
# n will go from zero to this positive value
to = random.randint(0, 10)
# generate random coefficients
# It is important for them to be a sympy Matrix or Tuple,
# otherwise the substitution (later step) won't work
coeff = Matrix([random.randint(-10, 10) for i in range(to + 1)])
c = IndexedBase("c")
eq = Sum(c[n]*x**n, (n, 0, to)).doit()
eq = eq.subs(c, coeff)
return eq
display(polynomial(x))
display(polynomial(x))
Another ways is to avoid using Sum, relying instead on list-comprehension syntax and builtin sum:
def polynomial(x):
to = random.randint(0, 10)
coeff = [random.randint(-10, 10) for i in range(to + 1)]
return sum([c * x**n for c, n in zip(coeff, range(to + 1))])
display(polynomial(x))
display(polynomial(x))
You can pass a list of coefficients (with highest order coefficient first and constant last) directly to Poly and then convert that to an expression:
>>> from sympy import Poly
>>> from sympy.abc import x
>>> Poly([1,2,3,4], x)
Poly(x**3 + 2*x**2 + 3*x + 4, x, domain='ZZ')
>>> _.as_expr()
x**3 + 2*x**2 + 3*x + 4
>>> from random import randint, choice
>>> Poly([choice((-1,1))*randint(1,10) for i in range(randint(0, 10))], x).as_expr()
-3*x**4 + 3*x**3 - x**2 - 6*x + 2
I am making an separable differential equation solver. In order to make an expression that separated by x and y variables I have to divide expression on the right by every variable that belong to s such as sin(y), e**y, y**2, ...
I am using Sympy
def equationseparator(diffeq):
x, y, z, e= sym.symbols("x y z e")
separateddiff, separatedeq = diffeq.split("=")
variables_of_eq = re.split('[(|)]', separatedeq)
eq = sym.parse_expr(separatedeq)
variables_of_eq_ordered = []
variables_of_eq_ord_var = []
for var in variables_of_eq:
if var == " * " or var == "":
pass
else:
variables_of_eq_ordered.append(var)
for var in variables_of_eq_ordered:
var = sym.Symbol(var)
variables_of_eq_ord_var.append(var)
print(sym.simplify(separatedeq))
print(variables_of_eq_ordered)
print(variables_of_eq_ord_var)
equationseparator("dy/dx=(6 * x) * (y) * (e**y)")
By using variables_of_eq_ord_var I get all the variables and append to the list. And I want to choose all the expressions that belong to y. But I couldn't make it. Thanks in advance!
Since you are using SymPy, why not use its solver for such equations?
>>> from sympy import S, Function
>>> from sympy.abc import x
>>> f = Function('f')
>>> S('dydx-6*x*y*exp(y)').subs(y,f(x)).subs('dydx',f(x).diff(x))
-6*x*f(x)*exp(f(x)) + Derivative(f(x), x)
>>> dsolve(_)
Eq(Ei(exp_polar(I*pi)*f(x)), C1 + 3*x**2)
Else, if you have a product of factors and want those that contain a certain symbol you can just use as_independent to separate them:
>>> nony, withy = (x*y*exp(y)).as_independent(y); (nony, withy)
(x, y*exp(y))
Thank you in advance and sorry for the bad English!
(ref)Distance from a point to a line < wikipedia
https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
from sympy import *
var('a b c x y x1 y1 x2 y2 x0 y0 co si tx ty d DH')
x1=0
y1=solve([a*x+b*y+c],[y])[y].subs({x:0})
x2=solve([a*x+b*y+c],[x])[x].subs({y:0})
y2=0
d=sqrt((x1-x2)**2+(y1-y2)**2)
v=solve([co*0-si*0+tx-x1,si*0+co*0+ty-y1,co*d-si*0+tx-x2,si*d+co*0+ty-y2],[co,si,tx,ty])
A=Matrix([
[v[co],-v[si],v[tx]],
[v[si], v[co],v[ty]],
[0 , 0, 1]
])
B=Matrix([
[x0],
[y0],
[ 1]
])
AinvB=A.inv()*B
DH=simplify(AinvB[1])
print(DH)
print(float(DH.subs({a:1,b:-1,c:10,x0:0,y0:11})))
print(float(DH.subs({a:1,b:-1,c: 0,x0:0,y0: 1})))
# -c*(a*x0 + b*y0 + c)/(a*b*sqrt(c**2*(a**2 + b**2)/(a**2*b**2)))
# -0.7071067811865476
# nan
The expression you generate is not always valid for all substituted values. In the case that gives nan your expression generates 0/0 which is nan.
>>> from sympy import S, fraction, Tuple
>>> eq=S('-c*(a*x0 + b*y0 + c)/(a*b*sqrt(c**2*(a**2 + b**2)/(a**2*b**2)))')
>>> n,d=fraction(eq)
>>> Tuple(n,d).subs(dict(a=1,b=-1,c=0,x0=0,y0=1))
(0, 0)
>>> _[0]/_[1]
nan
You might be interested in using SymPy's geometric objects to help with such calculations and (in this case) compare their expressions to what you generate by other means:
>>> from sympy.abc import b,m,x,y
>>> from sympy import Point, Line
>>> d=Point(x,y).distance(Line(m*x+b-y))
>>> d
sqrt((x-(-b*m+m*y+x)/(m**2+1))**2 + (y-(b+m**2*y+m*x)/(m**2+1))**2)
>>> d.subs(y, m*x+b).simplify()
0
I want to solve this differential equation in sympy:
f'(x) = f(x+1)
I try this:
from sympy import *
x = symbols("x")
f = Function("f")
f_ = Derivative(f,x)
dsolve(f_(x) - f(x+1), f(x))
but get an error: "'Derivative' object is not callable".
When I replace "f_(x)" by "f_", I get a different error: "TypeError: doit() missing 1 required positional argument: 'self'".
What is the correct syntax for this?
You have to differentiate after providing an argument.
The following works for me:
from sympy import *
x = symbols("x")
f = Function("f")
f_ = Derivative(f(x),x)
dsolve(f_ - f(x+1), f(x))
Sidenote: Solution to your actual problem
What you have is essentially a DDE, just with the time pointing in the wrong direction. The typical form of the DDE would be g'(t) = −g(t−1). With this module of mine, we can solve this numerically:
from jitcdde import y, t, jitcdde
from numpy import arange
f = [-y(0,t-1)]
DDE = jitcdde(f)
DDE.constant_past([1.0])
DDE.step_on_discontinuities()
times = arange(0,1000,0.1) + DDE.t
solution = [(time,DDE.integrate(time)[0]) for time in times]
It seems that no matter how we initialise the past, the solutions eventually converge to something of the form exp(a·t)·sin(b·t) with some constants a and b specified below. In fact if instead of DDE.constant_past([1.0]) we use
a = -0.318131477176434
b = 1.33723563936212
DDE.past_from_function([exp(a*t)*sin(b*t)])
the solution matches exp(a·t)·sin(b·t) extremely well.
Something tells me we're on a hiding to nowhere. This is not a useful answer.
>>> from sympy import *
>>> f = Function('f')
>>> var('x')
x
>>> Eq(f(x).diff(x,x)-f(x+1))
Eq(-f(x + 1) + Derivative(f(x), x, x), 0)
>>> dsolve(_,f(x))
Eq(f(x), C1 + x*(C2 + Integral(f(x + 1), x)) - Integral(x*f(x + 1), x))
>>> latex(_)
'f{\\left (x \\right )} = C_{1} + x \\left(C_{2} + \\int f{\\left (x + 1 \\right )}\\, dx\\right) - \\int x f{\\left (x + 1 \\right )}\\, dx'
As a graphic (having tried various ways of putting the mathematical representation here.)
In Sympy it is possible to define constraints on what values a symbol may take
x = symbols('x', real=True)
Is it possible to say that a symbol should take values only in a certain range, say -1 < x < 1? The reason why I am interested in this is because I am trying to get sympy to automatically simplify expressions like the one below
expr = sqrt(1+x) * sqrt((1-x)*(1+x)) / sqrt(1-x)
Running simplify(expr) yields no simplification, whereas when -1<x<1 the simplified result should be 1+x. How do I get sympy to simplify expressions like the one above?
Although a single symbol can't hold that assumption, an expression can. Let's define an expression that has the desired range:
>>> p = Symbol('p', positive=True)
>>> neg1to1 = (p - 1)/(p + 1)
Now replace x with that value and simplify
>>> asp = expr.subs(x, neg1to1).simplify(); asp
2*p/(p + 1)
Now restore x from the relationship between it and neg1to1:
>>> p_as_x = solve(neg1to1 - x, p)[0]
>>> asp.subs(p, p_as_x).simplify()
x + 1
You could turn this into a function to allow for any range for x:
>>> def simplify_assuming_range(expr, x, lo, hi):
... from sympy import Dummy, solve
... p = Dummy(positive=True)
... xr = (p - 1)/(p + 1)*(hi - lo) + lo
... rx = solve(xr - x, p)[0]
... return expr.subs(x, xr).simplify().subs(p, rx).simplify()
...
>>> simplify_assuming_range(expr,x,-1,1)
x + 1
Using targeted expansion with force can help:
>>> expand(expr, power=True, force=True, mul=False)
x + 1
The expand docstring will tell about each of those options.