Is there a way to use sympy to find/replace all standalone integers (that aren't exponents) to 1.
For example, converting the following:
F(x) = (2/x^2) + (3/x^3) + 4
To:
F(x) = (1/x^2) + (1/x^3) + 1
I've searched extensively on stackoverflow for sympy expression.match/replace/find solutions, and have tried using a Wildcard symbol to find and replace all numbers in the expression but I keep running into the issue of matching and replacing the exponents (2 and 3 in this example) as well as they are also considered numbers.
Is there a simple (pythonic) way to achieve the above?
Thanks!
setdefault used with replace is a nice way to go. The single expression below has 3 steps:
mask off powers and record
change Rationals to 1 (to handle integers in numer or denom)
restore powers
>>> from sympy.abc import x
>>> from sympy import Dummy
>>> eq = (2/x**2) + (3/x**3) + 4 + 1/x/8
>>> reps = {}
>>> eq = eq.replace(lambda x: x.is_Pow, lambda x: reps.setdefault(x, Dummy())
).replace(lambda x: x.is_Rational, lambda x: 1
).xreplace({v:k for k,v in reps.items()})
1 + 1/x + 1/x**2 + 1/x**3
You can write a function that will recurse into your expression. For any expression expr, expr.args will give you the components of that expression. expr.is_constant() will tell you if it's a constant. expr.is_Pow will tell you if it's an exponential expression, so you can choose not to drill down into these expressions.
import sympy
def get_constants(expr):
c = set()
for x in expr.args:
if x.is_constant(): c |= {x}
if not x.is_Pow:
c |= get_constants(x)
return c
Now, you can get all the constants in said expression, and replace each of these constants using expr.replace().
def replace_constants(expr, repl):
for const in get_constants(expr):
expr = expr.replace(const, repl)
return expr
With your example expression, we get:
x = sympy.symbols('x')
F = 2/x**2 + 3/x**3 + 4
G = replace_constants(F, 1)
print(F) # 4 + 2/x**2 + 3/x**3
print(G) # 1 + x**(-2) + x**(-3)
In the code below, I define real Symbols to take the limit in sympy then use subs to get the numeric result.
#To take the limit with unknown values, I have to define real symbols
from sympy import *
x = symbols("x")
H = symbols("H")
p = symbols("p")
#-----
# Position_1
#-----
dict = {H: 5,p:3,x:1}
### Some operations
H = Symbol("H", real = True, positive = True )
p = Symbol("p", real = True, positive = True )
h = (H*p + (1 - p)**H - 1)/(H*p)
dh = limit(h,p,1,'+')
#
g = H*x**2 + h
poly = Poly(g,x)
print("poly",poly)
#-----
# Position_2
#-----
dict = {H: 5,p:3,x:1}
Numeric_result = poly.subs(dict)
print("Numeric_result = " ,Numeric_result )
the output is :
Numeric_result = H*x**2 + 1 + (1 - p)**H/(H*p) - 1/(H*p)
While it should substitute H and p,x
Numeric_result = 3.8
I think the problem is that sympy defines symbols globally therefore can not substitute them.
I tried the following solutions but didn't work.
changing assumptions to remove real symbol and compute g [Sympy_ assumption] [1]: https://docs.sympy.org/latest/modules/assumptions/assume.html
and also right before computing g
H = Symbol("H", real = False, complex= True)
When doing subs make the keys the symbols you are trying to replace. It won't matter if your Symbols are "vanilla" type with no assumptions, but in your case you have assumptions. This works on your example:
>>> dict = {H: 5, p:3, x:1}
>>> poly.subs(dict)
19/5
I'm looking to dot two vectors or symbols in sympy so that the (latex) output is similar to what the code below would display, but with an actual sympy function e.g. RA.dot(RB)... How would I go about doing this?
from sympy import *
from sympy.interactive import printing
printing.init_printing(use_latex = True)
RA = Symbol('\mathbf{R}_A', commutative = False)
RB = Symbol('\mathbf{R}_B', commutative = False)
dt = Symbol('\cdot', commutative = False)
display(RA*dt*RB)
# I would prefer something like
display(RA.dot(RB)) # If RA and RB are type Vector, VectorAdd etc.
It's simple. Use this:
A = MatrixSymbol('\mathbf{R}_A', 1, 1)
B = MatrixSymbol('\mathbf{R}_B', 1, 1)
dt = MatrixSymbol('\cdot',1,1)
A*dt*B
Or just:
A = MatrixSymbol('\mathbf{R}_A', 1, 1)
B = MatrixSymbol('\mathbf{R}_B', 1, 1)
A*B
So a solution to the problem for LaTeX output is this:
from sympy import *
from sympy.interactive import printing
printing.init_printing(use_latex = True)
A, B, dt = symbols('A B \cdot', commutative = False)
display(A*dt*B)
However, functions like simplify(), expand(), factor() do not work so well with non-commutative symbols so if you want to do any math I recommend the following code:
expr = A*dt*B
l = [i for i in expr.atoms()]
nl = [Symbol(str(i)) for i in l]
for i in range(len(l)):
expr = expr.subs(l[i],nl[i])
### Perform your maths now that everything is commutative, then revert back to non-comm
You can declare it also for commutative symbols. Just make the dot a standalone non-commutative symbol and disable product simplification.
import sympy as sm
a,b,c= sm.symbols('a b c')
dt = sm.Symbol('\cdot ',commutative=False)
sm.Mul(a,dt,b,dt,c,evaluate=False)
i am trying to solve a matrix that has 6x6 matrices as it's entries(elements)
i tried multiplying the inverse of gen to the solution matrix, but i don't trust the correctness of the answer am getting.
from sympy import Eq, solve_linear_system, Matrix,count_ops,Mul,horner
import sympy as sp
a, b, c, d, e,f = sp.symbols('a b c d e f')
ad = Matrix(([43.4,26.5,115,-40.5,52.4,0.921],
[3.78,62.9,127,-67.6,110,4.80],
[41.25,75.0,213,-88.9, 131, 5.88],
[-10.6,-68.4,-120,64.6,-132,-8.49],
[6.5,74.3,121,-72.8,179,29.7],
[1.2,30.7,49.7,-28.7,91,29.9]))
fb= Matrix(([1,0,0,0,0,0],
[0,1,0,0,0,0],
[0,0,1,0,0,0],
[0,0,0,1,0,0],
[0,0,0,0,1,0],
[0,0,0,0,0,1]))
ab = Matrix(([-0.0057],
[0.0006],
[-0.0037],
[0.0009],
[0.0025],
[0.0042]))
az = sp.symbols('az')
bz = sp.symbols('bz')
fz = sp.symbols('fz')
gen = Matrix(([az, fz, 0, 0, 0, 0,bz],
[fz,az,fz,0,0,0,bz],
[0,fz,az,fz,0,0,bz],
[0,0,fz,az,fz,0,bz],
[0,0,0,fz,az,fz,bz],
[0,0,0,0,fz,az,bz]))
answer = solve_linear_system(gen,a,b,c,d,e,f)
first_solution = answer[a]
df = count_ops(first_solution)
print(df,first_solution)
disolved = zip(first_solution.simplify().as_numer_denom(),(1,-1))
dft = Mul(*[horner(b)**e for b,e in disolved])
dff = count_ops(dft)
print(dff,dft)
_1st_solution = dft.subs({az:ad,fz:fb,bz:ab},simultaneous = True).doit()
print(_1st_solution)
when i ran my code it raised sympy.matrices.common.ShapeError
You have to be careful when using horner with expressions containing commutative symbols that are actually noncommutative (in your case because they represent matrices). Your dft expression is
(az**2*bz - bz*fz**2)/(az*(az*(az + fz) - 2*fz**2) - fz**3)
but should maybe be
(az**2 - fz**2)*(az*(az*(az + fz) - 2*fz**2) - fz**3)**(-1)*bz
You would have received a correct expression if you had created the symbols as noncommutative (as shown below).
But you can't use horner with non-commutative symbols, so I just rearranged the expression by hand; you will have to check to see that the ordering is right. As an alternative to doing the factoring by hand you might also try using factor_nc to help you -- but it won't handle horner like expression factoring:
>>> ax, bz, fz = symbols('az bz fz, commutative=False)
>>> (az**2*bz - fz**2*bz)
az**2*bz - fz**2*bz
>>> factor_nc(_)
(az**2 - fz**2)*bz
I am using sympy to process some equations. I want to write the equations in a canonical form such that variables of interest are all on LHS. For eg. if I have,
lhs = sympify("e*x +f")`
rhs = sympify("g*y + t*x +h")`
eq = Eq(lhs,rhs)
e*x + f == g*y + h + t*x
I need a function which can isolate a list of given variables (my so called canonical form), like
IsolateVariablesToLHS(eq,[x,y]) # desired function
(e-t)*x - g*y == h-f # now x and y are on LHS and remaining are on RHS
I have the assurance that I will only get linear equations, so this is always possible.
>>> import sympy as sm
>>> lhs = sm.sympify('e*x + f')
>>> rhs = sm.sympify('g*y + t*x + h')
>>> eq = sm.Eq(lhs, rhs)
Here's a simple construct
def isolateVariablesToLHS(eq, syms):
l = sm.S.Zero
eq = eq.args[0] - eq.args[1]
for e in syms:
ind = eq.as_independent(e)[1]
l += ind
eq -= ind
return sm.Eq(l, eq)
>>> isolateVariablesToLHS(eq, [x, y])
Eq(e*x - g*y - t*x, f - h)
With the equation as provided in the question combine all the terms and construct a filter for discovering the required variables.
>>> from itertools import filterfalse
>>> terms = eq.lhs - eq.rhs
>>> vars = ['x', 'y']
>>> filt = lambda t: any(t.has(v) for v in vars)
>>> result = Eq(sum(filter(filt, terms.args)), - sum(filterfalse(filt, terms.args))
>>> result
e*x - g*y - t*x == -f + h
I'm not familiar with sympy but I think this will work for equations consisting of proper atoms such as Symbols. Make sure you replace the vars list with the actual instantiated Symbols x, y instead of the 'ascii' representations. This is probably required to combine terms that have variables in common.
filter and filterfalse might have different names in python 2.x, but this functionality is probably still in the itertools package.