For instance, I want to expand the following simultaneous equations in first order difference with respect to x, y and z1:
$$x^\alpha y^(1-\alpha) = z_1$$
$$x^\beta y^(1-\beta) = z_2$$
It is obviously that
$$\alpha \hat{x} + (1-\alpha) \hat{y} = \hat{z_1}$$
$$\beta \hat{x} + (1-\beta) \hat{y} = 0$$
where $\hat{variable}$ means the elasticity of the variable, namely, $\frac{d varibale}{variable}$.
We have:
$$\hat{x} = \frac{1-\beta}{\alpha - \beta} \hat{z_1}$$
$$\hat{y} = -\frac{\beta}{\alpha - \beta} \hat{z_1}$$
The corresponding code for python using SymPy will be:
import sympy as sp
x,y,z1,z2,alpha,beta = sp.symbols('x,y,z_1,z_2,alpha,beta',positive=True)
eq1 = x**alpha*y**(1-alpha) - z1
eq2 = x**beta*y**(1-beta) - z2
hat_x,hat_y,hat_z1 = sp.symbols('\hat{x},\hat{y},\hat{z_1})
diff_eq1 = eq1.diff(x)*hat_x*x + eq1.diff(y)*hat_y*y + eq1.diff(z1)*hat_z1*z1
diff_eq2 = eq2.diff(x)*hat_x*x + eq2.diff(y)*hat_y*y + eq2.diff(z1)*hat_z1*z1
root = sp.solve([diff_eq1,diff_eq2],[hat_x,hat_y])
which gives the result
As you can see, the expression is right, but without further simplification. The reason is that it does not take the advantage of eq1 = 0 and eq2 = 0. My question is, how to make further simplifications using the information given by the original equations? Thanks!!
BTW, how can I declare variables with ranges? For instance, I want to declare $\alpha \in (0,1)$ and the $1-\alpha$ will also be positive and facilitate the following manipulation.
My question is, how to make further simplifications using the information given by the original equations?
In general, the solution to a simultaneous equation will not have one side of the equation in the solution. So I can only answer your question in this specific case. root is a dictionary and we will loop through all the values and substitute the RHS of the equations with the LHS.
import sympy as sp
x,y,z1,z2,alpha,beta = sp.symbols('x,y,z_1,z_2,alpha,beta',positive=True)
eq1 = x**alpha*y**(1-alpha) - z1
eq2 = x**beta*y**(1-beta) - z2
hat_x,hat_y,hat_z1 = sp.symbols('\hat{x},\hat{y},\hat{z_1}')
diff_eq1 = eq1.diff(x)*hat_x*x + eq1.diff(y)*hat_y*y + eq1.diff(z1)*hat_z1*z1
diff_eq2 = eq2.diff(x)*hat_x*x + eq2.diff(y)*hat_y*y + eq2.diff(z1)*hat_z1*z1
root = sp.solve([diff_eq1,diff_eq2],[hat_x,hat_y])
for key, value in root.items():
root[key] = value.subs({z1: x**alpha*y**(1-alpha), z2: x**beta*y**(1-beta)}).simplify()
BTW, how can I declare variables with ranges? For instance, I want to declare $\alpha \in (0,1)$ and the $1-\alpha$ will also be positive and facilitate the following manipulation.
There is no explicit way to do so in SymPy. There are a few work-arounds. See this Stack Overflow question.
Related
Here is my prompt: Use sympy to determine a set of solutions. For each set of solutions, provide at least two examples of solutions when there is more than one possible.
x,y,z = sy.symbols('x y z')
eq1 = sy.Eq(3*x + 4*y + z, x)
eq2 = sy.Eq(9*x + y - 4*(z**2),0)
result = sy.solve([eq1,eq2],(x,y,z))
print(result)
This code works, however I am struggling to figure out how to show the example solutions for the code. I can't use any assert claims since I'm not working with callable function, so I struggling to figure this part out.
The tutorial at the link below seems to be saying that all the solutions will print out when there is more than one. https://reliability.readthedocs.io/en/latest/Solving%20simultaneous%20equations%20with%20sympy.html
For example, this code prints out 6 results:
import sympy as sym
x,y,z = sym.symbols('x,y,z')
c1 = sym.Symbol('c1')
eq1 = sym.Eq(2*x**2+y+z,1)
eq2 = sym.Eq(x+2*y+z,c1)
eq3 = sym.Eq(-2*x+y,-z)
result = sym.solve([eq1,eq2,eq3],(x,y,z))
print(result)
I have a set of 4 simultaneous equations:
0.059z = x
0.06w = y
z+w = 8093
x+y = 422
All the solutions I've found so far seem to be for equations that have all the variables present in each equation, then convert to matrices and use the solve function.
Is there an easier way to do this in R or Python using the equations in their original form?
Also, how can I ensure that only positive numbers are returned in the solution?
Hope this makes sense...many thanks for the help
You can use sympy for this:
from sympy import symbols, linsolve, Eq
x,y,z,w = symbols('x y z w')
linsolve([Eq(0.059*z, x), Eq(0.06*w, y), Eq(z+w, 8093), Eq(x+y, 422)], (x, y, z, w))
Output:
Regarding your comments about negative values - there is only one solution to the system of equations, and it has negative values for y and w. If there was more than one solution, sympy would return them, and you could filter the solutions from there to only positive values.
In R, maybe you try it like below:
library(rootSolve)
library(zeallot)
model <- function(v){
c(x,y,z,w) %<-% v
return(c(0.059*z-x, 0.06*w-y, z+w-8093, x+y-422))
}
res <- multiroot(f = model, start = c(0,0,0,0))
then you can get the solution res as
> res
[1] 3751.22 -3329.22 63580.00 -55487.00
there are a few things going on here. first as CDJB notes: if there were any positive solutions then sympy would find them. I searched for those numbers and found this paper which suggests you should be using 7088 instead of 8093. we can do a quick sanity check:
def pct(value):
return f"{value:.1%}"
print(pct(422 / 8093)) # ~5.2%
print(pct(422 / 7088)) # ~6.0%
confirming that you're going to struggle averaging ~5.9% and ~6.0% towards ~5.2%, and explaining the negative solutions in the other answers. further, these are presumably counts so all your variables also need to be whole numbers.
once this correct denominator is used, I'd comment that there are many solutions (11645 by my count) e.g:
cases = [1, 421]
pop = [17, 7071]
rates = [pct(c / p) for c, p in zip(cases, pop)]
gives the appropriate output, as does:
cases = [2, 420]
pop = [34, 7054]
this is because the data was rounded to two decimal places. you probably also don't want to use either of the above, they're just the first two valid solutions I got.
we can define a Python function to enumerate all solutions:
from math import floor, ceil
def solutions(pop, cases, rate1, rate2, err):
target = (pct(rate1), pct(rate2))
for pop1 in range(1, pop):
pop2 = pop - pop1
c1_lo = ceil(pop1 * (rate1 - err))
c1_hi = floor(pop1 * (rate1 + err))
for c1 in range(c1_lo, c1_hi+1):
c2 = cases - c1
if (pct(c1 / pop1), pct(c2 / pop2)) == target:
yield c1, c2, pop1, pop2
all_sols = list(solutions(7088, 422, 0.059, 0.060, 0.0005))
which is where I got my count of 11645 above from.
not sure what to suggest with this, but you could maybe do a bootstrap to see how much your statistic varies with different solutions. another option would be to do a Bayesian analysis which would let you put priors over the population sizes and hence cut this down a lot.
We are working on a big mathematical project with a lot of long equations and derivatives, which are produced by Wolfram Mathematica. We have more than 1000 very long equations.
Master program is written in Java and Mathematica is only used for generating equations. Our goal is to transform "Mathematica" form to "Java" form of equation. Then we can copy/paste generated code directly to "Java" code.
So for example we have short equation in Mathematica form:
Sqrt[((Cos[R]*X1 - X2)^2 + (Sin[R]*Y1 - Y2)^2)/S^2]/S
And we want to have it in Java form, so this is expected result:
Math.sqrt((Math.pow(Math.cos(R) * X1 - X2, 2) + Math.pow(Math.sin(R) * Y1 - Y2, 2)) / Math.pow(S, 2)) / S
Here is short python script, which manages some functions:
E = "Sqrt[((Cos[R]*X1 - X2)^2 + (Sin[R]*Y1 - Y2)^2)/S^2]/S"
E = E.replace("[", "(") # Replaces Square brackets with normal brackets
E = E.replace("]", ")") # Replaces Square brackets with normal brackets
E = E.replace("*", " * ") # Add some spaces for easier reading
E = E.replace("/", " / ") # Add some spaces for easier reading
E = E.replace("Cos", "Math.cos") # Change "Mathematica" cos to "Java" cos
E = E.replace("Sin", "Math.sin") # Change "Mathematica" sin to "Java" sin
E = E.replace("Sqrt", "Math.sqrt") # Change "Mathematica" SQRT to "Java" SQRT
# Converting Power function is missing here... This is a must :)
print(E)
Above code produces:
Math.sqrt(((Math.cos(R) * X1 - X2)^2 + (Math.sin(R) * Y1 - Y2)^2) / S^2) / S
The problem is that we didn't find any solution for power function. We wanted to use python regex, but we cannot find any proper solution. The problem is that power function has to take everything within brackets, so for example:
(Math.cos(R) * X1 - X2)^2 >>>> Math.pow(Math.cos(R) * X1 - X2, 2)
I hope that somebody has a quick and fancy solution. Otherwise I will need to take some time and write a long and "dirty" script, which will take care of this problem.
Thanks for your help :)
Your regex search could be somethig like this:
import re
E = "(Math.cos(R) * X1 - X2)^2"
regex = re.compile(r'\((.*)\)\^(\d)')
match = regex.match(E)
new_E = "Math.pow(%s, %s)" % (match.group(1), match.group(2))
print(new_E) # Math.pow(Math.cos(R) * X1 - X2, 2)
The way it works is by searching for anything inside parenthesis, followed by ^n, being n a digit from 0 to 9.
I hope you can adapt this to be as generalized as you need it to be.
I tried something using mathematica's fullform[] function which turns a^b into Power[a,b]. Then I changed the Power[a,b] to some arbitrary function e.g PowerJ[a,b] using find and replace. Then I could change back to input stlye to return the formula to a form with has "*,+" etc. I was then able to use your code above to change the PowerJ[a,b] to Math.pow[a,b].
I have several expressions of an undefined function some of which contain the corresponding (undefined) derivatives of that function. Both the function and its derivatives exist only as numerical data. I want to make functions out of my expressions and then call that function with the corresponding numerical data to numerically compute the expression. Unfortunately I have run into a problem with lambdify.
Consider the following simplified example:
import sympy
import numpy
# define a parameter and an unknown function on said parameter
t = sympy.Symbol('t')
s = sympy.Function('s')(t)
# a "normal" expression
a = t*s**2
print(a)
#OUT: t*s(t)**2
# an expression which contains a derivative
b = a.diff(t)
print(b)
#OUT: 2*t*s(t)*Derivative(s(t), t) + s(t)**2
# generate an arbitrary numerical input
# for demo purposes lets assume that s(t):=sin(t)
t0 = 0
s0 = numpy.sin(t0)
sd0 = numpy.cos(t0)
# labdify a
fa = sympy.lambdify([t, s], a)
va = fa(t0, s0)
print (va)
#OUT: 0
# try to lambdify b
fb = sympy.lambdify([t, s, s.diff(t)], b) # this fails with syntax error
vb = fb(t0, s0, sd0)
print (vb)
Error message:
File "<string>", line 1
lambda _Dummy_142,_Dummy_143,Derivative(s(t), t): (2*_Dummy_142*_Dummy_143*Derivative(_Dummy_143, _Dummy_142) + _Dummy_143**2)
^
SyntaxError: invalid syntax
Apparently the Derivative object is not resolved correctly, how can I work around that?
As an alternative to lambdify I'm also open to using theano or cython based solutions, but I have encountered similar problems with the corresponding printers.
Any help is appreciated.
As far as I can tell, the problem originates from an incorrect/unfortunate dummification process within the lambdify function. I have written my own dummification function that I apply to the parameters as well as the expression before passing them to lambdifying.
def dummify_undefined_functions(expr):
mapping = {}
# replace all Derivative terms
for der in expr.atoms(sympy.Derivative):
f_name = der.expr.func.__name__
var_names = [var.name for var in der.variables]
name = "d%s_d%s" % (f_name, 'd'.join(var_names))
mapping[der] = sympy.Symbol(name)
# replace undefined functions
from sympy.core.function import AppliedUndef
for f in expr.atoms(AppliedUndef):
f_name = f.func.__name__
mapping[f] = sympy.Symbol(f_name)
return expr.subs(mapping)
Use like this:
params = [dummify_undefined_functions(x) for x in [t, s, s.diff(t)]]
expr = dummify_undefined_functions(b)
fb = sympy.lambdify(params, expr)
Obviously this is somewhat brittle:
no guard against name-collisions
perhaps not the best possible name-scheme: df_dxdy for Derivative(f(x,y), x, y)
it is assumed that all derivatives are of the form:
Derivative(s(t), t, ...) with s(t) being an UndefinedFunction and t a Symbol. I have no idea what will happen if any argument to Derivative is a more complex expression. I kind of think/hope that the (automatic) simplification process will reduce any more complex derivative into an expression consisting of 'basic' derivatives. But I certainly do not guard against it.
largely untested (except for my specific use-cases)
Other than that it works quite well.
First off, rather than an UndefinedFunction, you could go ahead and use the implemented_function function to tie your numerical implementation of s(t) to a symbolic function.
Then, if you are constrained to discrete numerical data defining the function whose derivative occurs in the troublesome expression, much of the time, the numerical evaluation of the derivative may come from finite differences. As an alternative, sympy can automatically replace derivative terms with finite differences, and let the resulting expression be converted to a lambda. For example:
import sympy
import numpy
from sympy.utilities.lambdify import lambdify, implemented_function
from sympy import Function
# define a parameter and an unknown function on said parameter
t = sympy.Symbol('t')
s = implemented_function(Function('s'), numpy.cos)
print('A plain ol\' expression')
a = t*s(t)**2
print(a)
print('Derivative of above:')
b = a.diff(t)
print(b)
# try to lambdify b by first replacing with finite differences
dx = 0.1
bapprox = b.replace(lambda arg: arg.is_Derivative,
lambda arg: arg.as_finite_difference(points=dx))
print('Approximation of derivatives:')
print(bapprox)
fb = sympy.lambdify([t], bapprox)
t0 = 0.0
vb = fb(t0)
print(vb)
The similar question was discussed at here
You just need to define your own function and define its derivative as another function:
def f_impl(x):
return x**2
def df_impl(x):
return 2*x
class df(sy.Function):
nargs = 1
is_real = True
_imp_ = staticmethod(df_impl)
class f(sy.Function):
nargs = 1
is_real = True
_imp_ = staticmethod(f_impl)
def fdiff(self, argindex=1):
return df(self.args[0])
t = sy.Symbol('t')
print f(t).diff().subs({t:0.1})
expr = f(t) + f(t).diff()
expr_real = sy.lambdify(t, expr)
print expr_real(0.1)
I'm trying to solve a set of coupled ODE's using odeint in python; I initially created the program to solve 3 specified equations (where I use sympy.subs for each value I knew was present), but now I wish to solve N many coupled ODE's. The issue I am running into is how to properly substitute for initial conditions given a these equations were I don't know which values are present (i.e. which ones must be substituted).
For example: For an input of a 3x3 matrix, the set of ODEs I have is:
v0' = -6*v1*v3 - 12*v2*v6
v1' = -3*v1*(6 + v4) - 9*v2*v7 + 3*(3 + v0)*v1
v2' = -6*v2*(9 + v8) + 6*(3 + v0)*v2
v3' = 3*v3*(3 + v0) - 9*v5*v6 - 3*(6 + v4)*v3
v4' = 6*v3*v1 - 6*v5*v7
v5' = 9*v3*v2 - 3*v5*(9 + v8) + 3*(6 + v4)*v5
v6' = 6*v6*(3 + v0) - 6*(9 + v8)*v6
v7' = 9*v6*v1 + 3*v7*(6 + v4) - 3*(9 + v8)*v7
v8' = 12*v6*v2 + 6*v7*v5
where I have initial values for v0-v8 (where v0-v8 are set up as symbols through SymPy) in a vector but without manually substituting in each value, I don't know how to solve this.
Is there a way to substitute the values for v0-v8 without knowing which values of v0-v8 are present. (For different size matrices, the amount of initial values also change - i.e. 4x4 has v0-v15)
Edit: edited so that v0'-v8' are shown as functions of the coupled ODEs. When entering them in the odeint though, the equations are just implicitly equal to v0'-v8' by their position in the vector.
v0-v8 are created by:
v = sy.symbols('v0:%d'%matSize, commutative=False)
where matSize is an input int that correlates to the size of the input matrix.