Fourier Transform

Any ideas on how to code a Fourier transform to momentum space like the example below.

$$\partial_{i}{A} \partial_{j}{B_{i j}} C \rightarrow -k1_{i} A(k1) k2_{j} B(k2)_{i j} C(k3)$$

I assume I will need to convert expression to a Python string and manipulate it their and convert back.

edited

+1 vote

I have checked in some experimental functionality to modify the expression tree from Python. If you pull the latest from github, your Fourier transform can now be done with

\partial{#}::PartialDerivative;
ex:=A_{m n} \partial_{r}{ B_{p q} } \partial_{s}{ C } ;
for prod in ex["\\prod"]:
num=1
for factor in prod.children():
if factor.name=="\\partial":
for index in factor.indices():
k = Ex("k"+str(num)+"_{"+index.name+"}")
factor.insert(k)
for arg in factor.args():
arg.append_child(Ex("k"+str(num)))
factor.insert(arg)
factor.erase()
else:
factor.append_child(Ex("k"+str(num)))
num+=1

It could use some additional functionality to work on single-factor terms and perhaps some other edge cases, but it's a start (and I'm out of time to work on this until 2.2.0 is out).

I hope this is sufficiently self-explanatory, but feel free to ask if it is not clear. Please keep in mind that this is subject to change slightly in future updates; I haven't yet settled on the interface completely yet. Feedback more than welcome!

by (65.1k points)

Sorry, the example is not quite what you wrote, but I guess you can modify as required.

Thanks so much for creating this functionality. I tested it on my expressions and it worked as expected.

When you have time I would love to learn a little more about the structure of how this works. Maybe it is just a mapping of your new items to "tree(ex)" elements. Not sure how I access them directly

Also, when I use it on terms like

a**2 h_{i j} A \phi \varphi

it knows not to transform the a**2 terms. That is correct. But I don't see in your code how it knows this. Also, a small issue in expressions like this is that you get

a2 h_{i j}(k2) A(k3) \phi(k4) \varphi(k5) i.e. starts at k2 not k1, probably because of no k1 for a2

Also, sometimes terms like \phi are converted to \phi(k1) in some my tests on your code, and sometimes not. As you will see in my code below I create a list of terms that should not be converted -- an easy addition.

Before I received your updated code I create this (long) bunch of procedures to parse through the Cadabra expression as a string and convert it to momentum space. Obviously your solution is much cleaner.

Thanks again.

Here is my code. I am sure it can be improved on (although there is no need at this point).

NoMom list contains items that are not to be transformed to momentum space

NoMom= ["XXXkappa","(XXXkappa)(-2)","(a)4", "(a)2","a","XXXphi","(XXXphi)2","V(XXXphi)", "V'(XXXphi)", "V''(XXXphi)", "V^{\prime\prime\prime}(XXXphi)","V^{\prime\prime\prime\prime}(XXXphi)", "\partial_{0}{XXXphi}"];

Variable ex is String form

def ExtNum(ex): ex_num = re.findall("^\s" + "[-]?" + "\s" + "\d+" + ".?/?" + "\d",ex) if( len(ex_num) == 0): signcheck = re.findall("^\s" + "[-]",ex) if (len(signcheck) != 0): ex_num = "-1" else:
ex_num = "1" return ex_num[0]

Variable ex is String form

def ExtDer(ex): exder = re.findall("\\partial{[^(]" + "$[^\(]$", ex) if( len(ex_der) == 0): ex_der = " " return ex_der[0]

Variable ex is String form

def ParReg(ex): reg_List = ex.split() for i in range(0,len(reg_List)): if(i >= len(reg_List)-1): break match = re.search("\{*\}",reg_List[i]) if( "{" in reg_List[i] and not match): reg_List[i] = reg_List[i] + " " + reg_List[i+1] del reg_List[i+1] return reg_List

Variable ex is String form

def MomReg(ex,knum): res = ex if( ex not in NoMom): res = ex + "(k" + str(knum+1) + ")" knum = knum +1 return res,knum

FIX counter for NoMom case

def MomDer(ex,knum): ex_len = len(ex) kterm = " k" + str(knum+1) term_tmp = ""
for j in range(0,ex_len - 1): term_tmp = termtmp + "I " + kterm + "{" + str(ex[j]) + "}"
if (str(ex[ex_len -1]) not in NoMom): term_result = term_tmp + " " + str(ex[ex_len-1]) + "(" + kterm + ")" else: term_result = term_tmp + " " + str(ex[ex_len-1]) return term_result

