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
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
sympy.line.equation()
Same value and type, but what's the difference?"
How can I fix it?
What is the difference between z1 and z2?
from sympy import *
var('x y z1 z2')
z1=8*x+6*y+48
print("#z1",z1,type(z1))
z2=Line(Point(-6,0),Point(0,-8)).equation()
print("#z2",z2,type(z2))
if type(z1)==type(z2):
print("#","type==")
else:
print("#","type<>")
if z1==z2:
print("#","==")
else:
print("#","<>")
#z1 8*x + 6*y + 48 <class 'sympy.core.add.Add'>
#z2 8*x + 6*y + 48 <class 'sympy.core.add.Add'>
# type==
# <>
I try add .expand().simplify() 30 mins ago
from sympy import *
var('x y')
print("#z1#",solve(8*x+6*y+ 48 ,y))
print("# ", Line(Point(-6,0),Point(0,-8)).equation().expand().simplify() )
print("#z2#",solve(Line(Point(-6,0),Point(0,-8)).equation().expand().simplify(),y))
#z1# [-4*x/3 - 8]
# 8*x + 6*y + 48
#z2# []
Thank you.
from sympy import *
var('x y')
print("#z1#",solve(8*x+6*y+ 48 ,y))
print("# ", Line(Point(-6,0),Point(0,-8)).equation() )
print("#z2#",solve(sympify(str(Line(Point(-6,0),Point(0,-8)).equation())),y))
#z1# [-4*x/3 - 8]
# 8*x + 6*y + 48
#z2# [-4*x/3 - 8]
The equality operator (==) in SymPy tests whether expressions have identical form, not whether they are mathematically equivalent.
If you want to determine the mathematical equivalence of nontrivial expressions, you should apply a more advanced simplification routine to both sides of the equation. In the case of polynomials, expressions can be rewritten in a canonical form by expanding them fully. This is done using the .expand() method in SymPy - in your case:
print(bool(z1.expand()==z2.expand()))
or
print((z1-z2).expand())
In first case True will be resulted for equivalent expressions. In second case you will get 0 (zero) if expressions are equivalent. But you will have False and 8x - 8x - 6y + 6y instead.
If you try simplify(), which attempt more advanced transformations, you will get the same result:
print(simplify(z1-z2))
That means that your expressions has same type and 'value', but not mathematically equivalent. See detail here.
When you don't tell equation what symbols to use, it creates its own symbols x and y with assumptions appropriate for a line (i.e. real). When you create a symbol with var the symbols are created with only commutative assumptions. Symbols that have different assumptions do not compare equal.
>>> from sympy import Line, oo
>>> Line((0,0),slope=oo).equation()
x
>>> _._assumptions
{'real': True, 'commutative': True, 'infinite': False, 'extended_real': True,
'hermitian': True, 'complex': True, 'imaginary': False, 'finite': True}
>>> var('x')
x
>>> _._assumptions
{'commutative': True, 'zero': None}
>>> Line((0,0),slope=oo).equation(x) # supply value of x to use
x
>>> _ == x
True
>>> Line((0,0),slope=oo).equation() == x # no default given
False
So...if you want to compare expression built by Line and yourself, use the same symbols (i.e. provide the defaults to Line.equation. Otherwise the hidden assumptions will cause issues.
>>> from sympy.abc import y
>>> Line(Point(-6,0),Point(0,-8)).equation(x,y)
8*x + 6*y + 48
>>> _==8*x + 6*y + 48
True
Sympy's trigonometric functions takes periodic argument into account.
from sympy import pi, sin, Symbol
n = Symbol('n', integer=True)
>>> sin(2*pi + 4)
sin(4)
>>> sin(n*pi)
0
However, it seems that it does not support this feature...
n = Symbol('n', integer=True)
>>> sin(2*n*pi + 4)
sin(2*n*pi + 4) # Expected sin(4)
.simplify() or .doit() was not working. Is there any function or method to convert sin(2*n*pi + 4) to sin(4)?
You could use trigsimp or seemingly clunky expansion and rewriting:
>>> eq = sin(2*n*pi + 4)
>>> eq.rewrite(exp).expand().rewrite(sin).expand()
sin(4)
>>> trigsimp(eq)
sin(4)
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.)
Is there any way to get sympy to perform this integral?
x=var('x')
L=var('L')
Q.positive(1/L)
integrate(besseli(1,x) * exp(-x**2/(4*L)-L),(x,0,inf))
Sympy just returns the integral:
Integral(exp(-L - x**2/(4*L))*besseli(1, x), (x, 0, +inf))
Mathematica does it:
Integrate[BesselI[1, x] Exp[-(x^2/(4 L)) - L], {x, 0, Infinity}]
Result:
ConditionalExpression[1 - E^-L, Re[1/L] > 0]
EDIT: using the answer provided below, a better way to perform this integral is:
L=var('L',real=True,positive=True)
x=var('x',real=True,positive=True)
integrate(besseli(1,x) * exp(-x**2/(4*L)-L),(x,0,oo))
The problem is that you are using inf, which I guess is Float('inf'). You want oo, the symbolic infinity. SymPy should probably be smarter about converting Float('inf') to oo.
In [1]: x=var('x')
In [2]: L=var('L')
In [3]: Q.positive(1/L)
Out[3]: Q.positive(1/L)
In [5]: integrate(besseli(1,x) * exp(-x**2/(4*L)-L),(x,0,oo))
Out[5]:
⎧ ⎛ L ⎞ -L │ ⎛ 1 ⎞│ π
⎪ ⎝ℯ - 1⎠⋅ℯ for │periodic_argument⎜─────────────, ∞⎟│ < ─
⎪ │ ⎝polar_lift(L) ⎠│ 2
⎪
⎪∞
⎪⌠
⎨⎮ 2
⎪⎮ x
⎪⎮ -L - ───
⎪⎮ 4⋅L
⎪⎮ ℯ ⋅besseli(1, x) dx otherwise
⎪⌡
⎩0
The original expression now works in SymPy because inf is automatically recast to oo:
>>> inf=float('inf')
>>> x=var('x')
>>> L=var('L')
>>> Q.positive(1/L)
Q.positive(1/L)
>>> integrate(besseli(1,x) * exp(-x**2/(4*L)-L),(x,0,inf))
Piecewise(
((exp(L) - 1)*exp(-L), Abs(arg(L)) < pi/2),
(Integral(exp(-L - x**2/(4*L))*besseli(1, x), (x, 0, oo)), True))