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

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'.

Related

How do I rearrange an equation to be in terms of a specified variable with Sympy?

I can write, for example,
Line(Point(3,-4), Point(-2,2)).equation()
to generate an equation of a line that passes through those points, but the output is given as
-6x - 5y - 2
presumably being equivalent to -6x - 5y - 2 = 0. How can I instead set the output to be
y = (-6/5)x - (2/5)
I thought it might have to do with some formatting settings in the equation() method, so I checked the documention, but it didn't say anything about it.
EDIT 1: It appears that if I input
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()))
I will get the (albeit ugly) output
⎡⎧ 5⋅y 1⎫⎤
⎢⎨x: - ─── - ─⎬⎥
⎣⎩ 6 3⎭⎦
This does give a rearranged solution, but the issue is that this is only in the form of x=f(y). I'm not sure how I would get it to instead be in terms of y=f(x).
EDIT 2: I think this might actually be a bug with solve(), or Eq(). If I instead manually type
solve(-6*x-5*y-2,y)
or
solve(Eq(-6*x-5*y-2),y)
I will get the (somewhat ugly, but correct) output of
⎡ 6⋅x 2⎤
⎢- ─── - ─⎥
⎣ 5 5⎦
Now if I were to instead type
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()),y)
or
solve(Eq(Line(Point(3,-4), Point(-2,2)).equation()),x)
I get the output of
[]
This is rather strange, though, because
Eq(-6*x-5*y-2)
and
Eq(Line(Point(3,-4),Point(-2,2)).equation())
both output
-6⋅x - 5⋅y - 2 = 0
so I'm really not sure what Is going on here.
Since you need to pass the symbol you want to solve for, you can do something like this (Although the equation function expects strings )
x, y = symbols('x, y')
eq = (Line(Point(3,-4), Point(-2,2)).equation(x,y))
print(solve(eq, y))# prints [-6*x/5 - 2/5]
or you can get the symbol from the expression and pass it to solve like
eq = (Line(Point(3,-4), Point(-2,2)).equation())
print(solve((eq), list(eq.atoms(Symbol))[1])) # prints [-6*x/5 - 2/5]
The symbols used in the equation have assumptions on them and that makes them different from the plain symbols you might create with Symbol('x'). So that's why it has the option to pass in the symbols you want to use for x and y.
>>> var('x y')
(x, y)
>>> Line(Point(3,-4), Point(-2,2)).equation(x,y)
-6*x - 5*y - 2
>>> Eq(y, solve(_, y)[0])
Eq(y, -6*x/5 - 2/5)
That's also why you didn't get a solution in one of your examples -- the variable you were solving for wasn't in the equation. It looked the same but it wasn't since it had different assumptions on it.

How to add "*" inside an equation?

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.

Subs object still remains after calling doit method in sympy

I am trying to calculate general composite function derivative using sympy. In my specific case script is the following:
from sympy import *
t=symbols('t')
p=Function('p')
x=Function('x')
v=diff(x(p(t)),t)
a=diff(v,t)
for variable a it yields:
Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(p(t), t, t)*Subs(Derivative(x(_xi_1), _xi_1), (_xi_1,), (p(t),))
If I call doit(), answer still contains subs object
a.doit() #answer: Derivative(p(t), t)**2*Subs(Derivative(x(_xi_3), _xi_3, _xi_3), (_xi_3,), (p(t),)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t)
Mathematically the answer is correct but I still need output in following format (without Subs objects):
Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t)
Is there any way to achieve desired result? To be clear this example is very simplified compared to my original expression so I need general way to get desired output.
Indeed, repeated applications of doit() in this case result in flip-flopping between two forms of the expression: half the time the first addend has Subs, half the time it's the second.
But you can deal with the issue as follows:
for b in a.atoms(Subs):
a = a.xreplace({b: b.doit()})
This returns Derivative(p(t), t)**2*Derivative(x(p(t)), p(t), p(t)) + Derivative(x(p(t)), p(t))*Derivative(p(t), t, t) as desired.
The trick is that atoms(Subs) is the set of all Subs objects in the expression, and doit is applied only to them, not to Derivative objects where it only messes things up. (Ideally, doit would not mess Derivative objects up in the first place...)

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.

Reduce function calls