Fix for length of only one term

def ToMomem(exFull): distribute(exFull) expand_power(exFull) substitute(exFull, $a a a a -> a4, a a -> a2$) substitute(exFull,$\phi -> XXXphi, \varphi -> VVVV$) result = Ex(0)

for i in range(0, len(exFull)): term = str(exFull[i]) k_count =0 subterm = str("") num = ExtNum(term) term = term.replace(num," ") while ("\partial" in term): div_term = ExtDer(term) term = term.replace(div_term," ",1) if(div_term != " "):
subterm = " ".join([subterm, MomDer(Ex(div_term),k_count)]) k_count= k_count +1 regList = ParReg(term) for j in range(0, len(regList)): regList[j] tmp = MomReg(regList[j],k_count) subterm = " ".join([subterm,tmp[0]]) k_count = tmp[1] result = result + Ex(num + subterm) substitute(result,$VVVV(A?) ->\varphi(A?), XXXphi -> \phi$,repeat = True) return result

Another couple issues to fix in the future,

For an expression like

2.3 B{i} B{j} + h_{i j}

This was returned

2.3(k1} B{i}(k2} B{j} (k3) + h_{i j}

Problem with some constants and single terms -- I guess because you are picking out the "prod" head, as you mentioned.

+1 vote

Well I took a crack at coming up with a procedure to transform an expression to momentum space. I am not sure if proper indentation will show up in my posting.

I need to add a few more lines of code to allow the exclusion of the conversion of some variables in an expression to momentum space. The procedure below converts all terms.

I::ImaginaryI;

# Procedure coverts expression "exFull" to Momentum Space

def Momem(exFull):
result = Ex(0)
for ct in range(0,len(exFull)):
ex = exFull[ct]
sign= 1
if(str(ex)[0] == "-"):
sign = -1
len_ex = len(ex)
if (len_ex ==0):
result_trm = Ex( str(ex)+ "( k1 )")
else:
res_tmp = ""
for i in range(0,len_ex):
term = ex[i]
kterm = " k" + str(i+1)
len_term = len(term)
term_tmp =""
for j in range(0,len_term-1):
term_tmp = term_tmp + "I " + kterm + "_{" + str(term[j]) +"}"
term_result = term_tmp + " " + str(term[len_term-1]) + "("  + kterm + ")"
else:
term_result = str(term)+ "("  + kterm + ")"
res_tmp = res_tmp + term_result
result_trm = Ex(res_tmp)
if(sign== 1):
result = result +  result_trm
else:
result = result -  result_trm
return result

# Testing:

exFull:= A - \partial_{i}{\partial_{k}{VE_{k}}} h h h_{i}
+ \partial_{i}{C} \partial_{0}{VB_{k}} h_{i} h_{k} h
+ \partial_{0}    {\partial_{i}{AA}} VB_{i} h h
- \partial_{i}{\partial_{k}{CC}} \partial_{j}{VB_{i}} h_{j} h_{k}
- B h;
Momem(_);
type(_);

$${}A-\partial_{i k}\left(VE_{k}\right) h h h_{i}+\partial_{i}{C} \partial_{0}\left(VB_{k}\right) h_{i} h_{k} h+\partial_{0 i}\left(AA\right) VB_{i} h h-\partial_{i k}\left(CC\right) \partial_{j}\left(VB_{i}\right) h_{j} h_{k}-B h$$

$${}A\left(k1\right)+k1_{i} k1_{k} VE_{k}\left(k1\right) h\left(k2\right) h\left(k3\right) h_{i}\left(k4\right)-k1_{i} C\left(k1\right) k2_{0} VB_{k}\left(k2\right) h_{i}\left(k3\right) h_{k}\left(k4\right) h\left(k5\right)-k1_{0} k1_{i} AA\left(k1\right) VB_{i}\left(k2\right) h\left(k3\right) h\left(k4\right)+k1_{i} k1_{k} CC\left(k1\right) I k2_{j} VB_{i}\left(k2\right) h_{j}\left(k3\right) h_{k}\left(k4\right)-B\left(k1\right) h\left(k2\right)$$

<class 'cadabra2.Ex'>
by (520 points)