Is there an easy way to make a function to inverse an algorithm for example like this:
>>> value = inverse("y = 2*x+3")
>>> print(value)
"x = (y-3)/2"
If you can't make actual code for the function, please recommend me tools that would make this task easier. The function would be only used to inverse algorithms with +, -, * and /
You should try SymPy for doing that:
from sympy import solve
from sympy.abc import x, y
e = 2*x+3-y
solve(e,x)
#[y/2 - 3/2]
solve(e,y)
#[2*x + 3]
Based on this, you can build your inverse() like (works for two variables):
def inverse(string, left_string=None):
from sympy import solve, Symbol, sympify
string = '-' + string
e = sympify(string.replace('=','+'))
if left_string:
ans = left_string + ' = ' + str(solve(e, sympify(left_string))[0])
else:
left = sympify(string.split('=')[0].strip().replace('-',''))
symbols = e.free_symbols
symbols.remove( left )
right = list(symbols)[0]
ans = str(right) + ' = ' + str(solve(e, right)[0])
return ans
Examples:
inverse(' x = 4*y/2')
#'y = x/2'
inverse(' y = 100/x + x**2')
#'x = -y/(3*(sqrt(-y**3/27 + 2500) + 50)**(1/3)) - (sqrt(-y**3/27 + 2500) + 50)**(1/3)'
inverse("screeny = (isox+isoy)*29/2.0344827586206895", "isoy")
#'isoy = -isox + 0.0701545778834721*screeny'
This is a little long for a comment, but here's the sort of thing I had in mind:
import sympy
def inverse(s):
terms = [sympy.sympify(term) for term in s.split("=")]
eqn = sympy.Eq(*terms)
var_to_solve_for = min(terms[1].free_symbols)
solns = sympy.solve(eqn, var_to_solve_for)
output_eqs = [sympy.Eq(var_to_solve_for, soln) for soln in solns]
return output_eqs
After which we have
>>> inverse("y = 2*x+3")
[x == y/2 - 3/2]
>>> inverse("x = 100/z + z**2")
[z == -x/(3*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (sqrt(-x**3/27 + 2500) + 50)**(1/3), z == -x/(3*(-1/2 - sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (-1/2 - sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3),
z == -x/(3*(-1/2 + sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (-1/2 + sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)]
etc.
Related
I have a sympy expression I want to put numerical values in after differentiating it. The variables I want to replace are all the x[i], y[i] and R_abs[i] in the last expression and are numpy arrays a la
rx=np.array([-0.357, -0.742, -1.078, 0.206])
But trying subs or replace either doesn't do anything or raises the error that Symbols dont allow indexation for for example e1.subs(x[1],rx[0]). I pretty much went through every iteration I could think of to no avail.
import sympy as sp
r0,ge_x,ge_y,bx,by = sp.symbols('r0,ge_x,ge_y,bx,by', real=True) #Main symbols
i,x,y,R_abs = sp.symbols('i,x,y,R_abs', real=True) #Helper symbols
n=4
s2=sp.Sum((bx+r0*sp.Indexed('x',i)/sp.Indexed('R_abs',i)+ge_x*sp.Indexed('x',i)+ge_y*sp.Indexed('y',i)-sp.Indexed('x',i))**2+(by+r0*sp.Indexed('y',i)/sp.Indexed('R_abs',i)-ge_x*sp.Indexed('y',i)+ge_y*sp.Indexed('x',i)-sp.Indexed('y',i))**2,(i,1,n))
e1=sp.Eq(sp.diff(s2,bx).doit(),0)
With e1 then being
Eq(8*bx + 2*ge_x*x[1] + 2*ge_x*x[2] + 2*ge_x*x[3] + 2*ge_x*x[4] + 2*ge_y*y[1] + 2*ge_y*y[2] + 2*ge_y*y[3] + 2*ge_y*y[4] + 2*r0*x[4]/R_abs[4] + 2*r0*x[3]/R_abs[3] + 2*r0*x[2]/R_abs[2] + 2*r0*x[1]/R_abs[1] - 2*x[1] - 2*x[2] - 2*x[3] - 2*x[4], 0)
In here I would like to replace all the x, y, and R_abs with their numerical values.
I've always struggled with indexing in SymPy. Turns out, making Function instances are way easier than indexing instances of Symbol. It also makes notation simpler.
Also note that by using strings in your expression, I think SymPy makes its own symbols with those same string names but they can't be accessed with yours since your symbols are different. At least that's what happens sometimes to me.
Here is a working sample:
import sympy as sp
r0, ge_x, ge_y, bx, by = sp.symbols("r0 ge_x ge_y bx by", real=True) # main symbols
# define functions that will take the role of indexed symbols
x = sp.Function("x")
y = sp.Function("y")
R_abs = sp.Function("R_abs")
i = sp.Symbol("i", positive=True, integer=True)
n = 4
s2 = sp.Sum((bx + r0 * x(i) / R_abs(i) + ge_x * x(i) + ge_y * y(i) - x(i)) ** 2 +
(by + r0 * y(i) / R_abs(i) - ge_x * y(i) + ge_y * x(i) - y(i)) ** 2, (i, 1, n))
s2_prime = sp.diff(s2, bx).doit().simplify()
print(s2_prime)
# whatever lists you want. Can even be an instance of `np.ndarray`
# note that you summed from 1 to n so the 0th element will not be used
x_array = [0, 1, 2, 3, 4]
y_array = [4, 3, 2, 1, 0]
R_abs_array = [-10, 10, 5, 4, 3]
# define a function to access these array elements
x_function = lambda index: x_array[index]
y_function = lambda index: y_array[index]
R_abs_function = lambda index: R_abs_array[index]
# no idea why subs does not work and you MUST keep the same name for the variable.
# you can't have for example `evaluated_s2_prime = ...`.
# Probably something to do with forcing sp to remove references to `x`?
s2_prime = s2_prime.replace(x, x_function).replace(y, y_function).replace(R_abs, R_abs_function)
print(s2_prime)
Producing:
8*bx + 2*ge_x*x(1) + 2*ge_x*x(2) + 2*ge_x*x(3) + 2*ge_x*x(4) + 2*ge_y*y(1) + 2*ge_y*y(2) + 2*ge_y*y(3) + 2*ge_y*y(4) + 2*r0*x(4)/R_abs(4) + 2*r0*x(3)/R_abs(3) + 2*r0*x(2)/R_abs(2) + 2*r0*x(1)/R_abs(1) - 2*x(1) - 2*x(2) - 2*x(3) - 2*x(4)
8*bx + 20*ge_x + 12*ge_y + 31*r0/6 - 20
When the following code is run Derivative(Ksi(uix, uiy), uix)) and Derivative(Ksi(uix, uiy), uiy)) terms appear:
In [4]: dgN
Out[4]:
Matrix([
[-(x1x - x2x)*(-x1y + x2y)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)*Derivative(Ksi(uix, uiy), uix) + (-x1y + x2y)*(-(-x1x + x2x)*Derivative(Ksi(uix, uiy), uix) + 1)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)],
[-(-x1x + x2x)*(-x1y + x2y)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)*Derivative(Ksi(uix, uiy), uiy) + (x1x - x2x)*(-(-x1y + x2y)*Derivative(Ksi(uix, uiy), uiy) + 1)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)]])
I would like to replace this Derivative terms by, let's say, the symbolic expression of the derivative of a function that I know for example, I would like to set Derivative(Ksi(uix,uiy), uix) = 2 * uix.
Is there a neat way to do this substitution and to get a symbolic expression for dgN with Derivative(Ksi(uix,uiy), uix) set to 2 * uix? Here is my code:
import sympy as sp
sp.var("kPenN, Xix, Xiy, uix, uiy, Alpha, x1x, x1y, x2x, x2y, x3x, x3y ", real = True)
Ksi = sp.Function('Ksi')(uix,uiy)
Xi = sp.Matrix([Xix, Xiy])
ui = sp.Matrix([uix, uiy])
xix = Xix + uix
xiy = Xiy + uiy
xi = sp.Matrix([xix, xiy])
x1 = sp.Matrix([x1x, x1y])
x2 = sp.Matrix([x2x, x2y])
N = sp.Matrix([x2 - x1, sp.zeros(1)]).cross(sp.Matrix([sp.zeros(2,1) , sp.ones(1)]))
N = sp.Matrix(2,1, sp.flatten(N[0:2]))
N = N / (N.dot(N))**(0.5)
xp = x1 + (x2 - x1)*Ksi
# make it scalar (in agreement with 9.231)
gN = (xi - xp).dot(N)
dgN = sp.Matrix([gN.diff(uix), gN.diff(uiy)])
The substitution you want can be achieved with
dgN_subbed = dgN.subs(sp.Derivative(Ksi, uix), 2*uix)
Here Ksi is without arguments (uix,uiy) since those were already declared when Ksi was created.
The syntax would be a little more intuitive if you defined Ksi as Ksi = sp.Function('Ksi'), leaving the arguments -- whatever they may be -- to be supplied later. Then sp.Derivative(Ksi(uix, uiy), uix) would be the way to reference the derivative.
In order to calculate derivatives and other expressions I used the sympy package and said that T = sy.Symbol('T') now that I have calculated the right expression:
E= -T**2*F_deriv_T(T,rho)
where
def F_deriv_rho(T,rho):
ret = 0
for n in range(5):
for m in range(4):
inner= c[n,m]*g_rho_deriv_rho_np*g_T_np
ret += inner
return ret
that looks like this:
F_deriv_rho: [0.0 7.76971e-5*T 0.0001553942*T**2*rho
T*(-5.14488e-5*log(rho) - 5.14488e-5)*log(T) + T*(1.22574e-5*log(rho)+1.22574e-5)*log(T) + T*(1.89488e-5*log(rho) + 1.89488e-5)*log(T) + T(2.29441e-5*log(rho) + 2.29441e-5)*log(T) + T*(7.49956e-5*log(rho) + 7.49956e-5)*log(T)
T**2*(-0.0001028976*rho*log(rho) - 5.14488e-5*rho)*log(T) + T**2*(2.45148e-5*rho*log(rho) + 1.22574e-5*rho)*log(T) + T**2*(3.78976e-5*rho*log(rho) + 1.89488e-5*rho)*log(T) + T**2*(4.58882e-5*rho*log(rho) + 2.29441e-5*rho)*log(T) + T**2*(0.0001499912*rho*log(rho) + 7.49956e 5*rho)*log(T)]
with python I would like to change T (and rho) as a symbol to a value. How could I do that?
So, I would like to create 10 numbers like T_def = np.arange(2000, 10000, 800)and exchange all my sy.symbol(T) by iterating through the 10 values I created in the array.
Thanks for your help
I have found the solution according to this post:
How to substitute multiple symbols in an expression in sympy?
by usings "subs":
>>> from sympy import Symbol
>>> x, y = Symbol('x y')
>>> f = x + y
>>> f.subs({x:10, y: 20})
>>> f
30
There's more for this kinda thing here: http://docs.sympy.org/latest/tutorial/basic_operations.html
EDIT: A faster way would be by using "lamdify" as suggested by #Bjoern Dahlgren
I'm trying to convert a function from Matlab to Python. The Matlab function is:
function [f,df_dr1,df_dr2,g,dg_dr1,dg_dr2] = f_eval_2eq(r1,r2,r3,z1,z2,z3,n1,n2,n3)
f = (r1)./sqrt(r1.^2 + z1.^2)...
- (n2/n1)*(r2-r1)./sqrt((r2-r1).^2 + z2.^2);
df_dr1 = 1./sqrt(r1.^2 + z1.^2)...
- r1.^2./(r1.^2 + z1.^2).^(3/2)...
+ (n2/n1)./sqrt(z2.^2 + (r1-r2).^2)...
- (n2/n1).*(r1-r2).*(2*r1-2*r2)./(2*((r1-r2).^2 + z2.^2).^(3/2));
df_dr2 = (n2/n1).*(r1-r2).*(2*r1-2*r2)./(2*((r1-r2).^2 + z2.^2).^(3/2))...
- (n2/n1)./sqrt(z2.^2 + (r1-r2).^2);
g = (r2-r1)./sqrt((r2-r1).^2 + z2.^2)...
- (n3/n2)*(r3-r2)./sqrt((r3-r2).^2 + z3.^2);
dg_dr1 = (r1-r2).*(2*r1-2*r2)./(2*((r1-r2).^2 + z2.^2).^(3/2))...
- 1./sqrt(z2.^2 + (r1-r2).^2);
dg_dr2 = 1./sqrt((r1-r2).^2 + z2.^2)...
+ (n3/n2)./sqrt(z3.^2 + (r2-r3).^2)...
- (r1-r2).*(2*r1-2*r2)./(2*((r1-r2).^2 + z2.^2).^(3/2))...
- (n3/n2).*(r2-r3).*(2*r2-2*r3)./(2*((r2-r3).^2 + z3.^2).^(3/2));
end
%test code
K>> a=[1,2,3];b=a+1;c=b+1;d=a;e=b;f=c;g=1;h=2;i=3;
K>> [f,df_dr1,df_dr2,g,dg_dr1,dg_dr2] = f_eval_2eq(a,b,c,d,e,f,g,h,i)
The Python function I wrote is:
def f_eval_2eq(r1,r2,r3,z1,z2,z3,n1,n2,n3):
#evaluate gradients
#n_ are scalars
f = (r1)/np.sqrt(r1**2 + z1**2) \
- (n2/n1)*(r2-r1)/np.sqrt((r2-r1)**2 + z2**2);
df_dr1 = 1/np.sqrt(r1**2 + z1**2) \
- r1**2/((r1**2 + z1**2)**(3/2)) \
+ (n2/n1)/np.sqrt(z2**2 + (r1-r2)**2) \
- (n2/n1)*(r1-r2)*(2*r1-2*r2)/(2*((r1-r2)**2 + z2**2)**(3/2));
df_dr2 = (n2/n1)*(r1-r2)*(2*r1-2*r2)/(2*((r1-r2)**2 + z2**2)**(3/2)) \
- (n2/n1)/np.sqrt(z2**2 + (r1-r2)**2);
g = (r2-r1)/np.sqrt((r2-r1)**2 + z2**2) \
- (n3/n2)*(r3-r2)/np.sqrt((r3-r2)**2 + z3**2);
dg_dr1 = (r1-r2)*(2*r1-2*r2)/(2*((r1-r2)**2 + z2**2)**(3/2)) \
- 1/np.sqrt(z2**2 + (r1-r2)**2);
dg_dr2 = 1/np.sqrt((r1-r2)**2 + z2**2) \
+ (n3/n2)/np.sqrt(z3**2 + (r2-r3)**2) \
- (r1-r2)*(2*r1-2*r2)/(2*((r1-r2)**2 + z2**2)**(3/2)) \
- (n3/n2)*(r2-r3)*(2*r2-2*r3)/(2*((r2-r3)**2 + z3**2)**(3/2));
return (f,df_dr1,df_dr2,g,dg_dr1,dg_dr2)
#test code
A=np.array([1,2,3])
B=A+1
C=B+1
D=A
E=B
F=C
G=1
H=2
I=3
[f,df_dr1,df_dr2,g,dg_dr1,dg_dr2] =f_eval_2eq(A,B,C,D,E,F,G,H,I)
print ('f= '+str(f) +'\n'+'df_dr1= '+str(df_dr1) +'\n' +'df_dr2='+str(df_dr2) +'\n'+'g= '+str(g) +'\n'+'dg_dr1= '+str(dg_dr1) +'\n'+'dg_dr2= '+str(dg_dr2) +'\n')
The output for f is the same in both, but all the other values are different and I cant figure out why???
Any help is appreciated.
In Python 2.x, if you divide two integers (such as 2 and 3) the result is cast as an integer as well:
x = 3/2
# 1
type(x)
# <type 'int'>
You need to explicitly specify either the numerator or denominator to be a float rather than an integer using a decimal point and this will allow the output to be a float as well.
y = 3./2
# 1.5
type(y)
# <type 'float'>
Alternately, as suggested by #rayryeng, you can place the following at the top of your code to get the behavior you expect.
from __future__ import division
You can also add
from __future__ import division
to the top of your file, if you're using Python 2, in order to get the Python 3 behavior, i.e. always using float division.
I have an equation like:
R₂⋅V₁ + R₃⋅V₁ - R₃⋅V₂
i₁ = ─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
defined and I'd like to split it into factors that include only single variable - in this case V1 and V2.
So as a result I'd expect
-R₃ (R₂ + R₃)
i₁ = V₂⋅───────────────────── + V₁⋅─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃ R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
But the best I could get so far is
-R₃⋅V₂ + V₁⋅(R₂ + R₃)
i₁ = ─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
using equation.factor(V1,V2). Is there some other option to factor or another method to separate the variables even further?
If it was possible to exclude something from the factor algorithm (the denominator in this case) it would have been easy. I don't know a way to do this, so here is a manual solution:
In [1]: a
Out[1]:
r₁⋅v₁ + r₂⋅v₂ + r₃⋅v₂
─────────────────────
r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃
In [2]: b,c = factor(a,v2).as_numer_denom()
In [3]: b.args[0]/c + b.args[1]/c
Out[3]:
r₁⋅v₁ v₂⋅(r₂ + r₃)
───────────────────── + ─────────────────────
r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃ r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃
You may also look at the evaluate=False options in Add and Mul, to build those expressions manually. I don't know of a nice general solution.
In[3] can be a list comprehension if you have many terms.
You may also check if it is possible to treat this as multivariate polynomial in v1 and v2. It may give a better solution.
Here I have sympy 0.7.2 installed and the sympy.collect() works for this purpose:
import sympy
i1 = (r2*v1 + r3*v1 - r3*v2)/(r1*r2 + r1*r3 + r2*r3)
sympy.pretty_print(sympy.collect(i1, (v1, v2)))
# -r3*v2 + v1*(r2 + r3)
# ---------------------
# r1*r2 + r1*r3 + r2*r3