How to add "*" inside an equation? - python

I'm new to python.
I want to make a calculator and I am facing a problem right now.
Here's a simplified code I am trying to make:
from math import *
input = "(2)(3)e(sqrt(49))pi" #This is an example of equation
equation = "(2)*(3)*e*(sqrt(49))*pi" #The output
How can I add " * " between every ")(", ")e", "e(", and others based on the equation so that I can eval (equation) without having to put "*" manually, just like real life math?
I have tried to do it by making a code like this:
from math import *
input = "(2)(3)e(sqrt(49))pi"
input = input.replace(")(", ")*(")
input = input.replace(")e", ")*e")
input = input.replace("e(", "e*(")
input = input.replace(")pi", ")*pi")
#^^^I can loop this using for loop^^^
equation = input
print(eval(equation))
This definitely only works in this equation. I can loop the replacing method but that would be very inefficient. I don't want to have 49 iterations to just check if 7 different symbols need "*" between it or not.

The issue you will encounter here is that "e(" should be transformed to "e*(" but "sqrt(" should stay. As comments have suggested, the best or "cleanest" solution would be to write a proper parser for your equation. You could put "calculator parser" into your favorite search engine for a quick solution, or if you are interested in over-engineering but learning a lot, you could have a look at parser generators such as ANTLr.
If, for some reason, neither of those are an option, a quick-and-dirty solution could be this:
import re
def add_multiplication_symbols(equation: str) -> str:
constants = ['e', 'pi']
constants_re = '|'.join(f'(?:{re.escape(c)})' for c in constants)
equation = re.sub(r'(\))(\(|\w+)', r'\1*\2', equation)
equation = re.sub(f'({constants_re})' + r'(\()', r'\1*\2', equation)
return equation
Then print(add_multiplication_symbols("(2)(3)e(sqrt(49))pi")) results in (2)*(3)*e*(sqrt(49))*pi.
The function makes use of the re module (regular expressions) to group the cases for all constants together. It tries to work around the issue I described above by defining a set of constant variables (e.g. "e" and "pi") by hand.

Related

Sympy: How to get simplified commutators using the second quantization module?

So I want to use the fact that [b,bd]=1, where [] is the commutator, to get some commutators of more complicated expressions using sympy instead of doing it by hand, but instead, I get huge expressions that contain the commutator but it is not replaced for 1, here's the code
from sympy import *
from sympy.physics.secondquant import *
comm1=simplify(Commutator(B(0),Bd(0)).doit())
comm1
the output in this case is 1 , it corresponds to the [b,bd]=1 case, but if I input a more complicated expression such as
w1,w2,g=symbols('w1 w1 g')
H=w1*B(0)*Bd(0)+w2*B(1)*Bd(1)+g*Bd(0)*B(1)+conjugate(g)*Bd(1)*B(0)
comm2=simplify(Commutator(H,B(0)))
print(simplify(comm2))
I get
-g*(AnnihilateBoson(0)*CreateBoson(0)*AnnihilateBoson(1) - CreateBoson(0)*AnnihilateBoson(1)*AnnihilateBoson(0)) - w1*(AnnihilateBoson(0)*AnnihilateBoson(1)*CreateBoson(1) - AnnihilateBoson(1)*CreateBoson(1)*AnnihilateBoson(0)) + w1*(AnnihilateBoson(0)*CreateBoson(0)*AnnihilateBoson(0) - AnnihilateBoson(0)**2*CreateBoson(0)) - conjugate(g)*(AnnihilateBoson(0)*CreateBoson(1)*AnnihilateBoson(0) - CreateBoson(1)*AnnihilateBoson(0)**2)
Which clearly would be simplified quite a lot if [b,bd]=1 was substituted, Does anyone know how to this ? or could anyone point me to another tool capable of doing this?
The key trick is always to use the commutation relation to move either 'a' or 'a^\dagger' to the left, until you cannot do that anymore.
I don't have a good Sympy answer, but since you asked about other tools, here's a shameless plug about how you do it in Cadabra (https://cadabra.science) (which uses Sympy for various things, though not this particular computation). First setup the two sets of creation/annihilation operators using:
{a_{0}, ad_{0}}::NonCommuting;
{a_{1}, ad_{1}}::NonCommuting;
{a_{0}, ad_{0}, a_{1}, ad_{1}}::SortOrder.
They'll print nicer with
\bar{#}::Accent;
ad_{n?}::LaTeXForm("a^\dagger",n?,"").
Your Hamiltonian:
H:= w_{1} a_{0} ad_{0} + w_{2} a_{1} ad_{1} + g ad_{0} a_{1} + \bar{g} ad_{1} a_{1};
The commutator you want to compute:
ex:= #(H) a_{0} - a_{0} #(H);
Just expanding this (without simplification using the [a,ad]=1 commutator) is done with
distribute(ex);
sort_product(ex);
where the 2nd line moves operators with different subscripts through each other, but keeps the order of operators with the same subscripts. Applying the commutator until the expression no longer changes:
converge(ex):
substitute(ex, $a_{n?} ad_{n?} = ad_{n?} a_{n?} + 1$)
distribute(ex)
;
to finally give '-a_0 w_1 - a_1 g'.

Unknown result in z3 python for Int type

I was trying to solve certain set of constraints using z3 in python. My code:
import math
from z3 import *
### declaration
n_co2 = []
c_co2 = []
alpha = []
beta = []
m_dot_air = []
n_pir = []
pir_sensor = []
for i in range(2):
c_co2.append(Real('c_co2_'+str(i)))
n_pir.append(Real('n_pir_'+str(i)))
n_co2.append(Real('n_co2_'+str(0)))
alpha.append(Real('alpha_'+str(0)))
beta.append(Real('beta_'+str(0)))
m_dot_air.append(Real('m_dot_air_'+str(0)))
pir_sensor.append(Real('pir_sensor_'+str(0)))
s = Solver()
s.add(n_co2[0]>0)
s.add(c_co2[0]>0)
s.add(c_co2[1]>=0.95*c_co2[0])
s.add(c_co2[1]<=1.05*c_co2[0])
s.add(n_co2[0]>=0.95*n_pir[1])
s.add(n_co2[0]<=1.05*n_pir[1])
s.add(c_co2[1]>0)
s.add(alpha[0]<=-1)
s.add(beta[0]>0)
s.add(m_dot_air[0]>0)
s.add(alpha[0]==-1*(1+ m_dot_air[0] + (m_dot_air[0]**2)/2.0 + (m_dot_air[0]**3)/6.0 ))
s.add(beta[0]== (1-alpha[0])/m_dot_air[0])
s.add(n_co2[0]== (c_co2[1]-alpha[0]*c_co2[0])/(beta[0]*19.6)-(m_dot_air[0]*339)/19.6)
s.add(n_pir[1]>=0)
s.add(pir_sensor[0]>=-1)
s.add(pir_sensor[0]<=1)
s.add(Not(pir_sensor[0]==0))
s.add(n_pir[1]==(n_pir[0]+pir_sensor[0]))
#### testing
s.add(pir_sensor[0]==1)
s.add(n_pir[1]==1)
s.add(n_co2[0]==1)
print(s.check())
print(s.reason_unknown())
print(s.model())
The output of the code:
sat
[c_co2_0 = 355,
c_co2_1 = 1841/5,
m_dot_air_0 = 1,
n_co2_0 = 1,
n_pir_1 = 1,
pir_sensor_0 = 1,
n_pir_0 = 0,
beta_0 = 11/3,
alpha_0 = -8/3,
/0 = [(19723/15, 1078/15) -> 1793/98,
(11/3, 1) -> 11/3,
else -> 0]]
What is the significance "/0 = ..." part of the output model.
But when I change the type of n_pir from Real to Int, z3 cannot solve it. Although we saw that we have an Int solution for n_pir. Reason of unknown:
smt tactic failed to show goal to be sat/unsat (incomplete (theory arithmetic))
How this problem can be solved? Could anyone please provide reasoning about this problem?
For the "/0" part: It's an internally generated constraint from converting real to int solutions. You can totally ignore that. In fact, you shouldn't really even look at the value of that, it's an artifact of the z3py bindings and should probably be hidden from the user.
For your question regarding why you cannot make 'Real' to 'Int'. That's because you have a non-linear set of equations (where you multiply or divide two variables), and non-linear integer arithmetic is undecidable in general. (Whereas non-linear real arithmetic is decidable.) So, when you use 'Int', solver simply uses some heuristics, and in this case fails and says unknown. This is totally expected. Read this answer for more details: How does Z3 handle non-linear integer arithmetic?
Z3 does come with an NRA solver, you can give that a try. Declare your solver as:
s = SolverFor("NRA")
But again you're at the mercy of the heuristics and you may or may not get a solution. Also, watch out for z3py bindings coercing constants to when you mix and match arithmetic like that. A good way is to write:
print s.sexpr()
before you call s.check() and take a look at the output and convince yourself that the translation has been done correctly. For details on that, see this question: Python and Z3: integers and floating, how to manage them in the correct way?

Python: How to solve an ordinary differential equation with integral term in it

I dont know if this question has been asked before in SO, I will go ahead and post it here, I am attempting to solve a simple system with a PID controller, my system of differential equations are given below. I am basically attempting to code very basic PID algorithm. The structure of my control u depends on both derivative and integral of error term. I dont have any problem with the derivative term, it is the integral term that is creating problem in my code. The problem crops up when I assign s=0 in the beginning
and use it in my function as described in my code below. Is there a way to bypass it? I tried assigning s and told as global variables, but it didnt solve my problem. In a nutshell what I am doing is- I am adding state x1 every time and multiplying by dt(which is denoted by t-told).
Kindly help me iron out this issue, PFA my code attached below.
import numpy as np
from scipy.integrate import ode
import matplotlib.pyplot as plt
plt.style.use('bmh')
t0=0
y0=[0.1,0.2]
kp,kd,ki=2,0.5,0.8
s,told=0,0
def pid(t,Y):
x1,x2=Y[0],Y[1]
e=x1-1
de=x2
s=(x1+s)
integral=s*(t-told)
told=t
#ie=
u=kp*e+kd*de+ki*integral
x1dot=x2
x2dot=u-5*x1-2*x2
return[x1dot,x2dot]
solver=ode(pid).set_integrator('dopri5',rtol=1e-6,method='bdf',nsteps=1e5,max_step=1e-3)
solver.set_initial_value(y0,t0)
t1=10
dt=5e-3
sol = [ [yy] for yy in y0 ]
t=[t0]
while solver.successful() and solver.t<t1:
solver.integrate(solver.t+dt)
for k in range(2): sol[k].append(solver.y[k]);
t.append(solver.t)
print(len(sol[0]))
print(len(t))
x1=np.array(sol[0])
x2=np.array(sol[1])
e=x1-1
de=x2
u=kp*e+kd*de
for k in range(2):
if k==0:
plt.subplot(2,1,k+1)
plt.plot(t,sol[k],label='x1')
plt.plot(t,sol[k+1],label='x2')
plt.legend(loc='lower right')
else:
plt.subplot(2,1,k+1)
plt.plot(t,u)
plt.show()
You are making assumptions on the solver and the time steps that it visits that are not justified. With your hacking of the integral, even if it were mathematically sound (it should look like integral = integral + e*(t-told), which gives an order 1 integration method), you reduce the order of any integration method, probably down to 1, if you are lucky only to order 2.
A mathematically correct method to implement this system is to introduce a third variable x3 for the integral of e, that is, the derivative of x3 is e. That the correct order 1 system has to be of dimension 3 can be read of the fact that (eliminating e) your system has 3 differentiation/integration operations. With that your system becomes
def pid(t,Y):
x1, x2, x3 =Y
e=x1-1
x1dot = x2
edot = x1dot
x3dot = e
u=kp*e+kd*edot+ki*x3
x2dot=u-5*x1-2*x2
return[x1dot, x2dot, x3dot]
Note that there are no global dynamic variables necessary, only the constants (which could also be passed as parameters, whatever seems more efficient or readable).
Now you will also need an initial value for x3, it was not visible from the system what the integration variable would have to be, your code seems to suggest 0.
First of all you need to include "s" Variable into the pid function.
'
def pid(s, t, Y): ...
'
Easiest solution I can see right now is to create a class with s and told as properties of this class:
class PIDSolver:
def __init__(self)
self.t0=0
self.y0=[0.1,0.2]
self.kp,self.kd,self.ki=2,0.5,0.8
self.s,self.told=0,0
def pid(t,Y):
x1,x2=Y[0],Y[1]
e=x1-1
de=x2
self.s=(x1+self.s)
integral=self.s*(t-self.told)
self.told=t
#ie=
u=self.kp*e+self.kd*de+self.ki*integral
x1dot=x2
x2dot=u-5*x1-2*x2
return[x1dot,x2dot]
For the first part of your problem. Use pidsolver = PIDSolver() in the next part of your solution.
I solved this problem myself by using set_f_params() method and passing a list in itz argument. Also I passed a 3rd argument in pid() i.e pid(t,Y,arg). And lastly I assigned s,told=arg[0],arg[1].

multiple functions as arguments in python

I have the following problem: I have two sets of data (set T and set F). And the following functions:
x(T) = arctan(T-c0), A(x(T)) = arctan(x(T) -c1),
B(x(T)) = arctan(x(T) -c2)
and Y(x(t),F) = ((A(x(t)) - B(x(t)))/2 - A(x(t))arctan(F-c3) + B(x(t))arctan(F-c4))
# where c0,c1,c2,c3,c4 are constants
Now I want to create a surface plot of Y. And for that I would like to implement Y as a python (numpy) function what turns out to be quite complicated, because Y takes other functions as input.
Another idea of mine was to evaluate x, B and A on the data separately and store the results in numpy arrays. With those I also could get the output of the function Y , but I don't know which way is better in order to plot the data and I really would like to know how to write Y as a python function.
Thank you very much for your help
It is absolutely possible to use functions as input parameters to other functions. A use case could look like:
def plus_one(standard_input_parameter_like_int):
return standard_input_parameter_like_int + 1
def apply_function(function_as_input, standard_input_parameter):
return function_as_input(standard_input_parameter)
if(__name__ == '__main__'):
print(apply_function(plus_one, 1))
I hope that helps to solve your specific problem.
[...] somethin like def s(x,y,z,*args,*args2): will yield an
error.
This is perfectly normal as (at least as far as I know) there is only one variable length non-keyword argument list allowed per function (that has to be exactly labeled as *args). So if you remove the asterisks (*) you should actually be able to run s properly.
Regarding your initial question you could do something like:
c = [0.2,-0.2,0,0,0,0]
def x(T):
return np.arctan(T-c[0])
def A(xfunc,T):
return np.arctan(xfunc(T) - c[1])
def B(xfunc,T):
return np.arctan(xfunc(T) - c[2])
def Y(xfunc,Afunc,Bfunc,t,f):
return (Afunc(xfunc,t) - Bfunc(xfunc,t))/2.0 - Afunc(xfunc,t) * np.arctan(f - c[3]) + Bfunc(xfunc,t)*np.arctan(f-c[4])
_tSet = np.linspace(-1,1,20)
_fSet = np.arange(-1,1,20)
print Y(x,A,B,_tSet,_fSet)
As you can see (and probably already tested by yourself judging from your comment) you can use functions as arguments. And as long as you don't use any 'if' conditions or other non-vectorized functions in your 'sub'-functions the top-level function should already be vectorized.

Python equation parser

I'm writing a program which needs a user input for an polynomial function of x. I'm using Tkinter and python 2.5.
I have a parser method which so far takes the inputted equation and splits it into terms without dropping the signs.
I want to take each term and parse it to get a tuple of the (coefficient, degree). For example, -2x^3 returns (-2,3). I can then add these to an array and manipulate them accordingly in the program.
Is there a way or standard module that can do this?
Here is the beginning of the parse method.
def parse(a):
termnum=[]
terms=[]
hi=[]
num1=0
num=0
f=list(a)
count=0
negative=False
coef=0.0
deg=0.0
codeg=[]
for item in f:
if (item=='-' or item=='+') and count!=0:
termnum.append(count)
count+=1
for item in termnum:
num1=num
num=item
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
num1=num
num=len(f)
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
print terms
parse('-x^2+3x+2x^3-x')
Thanks!
P.S I don't want to use external packages.
you can use regular expressions,
import re
test = '-x^2+3x+2x^3-x'
for m in re.finditer( r'(-{0,1}\d*)x\^{0,1}(-{0,1}\d*)', test ):
coef, expn = list( map( lambda x: x if x != '' and x != '-' else x + '1' ,
m.groups( ) ))
print ( 'coef:{}, exp:{}'.format( coef, expn ))
output:
coef:-1, exp:2
coef:3, exp:1
coef:2, exp:3
coef:-1, exp:1
Look for "recursive descent parser". It's the canonical method for analysis of strings where some operator precedence is involved.
It looks like you're implementing something that already exists, in python and other math languages. See for example:
http://www.gnu.org/software/octave/doc/interpreter/Solvers.html
http://stat.ethz.ch/R-manual/R-devel/library/base/html/solve.html

Categories

Resources