I profiled my python program and found that the following function was taking too long to run. Perhaps, I can use a different algorithm and make it run faster. However, I have read that I can also possibly increase the speed by reducing function calls, especially when it gets called repeatedly within a loop. I am a python newbie and would like to learn how to do this and see how much faster it can get. Currently, the function is:
def potentialActualBuyers(setOfPeople,theCar,price):
count=0
for person in setOfPeople:
if person.getUtility(theCar) >= price and person.periodCarPurchased==None:
count += 1
return count
where setOfPeople is a list of person objects. I tried the following:
def potentialActualBuyers(setOfPeople,theCar,price):
count=0
Utility=person.getUtility
for person in setOfPeople:
if Utility(theCar) >= price and person.periodCarPurchased==None:
count += 1
return count
This, however, gives me an error saying local variable 'person' referenced before assignment
Any suggestions, how I can reduce function calls or any other changes that can make the code faster.
Again, I am a python newbie and even though I may possibly be able to use a better algorithm, it is still worthwhile learning the answer to the above question.
Thanks very much.
***** EDIT *****
Adding the getUtility method:
def getUtility(self,theCar):
if theCar in self.utility.keys():
return self.utility[theCar]
else:
self.utility[theCar]=self.A*(math.pow(theCar.mpg,self.alpha))*(math.pow(theCar.hp,self.beta))*(math.pow(theCar.pc,self.gamma))
return self.utility[theCar]
***** EDIT: asking for new ideas *****
Any ideas how to speed this up further. I used the method suggested by Alex to cut the time in half. Can I speed this further?
Thanks.
I doubt you can get much speedup in this case by hoisting the lookup of person.getUtility (by class, not by instances, as other instances have pointed out). Maybe...:
return sum(1 for p in setOfPeople
if p.periodCarPurchased is None
and p.getUtility(theCar) >= price)
but I suspect most of the time is actually spent in the execution of getUtility (and possibly in the lookup of p.periodCarPurchased if that's some fancy property as opposed to a plain old attribute -- I moved the latter before the and just in case it is a plain attribute and can save a number of the getUtility calls). What does your profiling say wrt the fraction of time spent in this function (net of its calls to others) vs the method (and possibly property) in question?
Try instead (that's assuming all persons are of the same type Person):
Utility = Person.getUtility
for person in setOfPeople:
if Utility (person, theCar) >= ...
Also, instead of == None using is None should be marginally faster. Try if swapping and terms helps.
Methods are just functions bound to an object:
Utility = Person.getUtility
for person in setOfPeople:
if Utility(person, theCar) ...
This doesn't eliminate a function call though, it eliminates an attribute lookup.
This one line made my eyes bleed:
self.utility[theCar]=self.A*(math.pow(theCar.mpg,self.alpha))*(math.pow(theCar.hp,self.beta))*(math.pow(theCar.pc,self.gamma))
Let's make it legible and PEP8able and then see if it can be faster. First some spaces:
self.utility[theCar] = self.A * (math.pow(theCar.mpg, self.alpha)) * (math.pow(theCar.hp, self.beta)) * (math.pow(theCar.pc, self.gamma))
Now we can see there are very redundant parentheses; remove them:
self.utility[theCar] = self.A * math.pow(theCar.mpg, self.alpha) * math.pow(theCar.hp, self.beta) * math.pow(theCar.pc, self.gamma)
Hmmm: 3 lookups of math.pow and 3 function calls. You have three choices for powers: x ** y, the built-in pow(x, y[, z]), and math.pow(x, y). Unless you have good reason for using one of the others, it's best (IMHO) to choose x ** y; you save both the attribute lookup and the function call.
self.utility[theCar] = self.A * theCar.mpg ** self.alpha * theCar.hp ** self.beta * theCar.pc ** self.gamma
annnnnnd while we're here, let's get rid of the horizontal scroll-bar:
self.utility[theCar] = (self.A
* theCar.mpg ** self.alpha
* theCar.hp ** self.beta
* theCar.pc ** self.gamma)
A possibility that would require quite a rewrite of your existing code and may not help anyway (in Python) would be to avoid most of the power calculations by taking logs everywhere and working with log_utility = log_A + log_mpg * alpha ...

Categories

Resources