Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
Roland Wirth committed Nov 7, 2018
0 parents commit 67df1d7
Show file tree
Hide file tree
Showing 5 changed files with 829 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
270 changes: 270 additions & 0 deletions imsrg/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
import numpy as np

from collections import namedtuple
from .operator import Operator
from .ci import SDBasis, SDMatrix

# Copied and modified from https://rosettacode.org/wiki/Bernoulli_numbers
def magnus_coefficients():
from fractions import Fraction as Fr

A, m = [], 0
fct = 1
while True:
A.append(Fr(1, m+1))
for j in range(m, 0, -1):
A[j-1] = j*(A[j-1] - A[j])
yield (-1 if m == 1 else +1) * A[0]/fct # (which is Bm)
m += 1
fct *= m


def wegner_generator(href, hole_levels=None):
from numpy import ix_

holes, particles, hh_classifier, ph_classifier, pp_classifier = href.ref.classifiers(hole_levels)

hdiag0 = href.o0

hdiag1 = href.o1.copy()
hdiag1[ix_(holes, particles)] = 0.
hdiag1[ix_(particles, holes)] = 0.

hh_states = tuple( i for i, (p,q) in enumerate(href.basis.tpb) if hh_classifier(p,q) )
pp_states = tuple( i for i, (p,q) in enumerate(href.basis.tpb) if pp_classifier(p,q) )

hdiag2 = href.o2.copy()
hdiag2[ix_(hh_states, pp_states)] = 0.
hdiag2[ix_(pp_states, hh_states)] = 0.

hdiag = Operator(hdiag0, hdiag1, hdiag2, href.ref)

return hdiag.comm(href)

def white_generator(href, hole_levels=None):
from numpy import ix_

holes, particles, hh_classifier, ph_classifier, pp_classifier = href.ref.classifiers(hole_levels)

denom1 = _get_denom1(href, holes, particles)

gen0 = 0.

gen1 = np.zeros_like(href.o1)
gen1[ix_(particles, holes)] = href.o1[ix_(particles, holes)] / denom1
gen1 -= gen1.T

denom2, pp_states, hh_states = _get_denom2(href, hh_classifier, ph_classifier, pp_classifier)

gen2 = np.zeros_like(href.o2)
gen2[ix_(pp_states, hh_states)] = href.o2[ix_(pp_states, hh_states)] / denom2
gen2 -= gen2.T

gen = Operator(gen0, gen1, gen2, href.ref)

return gen


def mbpt2(href):
from itertools import product

hole_levels = set( lvl for i, (lvl, ud) in enumerate(href.basis.spb) if href.ref.gam1[i] > 0. )

holes, particles, hh_classifier, ph_classifier, pp_classifier = href.ref.classifiers(hole_levels)

DEpt2 = 0.
for (I, (p,r)), (J, (q,s)) in product(enumerate(href.basis.tpb), repeat=2):
if not (hh_classifier(p, r) and pp_classifier(q, s)):
continue
DEpt2 -= href.o2[I,J]**2/(href.o1[q,q] + href.o1[s,s] - href.o1[p,p] - href.o1[r,r])

return href.o0 + DEpt2


def _flow_rhs(generator, reference, hole_levels=None):
def rhs(s, y):
href = Operator.unpack(y, reference, symmetry='hermitian')
eta = generator(href, hole_levels)
dhds = eta.comm(href)
return dhds.pack(symmetry='hermitian')
return rhs


def _magnus_rhs(generator, href0, reference, hole_levels=None):
def rhs(s, y, href):
omega = Operator.unpack(y, reference, symmetry='antihermitian')
href = href0.bch(omega)
eta = generator(href, hole_levels)

domegads = eta.copy()
domegads_term = eta.copy()

coeffs = magnus_coefficients()
next(coeffs)

termnorm0 = domegads.norm()
termnorm = 1.
m = 1
while termnorm > 1e-6:
domegads_term = omega.comm(domegads_term)

coeff = next(coeffs)
if coeff != 0:
domegads += float(coeff) * domegads_term
termnorm = abs(float(coeff)) * domegads_term.norm() / termnorm0
print('Magnus: order = {}, coeff = {}, ||domega|| = {}, ||rem||_rel = {}'.format(m, coeff, domegads.norm(), termnorm))
m += 1

domegads.o0 = 0.
domegads.o1 = 1/2 * (domegads.o1 - domegads.o1.T)
domegads.o2 = 1/2 * (domegads.o2 - domegads.o2.T)

return domegads.pack(symmetry='antihermitian')
return rhs

def _get_denom1(href, holes, particles):
denom1 = np.diag(href.o1)[:,np.newaxis] - np.diag(href.o1)[np.newaxis, :]

for I, (p,q) in enumerate(href.basis.tpb):
if p in holes and q in particles:
denom1[q,p] -= href.o2[I,I]
elif p in particles and q in holes:
denom1[p,q] -= href.o2[I,I]

return denom1[np.ix_(particles, holes)]

def _get_denom2(href, hh_classifier, ph_classifier, pp_classifier):
hh_states = list( i for i, (p,q) in enumerate(href.basis.tpb) if hh_classifier(p,q) )
pp_states = list( i for i, (p,q) in enumerate(href.basis.tpb) if pp_classifier(p,q) )

denom = np.array([ href.o1[p,p] + href.o1[q,q] for p,q in href.basis.tpb ])

denom2 = denom[:,np.newaxis] - denom[np.newaxis,:] + np.diag(href.o2)[:,np.newaxis] + np.diag(href.o2)[np.newaxis,:]

for I in hh_states:
h1, h2 = href.basis.tpb[I]
for J in pp_states:
p1, p2 = href.basis.tpb[J]

K1, _ = href.basis.get_tpi(p1, h1)
K2, _ = href.basis.get_tpi(p2, h2)
K3, _ = href.basis.get_tpi(p1, h2)
K4, _ = href.basis.get_tpi(p2, h1)

denom2[J,I] -= href.o2[K1,K1] + href.o2[K2,K2] + href.o2[K3,K3] + href.o2[K4,K4]

return denom2[np.ix_(pp_states, hh_states)], pp_states, hh_states


IntegrateStats = namedtuple('IntegrateStats', 's fd E0 E2')

def integrate_direct(href0, s_max, generator, reference, step_monitor=None, convergence_check=None):
from scipy.integrate import ode

solver = ode(_flow_rhs(generator, reference))
solver.set_integrator('vode')
solver.set_initial_value(href0.pack(symmetry='hermitian'))

stats = IntegrateStats([], [], [], [])

sdbasis = SDBasis(reference.basis, reference.nparticles)

while solver.t < s_max:
y = solver.integrate(s_max, step=True)
href = Operator.unpack(y, reference, symmetry='hermitian')
Ept2 = mbpt2(href)

sdmatrix = SDMatrix(sdbasis, href.normalorder(reference.basis.vacuum))

stats.s.append(solver.t)
stats.fd.append(sdmatrix.eigenvalues())
stats.E0.append(href.o0)
stats.E2.append(Ept2)

if step_monitor:
step_monitor(href, stats)

if not solver.successful():
break

if convergence_check is not None and href.o0 - Ept2 < convergence_check:
break

return solver.successful(), href, stats


def integrate_magnus(href0, s_max, generator, reference, step_monitor=None, convergence_check=None):
from scipy.integrate import ode

solver = ode(_magnus_rhs(generator, href0, reference))
solver.set_integrator('vode', atol=1e-6)
solver.set_initial_value(Operator.zero(reference).pack(symmetry='antihermitian'))
solver.set_f_params(href0)

stats = IntegrateStats([], [], [], [])

sdbasis = SDBasis(reference.basis, reference.nparticles)

while solver.t < s_max:
y = solver.integrate(s_max, step=True)
omega = Operator.unpack(y, reference, symmetry='antihermitian')
href = href0.bch(omega)
solver.set_f_params(href)
Ept2 = mbpt2(href)

sdmatrix = SDMatrix(sdbasis, href.normalorder(reference.basis.vacuum))

stats.s.append(solver.t)
stats.fd.append(sdmatrix.eigenvalues())
stats.E0.append(href.o0)
stats.E2.append(Ept2)

if step_monitor:
step_monitor(href, stats)

if not solver.successful():
break

if convergence_check is not None and href.o0 - Ept2 < convergence_check:
break

return solver.successful(), omega, href, stats


def integrate_magnus_dopri(href0, s_max, generator, reference, step_monitor=None, convergence_check=None):
from scipy.integrate import ode

stats = IntegrateStats([], [], [], [])

sdbasis = SDBasis(reference.basis, reference.nparticles)

def solout(s, y):
nonlocal stats, sdbasis

omega = Operator.unpack(y, reference, symmetry='antihermitian')
href = href0.bch(omega)
Ept2 = mbpt2(href)

sdmatrix = SDMatrix(sdbasis, href.normalorder(reference.basis.vacuum))

stats.s.append(s)
stats.fd.append(sdmatrix.eigenvalues())
stats.E0.append(href.o0)
stats.E2.append(Ept2)

if step_monitor:
step_monitor(href, stats)

if convergence_check is not None and href.o0 - Ept2 < convergence_check:
return -1

solver = ode(_magnus_rhs(generator, href0, reference))
solver.set_integrator('dop853', max_step=0.1)
solver.set_solout(solout)
solver.set_initial_value(Operator.zero(reference).pack(symmetry='antihermitian'))
solver.set_f_params(href0)

y = solver.integrate(s_max)
omega = Operator.unpack(y, reference, symmetry='antihermitian')
href = href0.bch(omega)
return solver.successful(), omega, href, stats
97 changes: 97 additions & 0 deletions imsrg/ci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

import scipy.linalg as scila
import numpy as np

class Configuration:
def __init__(self, cf):
self.cf = tuple(cf)

def __len__(self):
return len(self.cf)
def __getitem__(self, key):
return self.cf[key]
def __iter__(self):
return iter(self.cf)

def max_coincidence(self, other):
nparticles = len(self)
if nparticles != len(other):
raise ValueError('Configurations must have the same number of particles')

common = []
d1 = []
d2 = []
phase = 1

for i, k in enumerate(self):
for j, l in enumerate(other):
if k == l:
p = len(common)
common.append(k)
phase *= (-1)**(i-p) * (-1)**(j-p)
break
else:
d1.append(k)
phase *= (-1)**(nparticles - len(d1) - i)

for j, l in enumerate(other):
if l not in common:
d2.append(l)
phase *= (-1)**(nparticles - len(d2) - j)

return common, d1, d2, phase


class SDBasis:
def __init__(self, basis, nparticles):
from itertools import combinations

def levels_to_comb(lvls):
comb = []
for l in lvls:
comb += [ 2*l, 2*l+1 ]
return comb

self.cfs = tuple( Configuration(levels_to_comb(lvls)) for lvls in combinations(range(basis.nspstates//2), nparticles//2) )
self.basis = basis
self.nparticles = nparticles

class SDMatrix:
def __init__(self, sdbasis, hvac):
from itertools import combinations

dim = len(sdbasis.cfs)
mat = np.zeros((dim, dim))

for I, cf1 in enumerate(sdbasis.cfs):
for J, cf2 in enumerate(sdbasis.cfs):
common, d1, d2, phase = cf1.max_coincidence(cf2)

me = 0.

d = len(d1)
if d > 2:
continue
elif d == 2:
(i,ph_i), (j, ph_j) = sdbasis.basis.get_tpi(*d1), sdbasis.basis.get_tpi(*d2)
me += ph_i * ph_j * phase * hvac.o2[i,j]
elif d == 1:
for q in common:
(i,ph_i), (j, ph_j) = sdbasis.basis.get_tpi(q, d1[0]), sdbasis.basis.get_tpi(q, d2[0])
me += ph_i * ph_j * phase * hvac.o2[i,j]
me += hvac.o1[d1[0],d2[0]]
else: # d == 0
for q, qq in combinations(common, 2):
i,ph_i = sdbasis.basis.get_tpi(q, qq)
me += phase * ph_i**2 * hvac.o2[i,i]
for q in common:
me += phase * hvac.o1[q,q]
me += hvac.o0

if me != 0.:
mat[I,J] = me

self.cfmat = mat

def eigenvalues(self):
return scila.eigvalsh(self.cfmat)
Loading

0 comments on commit 67df1d7

Please sign in to comment.