Skip to content

Instantly share code, notes, and snippets.

@ngraymon
Created June 8, 2022 20:32
Show Gist options
  • Save ngraymon/efd7b55a0e57c32b6d6c5e2a13c76d10 to your computer and use it in GitHub Desktop.
Save ngraymon/efd7b55a0e57c32b6d6c5e2a13c76d10 to your computer and use it in GitHub Desktop.
Original approach to VECI/MIXEDCC/VECC residual terms
VECI condensed latex
\textbf{R}_{0} &= \bh_0 + \bh_1\bt^{1} + \bh_2\bt^{2} \\
%
\textbf{R}_{1} &= \bh^1 + (\bh_0 + \bh^1_1)\bt^{1} + \bh_1\bt^{2} + \bh_2\bt^{3} \\
%
\textbf{R}_{2} &= \bh^2 + \bh^1\bt^{1} + (\bh_0 + \bh^1_1)\bt^{2} + \bh_1\bt^{3} + \bh_2\bt^{4} \\
%
\textbf{R}_{3} &= \bh^2\bt^{1} + \bh^1\bt^{2} + (\bh_0 + \bh^1_1)\bt^{3} + \bh_1\bt^{4} + \bh_2\bt^{5}
VECI explicit latex
\begin{split} \textbf{R}_{0} &=
\bh_0 +
\bh_{k_1}\bt^{k_1} +
\left(\dfrac{1}{2!}\right)\bh_{k_1,k_2}\bt^{k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1} &=
\bh^{i_1} +
\bh_0\bt^{i_1} +
\bh^{i_1}_{k_1}\bt^{k_1} +
\bh_{k_1}\bt^{i_1,k_1} +
\left(\dfrac{3}{3!}\right)\bh_{k_1,k_2}\bt^{i_1,k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2} &=
\left(\dfrac{1}{2}\right)\bh^{i_1,i_2} +
\bh^{i_1}\bt^{i_2} +
\left(\dfrac{1}{2!}\right)\bh_0\bt^{i_1,i_2} +
\bh^{i_1}_{k_1}\bt^{i_2,k_1} +
\left(\dfrac{3}{3!}\right)\bh_{k_1}\bt^{i_1,i_2,k_1} +
\left(\dfrac{6}{4!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2, i_3} &=
\left(\dfrac{1}{2}\right)\bh^{i_1,i_2}\bt^{i_3} +
\left(\dfrac{1}{2!}\right)\bh^{i_1}\bt^{i_2,i_3} +
\left(\dfrac{1}{3!}\right)\bh_0\bt^{i_1,i_2,i_3} +
\left(\dfrac{3}{3!}\right)\bh^{i_1}_{k_1}\bt^{i_2,i_3,k_1} +
\left(\dfrac{4}{4!}\right)\bh_{k_1}\bt^{i_1,i_2,i_3,k_1} +
\left(\dfrac{10}{5!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,i_3,k_1,k_2} \end{split}
VECI/CC wave operator latex
\bw^{2} &= \bt^{2} + \bc^{2} & \bw^{3} &= \bt^{3} + \bc^{3} + \bc^{1}\bt^{2} & \\
\bw^{2} &= \bt^{2} + \textbf{d}^{2} & \bw^{3} &= \bt^{3} + \textbf{d}^{3} &
VECI/CC mixed condensed latex
\textbf{R}_{0} &= \bh_0 + \bh_1\bw^{1} + \bh_2\bw^{2} \\
%
\textbf{R}_{1} &= \bh^1 + (\bh_0 + \bh^1_1)\bw^{1} + \bh_1\bw^{2} + \bh_2(\bt^{3} + \bd^{3}) \\
%
\textbf{R}_{2} &= \bh^2 + \bh^1\bw^{1} + (\bh_0 + \bh^1_1)\bw^{2} + \bh_1(\bt^{3} + \bd^{3}) + \bh_2(\bt^{4} + \bd^{4}) \\
%
\textbf{R}_{3} &= \bh^2\bw^{1} + \bh^1\bw^{2} + (\bh_0 + \bh^1_1)(\bt^{3} + \bd^{3}) + \bh_1(\bt^{4} + \bd^{4}) + \bh_2(\bt^{5} + \bd^{5})
VECI/CC mixed explicit latex
\begin{split} \textbf{R}_{0} &=
\bh_0 +
\bh_{k_1}\bw^{k_1} +
\left(\frac{1}{2!}\right)\bh_{k_1,k_2}\bw^{k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1} &=
\bh^{i_1} +
\bh_0\bw^{i_1} +
\bh^{i_1}_{k_1}\bw^{k_1} +
\bh_{k_1}\bw^{i_1,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1,k_2}\bt^{i_1,k_1,k_2} +
\left(\frac{3}{3!}\right)\bh_{k_1,k_2}\bd^{i_1,k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2} &=
\left(\frac{1}{2}\right)\bh^{i_1,i_2} +
\bh^{i_1}\bw^{i_2} +
\left(\frac{1}{2!}\right)\bh_0\bw^{i_1,i_2} +
\bh^{i_1}_{k_1}\bw^{i_2,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1}\bt^{i_1,i_2,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1}\bd^{i_1,i_2,k_1} +
\left(\frac{6}{4!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,k_1,k_2} +
\left(\frac{6}{4!}\right)\bh_{k_1,k_2}\bd^{i_1,i_2,k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2, i_3} &=
\left(\frac{1}{2}\right)\bh^{i_1,i_2}\bw^{i_3} +
\left(\frac{1}{2!}\right)\bh^{i_1}\bw^{i_2,i_3} +
\left(\frac{1}{3!}\right)\bh_0\bt^{i_1,i_2,i_3} +
\left(\frac{1}{3!}\right)\bh_0\bd^{i_1,i_2,i_3} +
\left(\frac{3}{3!}\right)\bh^{i_1}_{k_1}\bt^{i_2,i_3,k_1} +
\left(\frac{3}{3!}\right)\bh^{i_1}_{k_1}\bd^{i_2,i_3,k_1} +
\left(\frac{4}{4!}\right)\bh_{k_1}\bt^{i_1,i_2,i_3,k_1} +
\left(\frac{4}{4!}\right)\bh_{k_1}\bd^{i_1,i_2,i_3,k_1} +
\left(\frac{10}{5!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,i_3,k_1,k_2} +
\left(\frac{10}{5!}\right)\bh_{k_1,k_2}\bd^{i_1,i_2,i_3,k_1,k_2} \end{split}
VECC wave operator latex
\bw^{2} &= \bt^{2} + \bc^{2} & \bw^{3} &= \bt^{3} + \bc^{3} + \bc^{1}\bt^{2} & \\
\bw^{2} &= \bt^{2} + \textbf{d}^{2} & \bw^{3} &= \bt^{3} + \textbf{d}^{3} &
VECC condensed latex
\textbf{R}_{0} &= \bh_0 + \bh_1\bw^{1} + \bh_2\bw^{2} \\
%
\textbf{R}_{1} &= \bh^1 + (\bh_0 + \bh^1_1)\bw^{1} + \bh_1\bw^{2} + \bh_2(\bt^{3} + \bd^{3}) \\
%
\textbf{R}_{2} &= \bh^2 + \bh^1\bw^{1} + (\bh_0 + \bh^1_1)\bw^{2} + \bh_1(\bt^{3} + \bd^{3}) + \bh_2(\bt^{4} + \bd^{4} + \bt^{2}\bt^{2}) \\
%
\textbf{R}_{3} &= \bh^2\bw^{1} + \bh^1\bw^{2} + (\bh_0 + \bh^1_1)(\bt^{3} + \bd^{3}) + \bh_1(\bt^{4} + \bd^{4} + \bt^{2}\bt^{2}) + \bh_2(\bt^{5} + \bd^{5} + \bt^{2}\bt^{2}\bt^{1} + \bt^{3}\bt^{2})
VECC explicit latex
\begin{split} \textbf{R}_{0} &=
\bh_0 +
\bh_{k_1}\bw^{k_1} +
\left(\frac{1}{2!}\right)\bh_{k_1,k_2}\bw^{k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1} &=
\bh^{i_1} +
\bh_0\bw^{i_1} +
\bh^{i_1}_{k_1}\bw^{k_1} +
\bh_{k_1}\bw^{i_1,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1,k_2}\bt^{i_1,k_1,k_2} +
\left(\frac{3}{3!}\right)\bh_{k_1,k_2}\bd^{i_1,k_1,k_2} \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2} &=
\left(\frac{1}{2}\right)\bh^{i_1,i_2} +
\bh^{i_1}\bw^{i_2} +
\left(\frac{1}{2!}\right)\bh_0\bw^{i_1,i_2} +
\bh^{i_1}_{k_1}\bw^{i_2,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1}\bt^{i_1,i_2,k_1} +
\left(\frac{3}{3!}\right)\bh_{k_1}\bd^{i_1,i_2,k_1} +
\left(\frac{6}{4!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,k_1,k_2} +
\left(\frac{6}{4!}\right)\bh_{k_1,k_2}\bd^{i_1,i_2,k_1,k_2} +
\bh_{k_1,k_2}\left[\bt^{2}\bt^{2}\right] \end{split} \\
%
\begin{split} \textbf{R}_{i_1, i_2, i_3} &=
\left(\frac{1}{2}\right)\bh^{i_1,i_2}\bw^{i_3} +
\left(\frac{1}{2!}\right)\bh^{i_1}\bw^{i_2,i_3} +
\left(\frac{1}{3!}\right)\bh_0\bt^{i_1,i_2,i_3} +
\left(\frac{1}{3!}\right)\bh_0\bd^{i_1,i_2,i_3} +
\left(\frac{3}{3!}\right)\bh^{i_1}_{k_1}\bt^{i_2,i_3,k_1} +
\left(\frac{3}{3!}\right)\bh^{i_1}_{k_1}\bd^{i_2,i_3,k_1} +
\left(\frac{4}{4!}\right)\bh_{k_1}\bt^{i_1,i_2,i_3,k_1} +
\left(\frac{4}{4!}\right)\bh_{k_1}\bd^{i_1,i_2,i_3,k_1} +
\bh_{k_1}\left[\bt^{2}\bt^{2}\right] +
\left(\frac{10}{5!}\right)\bh_{k_1,k_2}\bt^{i_1,i_2,i_3,k_1,k_2} +
\left(\frac{10}{5!}\right)\bh_{k_1,k_2}\bd^{i_1,i_2,i_3,k_1,k_2} +
\bh_{k_1,k_2}\left[\bt^{2}\bt^{2}\bt^{1}\right] +
\bh_{k_1,k_2}\left[\bt^{3}\bt^{2}\right] \end{split}
# system imports
# import os
import math
import sys
import itertools as it
from collections import namedtuple
# third party imports
import numpy as np
# local imports
import reference_latex_headers as headers
# define
tab_length = 4
tab = " "*tab_length
# use these if we define \newcommand to map textbf to \bt and so forth
if True:
bold_t_latex = "\\bt"
bold_h_latex = "\\bh"
bold_w_latex = "\\bw"
bold_c_latex = "\\bc"
bold_d_latex = "\\bd"
bold_z_latex = "\\bz"
bold_s_latex = "\\bs"
bold_G_latex = "\\bG"
else:
bold_t_latex = "\\textbf{t}"
bold_h_latex = "\\textbf{h}"
bold_w_latex = "\\textbf{w}"
bold_c_latex = "\\textbf{c}"
bold_d_latex = "\\textbf{d}"
bold_z_latex = "\\textbf{z}"
bold_s_latex = "\\textbf{s}"
bold_G_latex = "\\textbf{G}"
# ----------------------------------------------------------------------------------------------- #
# ------------------------------- NAMED TUPLES DEFINITIONS ------------------------------------ #
# ----------------------------------------------------------------------------------------------- #
# the building blocks for the h & w components of each residual term are stored in named tuples
# rterm_namedtuple = namedtuple('rterm_namedtuple', ['prefactor', 'h', 'w'])
# we originally defined a class so that we can overload the `__eq__` operator
# because we needed to compare the rterm tuples, however I think I might have removed that code
# check if we even need the class anymore
class residual_term(namedtuple('residual_term', ['prefactor', 'h', 'w'])):
__slots__ = ()
#
def __eq__(self, other_term):
return bool(
self.prefactor == other_term.prefactor and
np.array_equal(self.h, other_term.h) and
np.array_equal(self.w, other_term.w)
)
# tuple for a general operator as described on page 1, eq 1
general_operator_namedtuple = namedtuple('operator', ['name', 'rank', 'm', 'n'])
# connected_namedtuple = namedtuple('connected', ['name', 'm', 'n'])
# linked_namedtuple = namedtuple('linked', ['name', 'm', 'n'])
# unlinked_namedtuple = namedtuple('unlinked', ['name', 'm', 'n'])
hamiltonian_namedtuple = namedtuple('hamiltonian', ['maximum_rank', 'operator_list'])
"""rather than just lists and dictionaries using namedtuples makes the code much more concise
we can write things like `h.max_i` instead of `h[0]` and the label of the member explicitly
describes what value it contains making the code more readable and user friendly """
h_namedtuple = namedtuple('h_term', ['max_i', 'max_k'])
w_namedtuple = namedtuple('w_term', ['max_i', 'max_k', 'order'])
# used in building the W operators
t_term_namedtuple = namedtuple('t_term_namedtuple', ['string', 'order', 'shape'])
# ----------------------------------------------------------------------------------------------- #
# ------------------------------------ HELPER FUNCTIONS --------------------------------------- #
# ----------------------------------------------------------------------------------------------- #
def unique_permutations(iterable):
"""Return a sorted list of unique permutations of the items in some iterable."""
return sorted(list(set(it.permutations(iterable))))
def build_symmetrizing_function(max_order=5, show_perm=False):
""" x """
string = ""
string += (
f"\ndef symmetrize_tensor(tensor, order):\n"
f"{tab}'''Symmetrizing a tensor (the W operator or the residual) by tracing over all permutations.'''\n"
f"{tab}X = np.zeros_like(tensor, dtype=complex)\n"
)
string += (
f"{tab}if order == 0:\n"
f"{tab}{tab}return tensor\n"
f"{tab}if order == 1:\n"
f"{tab}{tab}return tensor\n"
)
for n in range(2, max_order+1):
string += f"{tab}if order == {n}:\n"
for p in it.permutations(range(2, n+2)):
string += f"{tab}{tab}X += np.transpose(tensor, {(0,1) + p})\n"
string += f"{tab}return X\n"
return string
def print_residual_data(R_lists, term_lists, print_equations=False, print_tuples=False):
"""Print to stdout in a easily readable format the residual terms and term tuples."""
if print_equations:
for i, R in enumerate(R_lists):
print(f"{'':-<30} R_{i} {'':-<30}")
for a in R:
print(f"{tab} - {a}")
print(f"{'':-<65}\n{'':-<65}\n")
if print_tuples:
for i, terms in enumerate(term_lists):
print(f"{'':-<30} R_{i} {'':-<30}")
for term in terms:
print(f"{tab} - {term}")
print(f"{'':-<65}\n{'':-<65}\n")
return
def _partitions(number):
"""Return partitions of n. See `https://en.wikipedia.org/wiki/Partition_(number_theory)`"""
answer = set()
answer.add((number,))
for x in range(1, number):
for y in _partitions(number - x):
answer.add(tuple(sorted((x, ) + y, reverse=True)))
return sorted(list(answer), reverse=True)
def generate_partitions_of_n(n):
"""Return partitions of n. Such as (5,), (4, 1), (3, 1, 1), (2, 2, 1) ... etc."""
return _partitions(n)
def generate_mixed_partitions_of_n(n):
"""Return partitions of n that include at most one number greater than 1.
Such as (5,), (4, 1), (3, 1, 1), (2, 1, 1, 1) ... etc, but not (3, 2) or (2, 2, 1)
"""
return [p for p in _partitions(n) if n - max(p) + 1 == len(p)]
def genereate_connected_partitions_of_n(n):
"""Return partitions of n which are only comprised of 1's.
Such as (1, 1), or (1, 1, 1). The max value should only ever be 1.
"""
return tuple([1]*n)
def generate_linked_disconnected_partitions_of_n(n):
"""Return partitions of n that include at most one number greater than 1 and not `n`.
Such as (4, 1), (3, 1, 1), (2, 1, 1, 1) ... etc, but not (5,), (3, 2), (2, 2, 1)
"""
return [p for p in _partitions(n) if n - max(p) + 1 == len(p) and max(p) < n]
def generate_un_linked_disconnected_partitions_of_n(n):
"""Return partitions of n that represent the unlinked disconnected wave operator parts.
Such as (3, 2), (2, 2, 1) ... etc, but not (5,), (4, 1), (3, 1, 1), (2, 1, 1, 1)
"""
new_set = set(_partitions(n)) - set(generate_mixed_partitions_of_n(n))
return sorted(list(new_set), reverse=True)
# ----------------------------------------------------------------------------------------------- #
# -------------------------------- GENERATING RESIDUAL DATA ----------------------------------- #
# ----------------------------------------------------------------------------------------------- #
def generate_hamiltonian_operator(maximum_h_rank=2):
"""Return a `hamiltonian_namedtuple`.
It contains an `operator_list` of namedtuples for each term that looks like equation 6 based on `maximum_h_rank`
(which is the sum of the ranks (m,n)).
Equation 6 is a Hamiltonian with `maximum_h_rank` of 2
"""
return_list = []
for m in range(maximum_h_rank + 1): # m is the upper label
for n in range(maximum_h_rank + 1 - m): # n is the lower label
if m == 0 and n == 0:
h_operator = general_operator_namedtuple("h_0", 0, 0, 0)
elif m == 0:
h_operator = general_operator_namedtuple(f"h_{n}", 0+n, 0, n)
elif n == 0:
h_operator = general_operator_namedtuple(f"h^{m}", m+0, m, 0)
else:
h_operator = general_operator_namedtuple(f"h^{m}_{n}", m+n, m, n)
return_list.append(h_operator)
return hamiltonian_namedtuple(maximum_h_rank, return_list)
# ------------- constructing the prefactor -------------- #
def extract_numerator_denominator_from_string(s):
"""Return the number part of the numerator and denominator
from a string (s) of a fraction w factorial in denominator part.
"""
if "*" in s: # we are only trying to get the first fraction
s = s.split('*')[0]
# print(s)
numer, denom = s.replace('(', '').replace(')', '').split(sep="/")
denom = denom.split(sep='!')[0]
# print(f"numer: {numer} denom: {denom}")
return [int(numer), int(denom)]
def simplified_prefactor(pre):
"""Creates the simplified form of the given prefactor f."""
arr = extract_numerator_denominator_from_string(pre)
numerator, denominator = arr[0], arr[1]
if pre == "*(1/2)": # case when 1/2 is the only prefactor, delete * sign
pre = "1/2"
elif denominator == numerator:
# case when (1/1!) or (2/2!) is present, which will both be recognized as 1
if "*(1/2)" in pre:
if denominator == 1 or denominator == 2:
pre = "(1/2)" # 1*(1/2) = (1/2)
else:
pre = f"({numerator}/(2*{denominator}))"
else:
if denominator == 1 or denominator == 2:
pre = "" # use empty string to represent 1
# case when 1/2 is multiplied to the prefactor
elif "*(1/2)" in pre:
if numerator % 2 == 0:
pre[0] = str(numerator // 2)
pre = pre[:-6] # get rid of "*(1/2)"
else:
pre = pre[:3] + "(2*" + pre[3:-6] + ")" # add "2*" to the front of the denominator
return pre
def construct_prefactor(h, p, simplify_flag=False):
"""Creates the string for the prefactor of the tensor h.
Returns condensed fraction by default.
If `simplify_flag` is true it reduces the fraction using the gcf(greatest common factor).
If the prefactor is equal to 1 or there is no prefactor then returns an empty string.
"""
# is there a 'master' equations / a general approach for any number of i's / k's
# Should be able to simplify down to 3 cases? maybe?
# case 1 - only 1 k, any number of i's or only 1 i, any number of k's
# case 2 - 2 or more k's AND 2 or more i's
# case 3 - only i or only k presents
if h.m > p:
return ""
prefactor = ""
i_number_w = p - h.m
total_number_w = p - h.m + h.n
# special case when there is no w operator and h^2 doesn't present
if total_number_w == 0:
if h.m == 2:
return "(1/2)"
else:
return ""
# case 1. when there is only 1 k or i label on w operator
if i_number_w == 1 or h.n == 1:
prefactor = f"({total_number_w}/{total_number_w}!)" # needs simplification: n/n! = 1/(n-1)
# case 2. when 2 or more k's AND 2 or more i's on w
elif h.n > 1 and i_number_w > 1:
prefactor += f"({sum(x for x in range(total_number_w))}/{total_number_w}!)"
# case 3. when only i or only k presents on w operator
elif h.n == 0 or i_number_w == 0:
prefactor += f"(1/{total_number_w}!)"
# special case: when h^2 is included, 1/2 needs to be multiplies to the term
if h.m == 2:
prefactor += "*(1/2)"
# if simplification is needed
if simplify_flag: # call simplification step
prefactor = simplified_prefactor(prefactor)
return prefactor
# ---- construct string labels for each residual term --- #
def construct_upper_w_label(h, p):
"""Creates the string for the "upper" labels of the tensor w.
Returns `^{str}` if there are upper labels
Otherwise returns an empty string
"""
if (h.m == p and h.n == 0) or h.m > p: # case when there is no w operator needed
return ""
w_label = "^{" # if w operator exist, initialize w_label
for a in range(h.m+1, p+1): # add i_p
w_label += f"i_{a},"
for b in range(1, h.n+1): # add k_h
w_label += f"k_{b},"
assert w_label != "^{", "Whoops you missed a case, check the logic!!!"
w_label = w_label[:-1] + "}" # delete extra comma and add close bracket
return w_label
def construct_upper_h_label(h, p):
"""Creates the string for the "upper" labels of the tensor h.
Returns `^{str}` if there are upper labels
Otherwise returns an empty string
"""
if h.m == 0 or h.m > p: # case when there is no upper i label or no proper h operator
return ""
upper_h_result = "^{" # initialize the return string if upper label exist (m!=0)
for c in range(1, h.m+1):
upper_h_result += f"i_{c},"
upper_h_result = upper_h_result[:-1] + "}" # delete extra comma and add close bracket
return upper_h_result
def construct_lower_h_label(h, p):
"""Creates the string for the "lower" labels of the tensor h.
Returns `_{str}` if there are lower labels
Otherwise returns an empty string
"""
# case when h_o presents
if h.m == 0 and h.n == 0:
return "_0"
# case when h operator doesn't have lower label
if h.n == 0 or h.m > p:
return ""
# initialize the return string if lower label exist (n!=0)
lower_h_result = "_{"
for d in range(1, h.n+1):
lower_h_result += f"k_{d},"
lower_h_result = lower_h_result[:-1] + "}"
return lower_h_result
# ------- constructing individual residual terms -------- #
def generate_p_term(str_fac):
"""Generate a floating point number calculated by the fraction in the input string fac_str"""
# check if the prefactor is 1
if str_fac == "":
return "1.0"
if str_fac == "(1/2) * ":
return "0.5"
arr = extract_numerator_denominator_from_string(str_fac)
numerator, denominator = arr[0], arr[1]
if "/(2*" in str_fac:
return ("(" + str(numerator) + "/(2*" + str(math.factorial(denominator)) + "))")
else:
return ("(" + str(numerator) + "/" + str(math.factorial(denominator)) + ")")
def generate_h_term(str_h):
"""Generate an h_namedtuple; contains max_i and max_k of h operator"""
if "0" in str_h:
# special case for h_0
return h_namedtuple(0, 0)
return h_namedtuple(str_h.count("i"), str_h.count("k"))
def generate_w_term(str_w):
"""Generate an w_namedtuple; contains max_i and max_k of w operator"""
if str_w == "":
# if there is no w operator, return [0,0,0]
return w_namedtuple(0, 0, 0)
max_i = str_w.count("i")
max_k = str_w.count("k")
return w_namedtuple(max_i, max_k, max_i+max_k)
# ------------------------------------------------------- #
# ----------------------------------------------------------------------------------------------- #
# ------------------------------- GENERATING RESIDUAL LATEX ----------------------------------- #
# ----------------------------------------------------------------------------------------------- #
# ----------------- generating VECI residual latex -------------------- #
def _generate_veci_explicit_latex_term(term_list, h_list, w_string, order):
"""Generate the latex for the residual equations including all the indices and factors."""
for h in h_list:
h_string = bold_h_latex
h_string += construct_upper_h_label(h, order)
h_string += construct_lower_h_label(h, order)
# no W operator
if (h.m == order and h.n == 0) or h.m > order:
w_string = ""
# 1 W operator
else:
w_string = bold_t_latex + construct_upper_w_label(h, order)
prefactor = construct_prefactor(h, order, True)
if prefactor != "":
numerator, denominator = prefactor[1:-1].split('/')
prefactor = f"\\left(\\dfrac{{{numerator}}}{{{denominator}}}\\right)"
# save the string representation of the term
# print(prefactor + h_string + w_string)
term_list.append(prefactor + h_string + w_string)
return
def _generate_veci_condensed_latex_term(term_list, h_list, w_string):
"""Append a string representation of a summation term for a residual to `term_list`."""
if len(h_list) == 1:
h_string = h_list[0].name.replace('h', bold_h_latex)
else:
bold_h_list = [h.name.replace('h', bold_h_latex) for h in h_list]
h_string = f"({' + '.join(bold_h_list)})"
# save the string representation of the term
term_list.append(h_string + w_string)
return
def _generate_veci_latex_form(hamiltonian, order, max_order, explicit=False):
"""Generate the VECI latex for the residual equations.
Default is to generate the condensed form, but if `explicit` flag is `True` then
explicit form with all i and k terms and prefactors is returned.
"""
w_range = list(range(0, order + hamiltonian.maximum_rank + 1))
# generate a list of H terms of equal or lower order than the residual
operators = []
for h in hamiltonian.operator_list:
if h.m <= order:
operators.append(h)
# generate each term we need to sum over
term_list = []
for n in w_range:
# create the w string
w_string = f"{bold_t_latex}^{{{n}}}" if n != 0 else ""
h_list = []
# collect h terms that map to w^n
for i, h in enumerate(operators):
if abs(h.m - h.n - order) == n:
h_list.append(h)
operators.pop(i)
# if no terms we skip this W operator
if len(h_list) == 0:
continue
# append all term strings to `term_list`
if explicit:
_generate_veci_explicit_latex_term(term_list, h_list, w_string, order)
# _generate_mixedcc_explicit_latex_term(term_list, h_list, w_list, order, expand_order_n_w)
else:
_generate_veci_condensed_latex_term(term_list, h_list, w_string)
# _generate_mixedcc_condensed_latex_term(term_list, h_list, w_list)
# loop
# return the full string (with prefix and all term's wrapped in plus symbols)
if explicit:
i_terms = ", ".join([f"i_{n}" for n in range(1, order+1)]) if order != 0 else "0"
return_string = f"\\begin{{split}} \\textbf{{R}}_{{{i_terms}}} &=\n" + " +\n".join(term_list) + " \\end{split}"
return return_string
else:
return_string = f"\\textbf{{R}}_{{{order}}} &= " + " + ".join(term_list)
return return_string
def _generate_veci_latex(hamiltonian, max_order):
"""Generate all of the VECI latex equations.
We use `join` to insert two backward's slashes \\ BETWEEN each line
rather then adding them to end and having extra trailing slashes on the last line.
The user is expected to manually copy the relevant lines from the text file into a latex file
and generate the pdf themselves.
"""
return_string = "" # store it all in here
return_string += "VECI condensed latex\n"
return_string += ' \\\\\n%\n'.join([_generate_veci_latex_form(hamiltonian, order, max_order) for order in range(max_order+1)])
return_string += "\n"*4
return_string += "VECI explicit latex\n"
return_string += ' \\\\\n%\n'.join([_generate_veci_latex_form(hamiltonian, order, max_order, explicit=True) for order in range(max_order+1)])
return return_string
# ----------------- generating VECI/CC residual latex -------------------- #
def _construct_c_term(h, power, order):
"""Creates the string for the "upper" labels of the tensor c.
c_n is defined as S * (1/n!) * (t^1)^n.
Returns `c^{str}` if there are upper labels
Otherwise returns an empty string
"""
i_start = h.m+1
nof_k = h.n
upper_labels = []
for n in range(i_start, order+1):
upper_labels.append(f"i_{n}")
for n in range(1, nof_k+1):
upper_labels.append(f"k_{n}")
return f"{bold_c_latex}^{{{', '.join(upper_labels)}}}"
def _construct_c_and_t_term(h, c_power, t_power, order):
"""Creates the string for the "upper" labels of the c and t tensors.
c_n is defined as S * (1/n!) * (t^1)^n.
Returns `c^{str1}t^{str2}` if there are upper labels
Otherwise returns an empty string
"""
nof_k = h.n
string = ""
return ""
for n in range(1, c_power - nof_k + 1):
string += f"{bold_c_latex}^{{i_{n}}}"
string += f"{bold_t_latex}^{{k_{n}}}"
return string
def _extract_power(string):
"""Return integer representation of the power that `string` is being raised to."""
return int(string.split('{')[1].strip('}')[0])
def _extract_ct_powers(string):
"""Return integer representation of the powers that the two terms in `string` are being raised to."""
n1 = int(string.split('{')[1].strip('}')[0])
n2 = int(string.split('{')[2].strip('}')[0])
return n1, n2
def _generate_mixedcc_explicit_latex_term(term_list, h_list, w_list, order, expand_order_n_w=None):
"""Generate the latex for the residual equations including all the indices and factors."""
for h in h_list:
h_string = bold_h_latex
h_string += construct_upper_h_label(h, order)
h_string += construct_lower_h_label(h, order)
prefactor = construct_prefactor(h, order, True)
if prefactor != "":
numerator, denominator = prefactor[1:-1].split('/')
prefactor = f"\\left(\\frac{{{numerator}}}{{{denominator}}}\\right)"
# prefactor = f"\\frac{{{numerator}}}{{{denominator}}}"
# no W operator
if (h.m == order and h.n == 0) or h.m > order:
w_string = ""
term_list.append(prefactor + h_string + w_string)
continue
# 1 W operator
elif len(w_list) == 1 and bold_w_latex in w_list[0]:
power = _extract_power(w_list[0])
if expand_order_n_w is None or power < expand_order_n_w:
w_string = bold_w_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + w_string)
else:
t_string = bold_t_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + t_string)
continue
# many W operators
else:
w_string = ""
for w_op in w_list:
# these terms only appear because we are mixing in the VECC through the e^(t^1) operator
if bold_c_latex in w_op:
# the term is c^x
if bold_t_latex not in w_op:
# add 1/n! to prefactor
power = _extract_power(w_op)
# we don't need to update prefactor if we keep the c term
# updated_prefactor = f"\\left(\\dfrac{{{numerator}}}{{{denominator}*{power}!}}\\right)"
term_list.append(prefactor + h_string + _construct_c_term(h, power, order))
continue
# the term is c^x * t^y
else:
# c_power, t_power = _extract_ct_powers(w_op)
# term_list.append(prefactor + h_string + "\\left[" + w_op + "\\right]")
term_list.append(h_string + "\\left[" + w_op + "\\right]") # no prefactor for the moment
# we will develop the expansion code here at a later date
# # we have to modify the prefactor
# if c_power > 1:
# # add 1/n! to prefactor
# updated_prefactor = f"\\left(\\dfrac{{{numerator}}}{{{denominator}*{c_power}!}}\\right)"
# term_list.append(
# updated_prefactor \
# + h_string \
# + _construct_c_and_t_term(h, c_power, t_power, order)
# )
# # normal prefactor
# else:
# term_list.append(
# prefactor \
# + h_string \
# + _construct_c_and_t_term(h, c_power, t_power, order)
# )
continue
# this is the condensed linked-disconnected term contribution
elif bold_d_latex in w_op:
d_string = bold_d_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + d_string)
continue
# this is the VECI contribution (simple t amplitude t^y)
elif bold_t_latex in w_op and w_op.count(bold_t_latex) == 1:
t_string = bold_t_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + t_string)
continue
else:
raise Exception()
return
def _generate_mixedcc_condensed_latex_term(term_list, h_list, w_list):
"""Append a string representation of a summation term for a residual to `term_list`."""
if len(h_list) == 1:
h_string = h_list[0].name.replace('h', bold_h_latex)
else:
bold_h_list = [h.name.replace('h', bold_h_latex) for h in h_list]
h_string = f"({' + '.join(bold_h_list)})"
if len(w_list) == 1:
w_string = w_list[0]
else:
w_string = f"({' + '.join(w_list)})"
# save the string representation of the term
term_list.append(h_string + w_string)
return
def _generate_mixedcc_latex_form(hamiltonian, order, max_order, expand_order_n_w=3, condense_disconnected_terms=True, explicit=False):
"""Generate the VECI/CC latex for the residual equations.
Default is to generate the condensed form, but if `explicit` flag is `True` then
explicit form with all i and k terms and prefactors is returned.
"""
w_range = list(range(0, order + hamiltonian.maximum_rank + 1))
# generate a list of H terms of equal or lower order than the residual
operators = []
for h in hamiltonian.operator_list:
if h.m <= order:
operators.append(h)
term_list = [] # store all terms in here
# generate each term we need to sum over
for n in w_range:
h_list, w_list = [], []
# fill up the `w_list`
if expand_order_n_w is None or n < expand_order_n_w:
# create the plain w string
w_list.append(f"{bold_w_latex}^{{{n}}}" if n != 0 else "")
elif n >= expand_order_n_w:
# connected term
w_list.append(f"{bold_t_latex}^{{{n}}}")
# linked disconnected terms
if condense_disconnected_terms:
w_list.append(f"{bold_d_latex}^{{{n}}}")
else:
for partition in sorted(generate_linked_disconnected_partitions_of_n(n)):
if max(partition) == 1:
w_list.append(f"{bold_c_latex}^{{{len(partition)}}}")
else:
w_list.append(f"{bold_c_latex}^{{{len(partition)-1}}}" + f"{bold_t_latex}^{{{max(partition)}}}")
# collect h terms that map to the w^n operators in `w_list`
for i, h in enumerate(operators):
if abs(h.m - h.n - order) == n:
h_list.append(h)
operators.pop(i)
# if no terms we skip this W operator
if len(h_list) == 0:
continue
# append all term strings to `term_list`
if explicit:
_generate_mixedcc_explicit_latex_term(term_list, h_list, w_list, order, expand_order_n_w)
else:
_generate_mixedcc_condensed_latex_term(term_list, h_list, w_list)
# loop
# return the full string (with prefix and all term's wrapped in plus symbols)
if explicit:
i_terms = ", ".join([f"i_{n}" for n in range(1, order+1)]) if order != 0 else "0"
return_string = f"\\begin{{split}} \\textbf{{R}}_{{{i_terms}}} &=\n" + " +\n".join(term_list) + " \\end{split}"
return return_string
else:
return_string = f"\\textbf{{R}}_{{{order}}} &= " + " + ".join(term_list)
return return_string
def _generate_mixedcc_wave_operator_2(hamiltonian, order, max_order):
"""Generate the latex for the VECI/CC mixed wave operator w^{`order`}."""
return_string = ""
if order == 0:
return f"{bold_w_latex}^{{0}} &= \\textbf{{1}}"
elif order == 1:
return f"{bold_w_latex}^{{1}} &= {bold_t_latex}^{{1}}"
else:
c_list, d_list = [], []
c_list.append(f"{bold_c_latex}^{{{order}}}")
for i in range(2, order):
c_list.append(f"{bold_c_latex}^{{{order-i}}}" + f"{bold_t_latex}^{{{i}}}")
c_list.append(f"{bold_t_latex}^{{{order}}}")
d_list.append(f"\\textbf{{d}}^{{{order}}}")
d_list.append(f"{bold_t_latex}^{{{order}}}")
return_string = f"{bold_w_latex}^{{{order}}} &= " + " + ".join(c_list) + " &&=" + " + ".join(d_list)
return return_string
def _generate_mixedcc_wave_operator_1(hamiltonian, max_order):
"""Generate the latex for all the VECI/CC mixed wave operators up to w^{`max_order`}."""
line1, line2 = "", ""
for order in range(max_order + 1):
if order == 0:
# line1 += f"{bold_w_latex}^{{0}} &= \\textbf{{1}} &"
# line2 += f"{bold_w_latex}^{{0}} &= \\textbf{{1}} &"
continue
elif order == 1:
# line1 += f"{bold_w_latex}^{{1}} &= {bold_t_latex}^{{1}} &"
# line2 += f"{bold_w_latex}^{{1}} &= {bold_t_latex}^{{1}} &"
continue
else:
# c_list is the uncompressed format
# d_list is the compressed format
c_list, d_list = [], []
c_list, d_list = [], []
# connected term
c_list.append(f"{bold_t_latex}^{{{order}}}")
d_list.append(f"{bold_t_latex}^{{{order}}}")
# linked disconnected terms
d_list.append(f"\\textbf{{d}}^{{{order}}}")
for partition in sorted(generate_linked_disconnected_partitions_of_n(order)):
if max(partition) == 1:
c_list.append(f"{bold_c_latex}^{{{len(partition)}}}")
else:
c_list.append(f"{bold_c_latex}^{{{len(partition)-1}}}" + f"{bold_t_latex}^{{{max(partition)}}}")
# record lines
line1 += f"{bold_w_latex}^{{{order}}} &= " + " + ".join(c_list) + " & "
line2 += f"{bold_w_latex}^{{{order}}} &= " + " + ".join(d_list) + " & "
return line1 + ' \\\\\n' + line2
def _generate_mixedcc_latex(hamiltonian, max_order):
"""Generate all of the VECI/CC mixed latex equations.
We use `join` to insert two backward's slashes \\ BETWEEN each line
rather then adding them to end and having extra trailing slashes on the last line.
The user is expected to manually copy the relevant lines from the text file into a latex file
and generate the pdf themselves.
"""
expand_order_n_w = 3 # expand all terms of order n or higher
return_string = "" # store it all in here
return_string += "VECI/CC wave operator latex\n"
if True:
return_string += _generate_mixedcc_wave_operator_1(hamiltonian, max_order)
else:
return_string += ' \\\\\n'.join(
[_generate_mixedcc_wave_operator_2(hamiltonian, order, max_order) for order in range(max_order+1)]
)
return_string += "\n"*4
return_string += "VECI/CC mixed condensed latex\n"
return_string += ' \\\\\n%\n'.join(
[_generate_mixedcc_latex_form(hamiltonian, order, max_order, expand_order_n_w) for order in range(max_order+1)]
)
return_string += "\n"*4
return_string += "VECI/CC mixed explicit latex\n"
return_string += ' \\\\\n%\n'.join(
[_generate_mixedcc_latex_form(hamiltonian, order, max_order, expand_order_n_w, explicit=True) for order in range(max_order+1)]
)
return return_string
# ------------------- generating VECC residual latex --------------------- #
def _generate_vecc_explicit_latex_term(term_list, h_list, w_list, order, expand_order_n_w=None):
"""Generate the latex for the residual equations including all the indices and factors."""
for h in h_list:
h_string = bold_h_latex
h_string += construct_upper_h_label(h, order)
h_string += construct_lower_h_label(h, order)
prefactor = construct_prefactor(h, order, True)
if prefactor != "":
numerator, denominator = prefactor[1:-1].split('/')
prefactor = f"\\left(\\frac{{{numerator}}}{{{denominator}}}\\right)"
# prefactor = f"\\frac{{{numerator}}}{{{denominator}}}"
# no W operator
if (h.m == order and h.n == 0) or h.m > order:
w_string = ""
term_list.append(prefactor + h_string + w_string)
continue
# 1 W operator
elif len(w_list) == 1 and bold_w_latex in w_list[0]:
power = _extract_power(w_list[0])
if expand_order_n_w is None or power < expand_order_n_w:
w_string = bold_w_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + w_string)
else:
t_string = bold_t_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + t_string)
continue
# many W operators
else:
w_string = ""
for w_op in w_list:
# these terms only appear because we are mixing in the VECC through the e^(t^1) operator
if bold_c_latex in w_op:
# the term is c^x
if bold_t_latex not in w_op:
# add 1/n! to prefactor
power = _extract_power(w_op)
# we don't need to update prefactor if we keep the c term
# updated_prefactor = f"\\left(\\dfrac{{{numerator}}}{{{denominator}*{power}!}}\\right)"
term_list.append(prefactor + h_string + _construct_c_term(h, power, order))
continue
# the term is c^x * t^y
else:
# c_power, t_power = _extract_ct_powers(w_op)
# term_list.append(prefactor + h_string + "\\left[" + w_op + "\\right]")
term_list.append(h_string + "\\left[" + w_op + "\\right]") # no prefactor for the moment
# we will develop the expansion code here at a later date
# # we have to modify the prefactor
# if c_power > 1:
# # add 1/n! to prefactor
# updated_prefactor = f"\\left(\\dfrac{{{numerator}}}{{{denominator}*{c_power}!}}\\right)"
# term_list.append(updated_prefactor + h_string + _construct_c_and_t_term(h, c_power, t_power, order))
# # normal prefactor
# else:
# term_list.append(prefactor + h_string + _construct_c_and_t_term(h, c_power, t_power, order))
continue
# this is the condensed linked-disconnected term contribution
elif bold_d_latex in w_op:
d_string = bold_d_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + d_string)
continue
# this is the VECI contribution (simple t amplitude t^y)
elif bold_t_latex in w_op and w_op.count(bold_t_latex) == 1:
t_string = bold_t_latex + construct_upper_w_label(h, order)
term_list.append(prefactor + h_string + t_string)
continue
# this is the unlinked-disconnected term (the VECC contributions)
elif bold_t_latex in w_op and w_op.count(bold_t_latex) > 1:
# string = bold_t_latex + construct_upper_w_label(h, order)
# term_list.append(prefactor + h_string + string)
term_list.append(h_string + "\\left[" + w_op + "\\right]") # no prefactor for the moment
continue
else:
raise Exception()
return
def _generate_vecc_condensed_latex_term(term_list, h_list, w_list):
"""Append a string representation of a summation term for a residual to `term_list`."""
if len(h_list) == 1:
h_string = h_list[0].name.replace('h', bold_h_latex)
else:
bold_h_list = [h.name.replace('h', bold_h_latex) for h in h_list]
h_string = f"({' + '.join(bold_h_list)})"
if len(w_list) == 1:
w_string = w_list[0]
else:
w_string = f"({' + '.join(w_list)})"
# save the string representation of the term
term_list.append(h_string + w_string)
return
def _generate_vecc_latex_form(hamiltonian, order, max_order, expand_order_n_w=3, condense_disconnected_terms=True, explicit=False):
"""Generate the VECC latex for the residual equations.
Default is to generate the condensed form, but if `explicit` flag is `True` then
explicit form with all i and k terms and prefactors is returned.
"""
w_range = list(range(0, order + hamiltonian.maximum_rank + 1))
# generate a list of H terms of equal or lower order than the residual
operators = []
for h in hamiltonian.operator_list:
if h.m <= order:
operators.append(h)
term_list = [] # store all terms in here
# generate each term we need to sum over
for n in w_range:
h_list, w_list = [], []
# fill up the `w_list`
if expand_order_n_w is None or n < expand_order_n_w:
# create the plain w string
w_list.append(f"{bold_w_latex}^{{{n}}}" if n != 0 else "")
elif n >= expand_order_n_w:
# connected term
w_list.append(f"{bold_t_latex}^{{{n}}}")
# linked disconnected terms
if condense_disconnected_terms:
w_list.append(f"{bold_d_latex}^{{{n}}}")
else:
for partition in sorted(generate_linked_disconnected_partitions_of_n(n)):
if max(partition) == 1:
w_list.append(f"{bold_c_latex}^{{{len(partition)}}}")
else:
w_list.append(f"{bold_c_latex}^{{{len(partition)-1}}}" + f"{bold_t_latex}^{{{max(partition)}}}")
# un-linked disconnected terms
for partition in sorted(generate_un_linked_disconnected_partitions_of_n(n)):
unlinked_disconnected_term = "".join([f"{bold_t_latex}^{{{term}}}" for term in partition])
w_list.append(unlinked_disconnected_term)
# collect h terms that map to the w^n operators in `w_list`
for i, h in enumerate(operators):
if abs(h.m - h.n - order) == n:
h_list.append(h)
operators.pop(i)
# if no terms we skip this W operator
if len(h_list) == 0:
continue
# append all term strings to `term_list`
if explicit:
_generate_vecc_explicit_latex_term(term_list, h_list, w_list, order, expand_order_n_w)
else:
_generate_vecc_condensed_latex_term(term_list, h_list, w_list)
# return the full string (with prefix and all term's wrapped in plus symbols)
if explicit:
i_terms = ", ".join([f"i_{n}" for n in range(1, order+1)]) if order != 0 else "0"
return_string = f"\\begin{{split}} \\textbf{{R}}_{{{i_terms}}} &=\n" + " +\n".join(term_list) + " \\end{split}"
return return_string
else:
# higher order terms are very long and will probably need to be split over many lines
if order >= 4:
return f"\\begin{{split}} \\textbf{{R}}_{{{order}}} &=\n" + " +\n".join(term_list) + " \\end{split}"
else:
return f"\\textbf{{R}}_{{{order}}} &= " + " + ".join(term_list)
return return_string
def _generate_vecc_wave_operator(hamiltonian, max_order):
"""Generate the latex for all the VECC wave operators up to w^{`max_order`}."""
line1, line2 = "", ""
for order in range(max_order + 1):
if order == 0:
# line1 += f"{bold_w_latex}^{{0}} &= \\textbf{{1}} &"
# line2 += f"{bold_w_latex}^{{0}} &= \\textbf{{1}} &"
continue
elif order == 1:
# line1 += f"{bold_w_latex}^{{1}} &= {bold_t_latex}^{{1}} &"
# line2 += f"{bold_w_latex}^{{1}} &= {bold_t_latex}^{{1}} &"
continue
else:
# c_list is the uncompressed format
# d_list is the compressed format
c_list, d_list = [], []
# connected term
c_list.append(f"{bold_t_latex}^{{{order}}}")
d_list.append(f"{bold_t_latex}^{{{order}}}")
# linked disconnected terms
d_list.append(f"\\textbf{{d}}^{{{order}}}")
for partition in sorted(generate_linked_disconnected_partitions_of_n(order)):
if max(partition) == 1:
c_list.append(f"{bold_c_latex}^{{{len(partition)}}}")
else:
c_list.append(f"{bold_c_latex}^{{{len(partition)-1}}}" + f"{bold_t_latex}^{{{max(partition)}}}")
# un-linked disconnected terms
for partition in sorted(generate_un_linked_disconnected_partitions_of_n(order)):
string = ""
for term in partition:
string += f"{bold_t_latex}^{{{term}}}"
c_list.append(string)
d_list.append(string)
# record lines
line1 += f"{bold_w_latex}^{{{order}}} &= " + " + ".join(c_list) + " & "
line2 += f"{bold_w_latex}^{{{order}}} &= " + " + ".join(d_list) + " & "
return line1 + ' \\\\\n' + line2
def _generate_vecc_latex(hamiltonian, max_order):
"""Generate all of the VECI/CC mixed latex equations.
We use `join` to insert two backward's slashes \\ BETWEEN each line
rather then adding them to end and having extra trailing slashes on the last line.
The user is expected to manually copy the relevant lines from the text file into a latex file
and generate the pdf themselves.
"""
expand_order_n_w = 3 # expand all terms of order n or higher
return_string = "" # store it all in here
return_string += "VECC wave operator latex\n"
return_string += _generate_vecc_wave_operator(hamiltonian, max_order)
return_string += "\n"*4
return_string += "VECC condensed latex\n"
return_string += ' \\\\\n%\n'.join(
[_generate_vecc_latex_form(hamiltonian, order, max_order, expand_order_n_w) for order in range(max_order+1)]
)
return_string += "\n"*4
return_string += "VECC explicit latex\n"
return_string += ' \\\\\n%\n'.join(
[_generate_vecc_latex_form(hamiltonian, order, max_order, expand_order_n_w, explicit=True) for order in range(max_order+1)]
)
return return_string
# ------------------------------------------------------------------------ #
def generate_residual_equations_latex(max_residual_order, maximum_h_rank, path="./generated_latex.txt"):
"""Generates and saves to a file the code to calculate the residual equations for the CC approach."""
# generate the Hamiltonian data
H = generate_hamiltonian_operator(maximum_h_rank)
for h in H.operator_list:
print(h)
# write latex code
string = _generate_veci_latex(H, max_residual_order)
# write latex code
string += "\n"*4 + _generate_mixedcc_latex(H, max_residual_order)
# write latex code
string += "\n"*4 + _generate_vecc_latex(H, max_residual_order)
# save data
with open(path, 'w') as fp:
fp.write(string)
if (__name__ == '__main__'):
generate_residual_equations_latex(3, 2, path="./generated_latex.txt")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment