I want diophantine convert t_0 ---> n - sympy

I want diophantine convert (t_0 ---> n)
from sympy import *
var('x y t_0 n')
def myDiophantine(myf):
myf_diox = list(diophantine(myf))[0][0]
myf_dioy = list(diophantine(myf))[0][1]
print("#1#",type(myf_diox),myf_diox)
myf_diox = myf_diox.subs({t_0:n})
print("#2#",type(myf_diox),myf_diox)
return myf_diox,myf_dioy
myf=5**4*x-2**4*y-1
print("#3#",myDiophantine(myf))
var('z')
print("#4#",type(myf),myf)
print("#5#",type(myf.subs({x:z})),myf.subs({x:z}))
#1# <class 'sympy.core.add.Add'> 16*t_0 + 1
#2# <class 'sympy.core.add.Add'> 16*t_0 + 1
#3# (16*t_0 + 1, 625*t_0 + 39)
#4# <class 'sympy.core.add.Add'> 625*x - 16*y - 1
#5# <class 'sympy.core.add.Add'> -16*y + 625*z - 1
i used subs? It could not be replaced.
Is there a better way?
i want
#2# <class 'sympy.core.add.Add'> 16*n + 1
ref
I want function convert from xy to cells
20220401
from sympy import *
var('x y t_0 n')
def myDiophantine(myf):
d=diophantine(myf)
params = Tuple(*d).free_symbols - myf.free_symbols;
d=Tuple(*d).xreplace(dict(zip(params, [n])))
myf_diox = list(d)[0][0]
myf_dioy = list(d)[0][1]
return myf_diox,myf_dioy
myf=5**4*x-2**4*y-1
myg=myDiophantine(myf)
print("#",myg[0],myg[1])
# 16*n + 1 625*n + 39
https://www.wolframalpha.com/input?i=5%5E4*x-2%5E4*y%3D1
5^4x-2^4y=1
Integer solution
x = 16 n + 1, y = 625 n + 39, n element Z

>>> myf = 5**4*x-2**4*y-1
>>> d = diophantine(myf)
Get a list of parameters that were used for the solution (converting set-of-tuples solution to Tuple-of-Tuples):
>>> params = Tuple(*d).free_symbols - myf.free_symbols; params
{t_0}
Create a replacement dictionary with desired replacements
>>> Tuple(*d).xreplace(dict(zip(params, [n])))
((16*n + 1, 625*n + 39),)
Why didn't your approach work?
>>> Symbol('t_0') in params
False
>>> Symbol('t_0',integer=True) in params
True
Symbols are matched based on name and assumptions, not name alone.
As to getting smaller coefficients for Diophantine equations: this is a known issue.

Related

Substitute compound expression in SymPy

In sympy how can I make a substitution of a compound expression for a single variable as in the following example that only works for one of the instances of the common factor?
from sympy import *
x, y, z = symbols('x y z')
eq = Eq(2*(x+y) + 3*(x+y)**2, 0)
print(eq)
eq1 = Eq(z, x+y)
print(eq1)
eq2 = eq.subs(eq1.rhs, eq1.lhs)
print(eq2)
Output
Eq(2*x + 2*y + 3*(x + y)**2, 0)
Eq(z, x + y)
Eq(2*x + 2*y + 3*z**2, 0)
Desired output for last line
Eq(2*z + 3*z**2, 0)
Thanks to Oscar Benjamin's comment. I've solved the case I was actually interested in:
from sympy import *
t, L, C0, R, a, w0, h = symbols('t L C_0 R alpha omega_0 h')
Q = Function('Q')
ex0 = L*Q(t).diff(t, t) + R*Q(t).diff(t) + Q(t)*(1/(C0/(1+h*cos(a*t))))
print(ex0)
ex1 = ex0/L
ex1 = ex1.collect(Q(t)).expand()
print(ex1)
# substitute the following compound expression
ex2 = Eq(w0*w0, 1/(L*C0))
print(ex2)
ex3 = ex1.subs(L*C0, 1/(w0*w0))
ex4 = ex3.collect(Q(t))
print(ex4)
Output:
L*Derivative(Q(t), (t, 2)) + R*Derivative(Q(t), t) + (h*cos(alpha*t) + 1)*Q(t)/C_0
Derivative(Q(t), (t, 2)) + R*Derivative(Q(t), t)/L + h*Q(t)*cos(alpha*t)/(C_0*L) + Q(t)/(C_0*L)
Eq(omega_0**2, 1/(C_0*L))
(h*omega_0**2*cos(alpha*t) + omega_0**2)*Q(t) + Derivative(Q(t), (t, 2)) + R*Derivative(Q(t), t)/L
The substitution fails because subs does not encounter any argument x + y in the (sub)expression 2*(x + y): that expression automatically expands to 2*x + 2*y. So one solution is to do as Oscar suggested: make an algebraic substitution. I often follow this up with a restoration step to handle anything that didn't change as I expected. The other thing you can do is to use a helper function that groups together terms that are in the multi-term old object that you desire to replace:
def mvsubs(eq, old, new):
from sympy.core.exprtools import factor_terms
if not old.is_Add:
return eq.subs(old, new)
Add = old.func
free = old.free_symbols
for i in eq.atoms(Add):
reps = {}
for i in i.args:
if not all(i.has(x) for x in free):
reps.setdefault(i, Dummy())
eq = eq.subs(reps).subs(Add(*reps.values()),
factor_terms(Add(*reps.keys()))).subs(
old, new).xreplace({v:k for k,v in reps.items()})
return eq
>>> mvsubs(eq, x+y, z)
Eq(3*z**2 + 2*z, 0)

