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].
Related
I'm in the middle of a big (and frankly quite hard) project so while this is my first interrogation, it probably won't be the last. Also : english is not my first langage so 'Sorry for bad english' and I'm writing this on my phone so 'Sorry for bad formating'.
Ok so : I'm trying to implement the General Number Field Sieve in Python, and I'm, at least for now, heavily relying on sympy.
Here is a peice of code where I'm struggling. In the code below, gpc(N,m) is a float list.
From sympy import Poly
From sympy.abc import x
g = Poly(gpc(N,m), x) [*]
However, when I do that, I get a polynomial over the domain RR and I would very much like to switch this to another domain D (where D will end up being ZZ['x'] but I would like this function to be general)
I'm aware of the fact that I can slightly modify [*] in
g = Poly(gpc(N,m), x, domain = D)
to get what I want. However, this wouldn't be enough. Somewhere else in my code, I need to be able to change the domain of an already constructed polynomial, and this solution wouldn't help.
When I lookep it up, I found the change_ring method so I tried this :
f = g.change_ring(D)
However, upon execution, I get the error message :
'Poly' object has no attribute 'change_ring'
So I guess that this function don't exist.
Does anyone knows how to change the domain of a polynomial ?
Thanks a lot !
It looks like creating a new Poly instance is the best approach; there are a few class methods that could help (take a look at the Poly.from_* class methods)
For example:
from sympy import Poly
from sympy.abc import x, a
g = Poly(x**3 + a*x*2 - 5*x + 6, x)
print(g) # Poly(x**3 + (2*a - 5)*x + 6, x, domain='ZZ[a]')
f = Poly.from_poly(g, *g.gens, domain='ZZ[a, b]')
print(f) # Poly(x**3 + (2*a - 5)*x + 6, x, domain='ZZ[a,b]')
I also wonder if rationalizing your floats at some point might help - see e.g. nsimplify.
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.
I am trying to approximate the Gauss Linking integral for two straight lines in R^3 using dblquad. I've created this pair of lines as an object.
I have a form for the integrand in parametrisation variables s and t generated by a function gaussint(self,s,t) and this is working. I'm then just trying to define a function which returns the double integral over the two intervals [0,1].
Edit - the code for the function looks like this:
def gaussint(self,s,t):
formnum = self.newlens()[0]*self.newlens()[1]*np.sin(test.angle())*np.cos(test.angle())
formdenone = (np.cos(test.angle())**2)*(t*(self.newlens()[0]) - s*(self.newlens()[1]) + self.adists()[0] - self.adists()[1])**2
formdentwo = (np.sin(test.angle())**2)*(t*(self.newlens()[0]) + s*(self.newlens()[1]) + self.adists()[0] + self.adists()[1])**2
fullden = (4 + formdenone + formdentwo)**(3/2)
fullform = formnum/fullden
return fullform
The various other function calls here are just bits of linear algebra - lengths of lines, angle between them and so forth. s and t have been defined as symbols upstream, if they need to be.
The code for the integration then just looks like this (I've separated it out just to try and work out what was going on:
def approxint(self, s, t):
from scipy.integrate import dblquad
return dblquad(self.gaussint(s,t),0,1, lambda t:0,lambda t:1)
Running it gets me a lengthy bit of somewhat impenetrable process messages, followed by
ValueError: invalid callable given
Any idea where I'm going wrong?
Cheers.
Im trying to speed up my python code by porting a bunch of my nested loops over to fortran and calling them as subroutines.
But alot of my loops call numpy, and special functions from scipy like bessel functions.
Before I try and use fortran I was wondering if it was possible to import scipy and numpy to my fortran subroutine and call the modules for bessel functions?
Else would I have to create the bessel function in fortran in order to use it?
Ideally, I would create some sort of subroutine that would optimize this code below. This is just a snippet of my entire project to give you an idea of what I'm trying to accomplish.
I understand that there are other practices I should implement to improve the speed, but for now I was investigating the benefits of calling fortran subroutines in my main python program.
for m in range(self.MaxNum_Eigen):
#looping throught the eigenvalues for the given maximum number of eigenvalues allotted
bm = self.beta[m]
#not sure
#*note: rprime = r. BUT tprime ~= t.
#K is a list of 31 elements for this particular case
K = (bm / math.sqrt( (self.H2**2) + (bm**2) ))*(math.sqrt(2) / self.b)*((scipy.special.jv(0, bm * self.r))/ (scipy.special.jv(0, bm * self.b))) # Kernel, K0(bm, r).
#initial condition
F = [37] * (self.n1)
# Integral transform of the initial condition
#Fbar = (np.trapz(self.r,self.r*K*F))
'''
matlab syntax trapz(X,Y), x ethier spacing or vector
matlab: trapz(r,r.*K.*F) trapz(X,Y)
python: np.trapz(self.r*K*F, self.r) trapz(Y,X)
'''
#*(np.trapz(self.r,self.r*K*F))
Fbar = np.ones((self.n1,self.n2))*(np.trapz(self.r*K*F, self.r))
#steady state condition: integral is in steady state
SS = np.zeros((sz[0],sz[1]))
coeff = 5000000*math.exp(-(10**3)) #defining value outside of loop with higher precision
for i in range(sz[0]):
for j in range(sz[1]):
'''
matlab reshape(Array, size1, size2) takes multiple arguments the item its resizeing and the new desired shape
create self variables and so we are not re-initializing them over and over agaian?
using generators? How to use generators
'''
s = np.reshape(tau[i,j,:],(1,n3))
# will be used for rprime and tprime in Ozisik solution.
[RR,TT] = np.meshgrid(self.r,s)
'''
##### ERROR DUE TO ROUNDING OF HEAT SOURCE ####
error in rounding 5000000*math.exp(-(10**3)) becomes zero
#log10(e−10000)=−10000∗(0.4342944819)=−4342.944819
#e−1000=10−4342.944819=10−4343100.05518=1.13548386531×10−4343
'''
#g = 5000000*math.exp(-(10**3)) #*(RR - self.c*TT)**2) #[W / m^2] heat source.
g = coeff * (RR - self.c*TT)**2
K = (bm/math.sqrt(self.H2**2 + bm**2))*(math.sqrt(2)/self.b)*((scipy.special.jv(0,bm*RR))/(scipy.special.jv(0,bm*self.b)))
#integral transform of heat source
gbar = np.trapz(RR*K*g, self.r, 2) #trapz(Y,X,dx (spacing) )
gbar = gbar.transpose()
#boundary condition. BE SURE TO WRITE IN TERMS OF s!!!
f2 = self.h2 * 37
A = (self.alpha/self.k)*gbar + ((self.alpha*self.b)/self.k2)*((bm/math.sqrt(self.H2**2 + bm**2))*(math.sqrt(2)/self.b)*((scipy.special.jv(0,bm*self.b))/(scipy.special.jv(0,bm*self.b))))*f2
#A is essentially a constant is this correct all the time?
#What does A represent
SS[i, j] = np.trapz(np.exp( (-self.alpha*bm**2)*(T[i,j] - s) )*A, s)
#INSIDE M loop
K = (bm / math.sqrt((self.H2 ** 2) + (bm ** 2)))*(math.sqrt(2) /self.b)*((scipy.special.jv(0, bm * R))/ (scipy.special.jv(0, bm * self.b)))
U[:,:, m] = np.exp(-self.alpha * bm ** 2 * T)* K* Fbar + K* SS
#print(['Eigenvalue ' num2str(m) ', found at time ' num2str(toc) ' seconds'])
Compilation of answers given in the comments
Answers specific to my code:
As vorticity mentioned my code in itself was not using the numpy, and scipy packages to the fullest extent.
In regards to Bessel, function 'royvib' mentions using using .jo from scipy rather than .jv. Calling the special Bessel function jv. is much more computationally expensive, especially since I knew that I would be using a zeroth order bessel function for many of my declarations the minor change from jv -> j0 solved speed up the process.
In addition, I declared variables outside the loop to prevent expensive calls to searching for my appropriate functions. Example below.
Before
for i in range(SomeLength):
some_var = scipy.special.jv(1,coeff)
After
Bessel = scipy.special.jv
for i in range(SomeLength):
some_var = Bessel(1,coeff)
Storing the function saved time by not using the dot ('.') the command to look through the libraries every single loop. However keep in mind this does make python less readable, which is the main reason I choose to do this project in python. I do not have an exact amount of time this step cut from my process.
Fortran specific:
Since I was able to improve my python code I did not go this route an lack of specifics, but the general answer as stated by 'High Performance Mark' is that yes there are libraries that have been made to handle Bessel functions in Fortran.
If I do port my code over to Fortran or use f2py to mix Fortran and python I will update this answer accordingly.
If I use functions in SymPy and call the diff method, the commutative property just gets ignored.
h = Function('h',real=True,commutative=False)(t)
R = Function('R',real=True,commutative=False)(t)
print(diff(R*h,t))
# returns:
R(t)*Derivative(h(t), t) + h(t)*Derivative(R(t), t)
Am I doing something wrong here? I just want the output to have R in the front always..
This is arguably a bug in SymPy, which determines the commutativity of a function from its arguments. See also this comment. It's not related to derivatives: simply printing h*R will expose the bug (the expression is presented as R(t)*h(t)).
Until this behavior is changed, it seems the only way to achieve the desired result is to declare t to be noncommutative:
t = Symbol('t', commutative=False)
h = Function('h', real=True)(t)
R = Function('R', real=True)(t)
print(diff(R*h, t))
prints
R(t)*Derivative(h(t), t) + Derivative(R(t), t)*h(t)