How could I generate random coefficients for polynomials using Sum( f(x), (x,0,b) )?

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 tensorproduct and tensorcontraction

I want to do two computations with sympy and one substitution:
The first is: "E:E" or in index notation "E_{ij}E{ji}"
The second is: "T_{ijmn} T_{mnkl}"
After I do these calculations I would like to replace the symbols with numeric values.
I have the following code:
import sympy as sp
import numpy as np
sp.init_printing(pretty_print=False)
# e = sp.MatrixSymbol('e',3,3)
# E = sp.Matrix(e)
def foo():
e = sp.MatrixSymbol('e',3,3)
E = sp.Matrix(e)
result1 = sp.tensorcontraction( sp.tensorproduct(E, E), (0, 2), (1,3))
T = sp.tensorproduct(E, E)
result2 = sp.tensorcontraction( sp.tensorproduct(T, T), (2,4), (3,5))
return [result1, result2]
# Verification
res1, res2 = foo()
E_num = np.array([[1,2,3],
[4,5,6],
[7,8,12]])
res1 = res1.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
res2 = res2.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
check1 = np.einsum("ij,ji", E_num, E_num) - res1
T1 = np.einsum("ij,mn->ijmn", E_num, E_num)
T2 = np.einsum("mn,kl->mnkl", E_num, E_num)
check2 = np.einsum("ijmn,mnkl->ijkl", T1,T2) - res2
In the above code I cannot replace the E matrix with numerical values as the symbolic variable is defined inside the function. I can do it if I define them outside. Any way to look into the expression and get the symbols to replace?
Additionally, check1 is not zero as it appears to be doing E_{ij}E_{ij}, whilst check2 appears to be correct. Am I not asking to contract the correct indices?
Best Regards
Your res1 - before numeric substitute is
In [18]: res1
Out[18]:
2 2 2 2 2 2 2 2 2
e₀₀ + e₀₁ + e₀₂ + e₁₀ + e₁₁ + e₁₂ + e₂₀ + e₂₁ + e₂₂
That's the same as
np.einsum('ij,ij', E_num, E_num)
or
np.sum(E_num * E_num)
The einsum contraction of the array with its transpose:
In [18]: np.einsum("ij,ji", E_num, E_num)
Out[18]: 324
In [19]: np.einsum("ij,ij", E_num, E_num.T)
Out[19]: 324
Using E.T in your res1 calcultion gets the same thing
In [24]: sp.tensorcontraction( sp.tensorproduct(E, E.T), (0, 2), (1,3))
Out[24]:
2 2 2
e₀₀ + 2⋅e₀₁⋅e₁₀ + 2⋅e₀₂⋅e₂₀ + e₁₁ + 2⋅e₁₂⋅e₂₁ + e₂₂
In [25]: _.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
...: E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
...: E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
Out[25]: 324
I haven't read the docs for tensorproduct or tensorcontraction.

Sympy : How is it possible to simplify power of sum?

Considering an expression of this form:
x,y,n=sp.symbols("x y n",positive=True,real=True)
sp.Pow(x+y+x**2,n+1)*sp.Pow(x+2*y+4*y**3,-n-1)
how is it possible to simplify it to have a common power ?
(i.e. sp.Pow((x+y+x**2)/(x+2*y+y**3),n+1) )
This is the same general problem as here
>>> var('z', positiv=True)
z
>>> expr = sp.Pow(x+y+x**2,n+1)*sp.Pow(x+2*y+4*y**3,-n-1)
>>> powsimp(expr.subs(n + 1, var('z',positive=1))).subs(z, n + 1)
((x**2 + x + y)/(x + 4*y**3 + 2*y))**(n + 1)

Collecting sub-expressions of a multivariate polynomial function in Sympy

I have a degree 6 multivariate equation in x and y written in Sympy, e.g.
eqn = a*x**6 + b*x**5*y + c*x**4*y + d*x**3*y + e*x**3*y**2 + ...
Is there a way to collect (x**2+y**2) and rearrange them into the following format?
eqn2 = A*(x**2+y**2)**3 + B*(x**2+y**2)**2 + C*(x**2+y**2) + D
A, B, C, D can be in x, y.
So far I have only tried collect(eqn, x**2 + y**2) and it returned the original equation.
Thank you!
Consider using a temporary symbol z = x**2 + y**2 and replace x**2 with z - y**2, then expand and restore:
>>> ex
A*x**6 + 3*A*x**4*y**2 + 3*A*x**2*y**4 + A*y**6 + B*x**4 + 2*B*x**2*y**2 +
B*y**4 + C*x**2 + C*y**2 + D
>>> ex.subs(x**2, z - y**2).expand().subs(z, x**2 + y**2)
A*(x**2 + y**2)**3 + B*(x**2 + y**2)**2 + C*(x**2 + y**2) + D
Although that works, perhaps a more direct thing to do is separate the expression by coefficients A-D and then factor those collections of terms:
def separatevars_additively(expr, symbols=[]):
free = set(symbols) or expr.free_symbols
d = {}
while free:
f = free.pop()
expr, dep = expr.as_independent(f, as_Add=True)
if dep.has(*free):
return None
d[f] = dep
if expr:
d[0] = expr
return d
>>> coeff = var("A:D")
>>> separatevars_additively(ex, coeff)
{B: B*x**4 + 2*B*x**2*y**2 + B*y**4, A: A*x**6 + 3*A*x**4*y**2 + 3*A*x**2*y**4 + A*y**6, D: D, C: C*x**2 + C*y**2}
>>> Add(*[factor(i) for i in _.values()])
A*(x**2 + y**2)**3 + B*(x**2 + y**2)**2 + C*(x**2 + y**2) + D