def test_recursive_single_commutator_1(): h = hamiltonian_operator(2) t2e = cluster_operator(2) a = recursive_single_commutator([h, t2e], 3, (0, 6), n_process=4) b = single_commutator(h, t2e, for_commutator=True) assert a[1] == b
def test_single_commutator(): h = hamiltonian_operator(2) t2e = cluster_operator(2) a = single_commutator(h, t2e, for_commutator=True) b = single_commutator(h, t2e, for_commutator=False, n_process=4) assert a == b
def test_contract_terms_1(): h = hamiltonian_operator(2) t2e = cluster_operator(2, hole_label='c', particle_label='v') t2ee = cluster_operator(2, start=4, hole_label='c', particle_label='v') a = contract_terms([h, t2e, t2ee], max_cu=1, scale_factor=0.5, for_commutator=True, n_process=2) ref = {Term([make_tensor('H', 'c2,c3', 'v2,v3'), make_tensor('t', 'c0,c1', 'v0,v2'), make_tensor('t', 'c2,c3', 'v1,v3')], make_sq('v0,v1', 'c0,c1'), -0.25), Term([make_tensor('H', 'c2,c3', 'v2,v3'), make_tensor('t', 'c0,c1', 'v2,v3'), make_tensor('t', 'c2,c3', 'v0,v1')], make_sq('v0,v1', 'c0,c1'), 1.0/16.0), Term([make_tensor('H', 'c2,c3', 'v2,v3'), make_tensor('t', 'c0,c2', 'v0,v1'), make_tensor('t', 'c1,c3', 'v2,v3')], make_sq('v0,v1', 'c0,c1'), -0.25), Term([make_tensor('H', 'c2,c3', 'v2,v3'), make_tensor('t', 'c0,c2', 'v0,v2'), make_tensor('t', 'c1,c3', 'v1,v3')], make_sq('v0,v1', 'c0,c1'), 0.5), Term([make_tensor('H', 'v2,v3', 'g0,c3'), make_tensor('t', 'c0,c1', 'v0,v2'), make_tensor('t', 'c2,c3', 'v1,v3')], make_sq('g0,v0,v1', 'c0,c1,c2'), -0.5), Term([make_tensor('H', 'v2,v3', 'g0,c3'), make_tensor('t', 'c0,c3', 'v0,v1'), make_tensor('t', 'c1,c2', 'v2,v3')], make_sq('g0,v0,v1', 'c0,c1,c2'), 0.125), Term([make_tensor('H', 'c2,c3', 'g0,v3'), make_tensor('t', 'c0,c1', 'v2,v3'), make_tensor('t', 'c2,c3', 'v0,v1')], make_sq('v0,v1,v2', 'g0,c0,c1'), -0.125), Term([make_tensor('H', 'c2,c3', 'g0,v3'), make_tensor('t', 'c0,c2', 'v0,v1'), make_tensor('t', 'c1,c3', 'v2,v3')], make_sq('v0,v1,v2', 'g0,c0,c1'), 0.5) } for i in a: assert i in ref
def test_recursive_single_commutator_2(): # Jacobi identity [[X, Y], Z] = [X, [Y, Z]] + [Y, [Z, X]] = [[X, Z], Y] + [[Z, Y], X] h = hamiltonian_operator(2) t1e = cluster_operator(1, start=4, hole_label='c', particle_label='v') t2e = cluster_operator(2, start=0, hole_label='c', particle_label='v') a = recursive_single_commutator([h, t2e, t1e], 1, (0, 6), n_process=4) t1e = cluster_operator(1, start=0, hole_label='c', particle_label='v') t2e = cluster_operator(2, start=4, hole_label='c', particle_label='v') b = recursive_single_commutator([h, t1e, t2e], 1, (0, 6), n_process=4) assert a[2] == b[2] # note [t2e, t1e] = 0 for single reference
def test_recursive_single_commutator_3(): # Jacobi identity [[X, Y], Z] = [X, [Y, Z]] + [Y, [Z, X]] = [[X, Z], Y] + [[Z, Y], X] h = hamiltonian_operator(2) t1e = cluster_operator(1, start=4) t2e = cluster_operator(2, start=0) a = recursive_single_commutator([h, t2e, t1e], 3, (0, 6), n_process=4) t1e = cluster_operator(1, start=0) t2e = cluster_operator(2, start=4) b = recursive_single_commutator([h, t1e, t2e], [2, 3], [(0, 4), (0, 6)], n_process=4) c = recursive_single_commutator([t1e, t2e, h], [2, 3], (0, 6), n_process=4) assert a[2] == combine_terms(b[2] + c[2])
def nested_commutator_cc(nested_level, cluster_levels, max_cu=3, max_n_open=6, min_n_open=0, for_commutator=True, expand_hole=True, single_reference=False, unitary=False, n_process=1, hermitian_tensor=True): """ Compute the BCH nested commutator in coupled cluster theory. :param nested_level: the level of nested commutator :param cluster_levels: a list of integers for cluster operator, e.g., [1,2,3] for T1 + T2 + T3 :param max_cu: max value of cumulant allowed for contraction :param max_n_open: the max number of open indices for contractions kept for return :param min_n_open: the min number of open indices for contractions kept for return :param for_commutator: compute only non-zero terms for commutators if True :param expand_hole: expand HoleDensity to Kronecker minus Cumulant if True :param single_reference: use single-reference amplitudes if True :param unitary: use unitary formalism if True :param n_process: number of processes launched for tensor canonicalization :param hermitian_tensor: assume tensors being Hermitian if True :return: a list of contracted canonicalized Term objects """ if not isinstance(nested_level, int): raise ValueError("Invalid nested_level (must be an integer)") if not isinstance(cluster_levels, Iterable): raise ValueError("Invalid type for cluster_operator") if not all(isinstance(t, int) for t in cluster_levels): raise ValueError( "Invalid content in cluster_operator (must be all integers)") scale_factor = 1.0 / factorial(nested_level) out = [] hole_label = 'c' if single_reference else 'h' particle_label = 'v' if single_reference else 'p' # symbolic evaluate nested commutator t = sum(Operator(f'T{i}') for i in cluster_levels) h = HermitianOperator('H1') + HermitianOperator('H2') a = t - Dagger(t) if unitary else t for term in sympy_nested_commutator_recursive(nested_level, h, a).doit().expand().args: coeff, tensors = term.as_coeff_mul() factor = scale_factor * int(coeff) tensor_names = [] for tensor in tensors: if isinstance(tensor, Pow): if isinstance(tensor.base, Dagger): tensor_names += ['X' + str(tensor.base.args[0])[1:]] * int( tensor.exp) else: tensor_names += [str(tensor.base)] * int(tensor.exp) else: if isinstance(tensor, Dagger): tensor_names.append('X' + str(tensor.args[0])[1:]) else: tensor_names.append(str(tensor)) list_of_terms = [] start = 0 for name in tensor_names: real_name, n_body = name[0], int(name[1:]) if real_name == 'T' or real_name == 'X': list_of_terms.append( cluster_operator(n_body, start=start, excitation=(real_name == 'T'), hole_label=hole_label, particle_label=particle_label)) start += n_body else: list_of_terms.append(hamiltonian_operator(n_body)) out += contract_terms(list_of_terms, max_cu, max_n_open, min_n_open, factor, for_commutator, expand_hole, n_process, hermitian_tensor) return combine_terms(out)
def bch_cc_rsc(nested_level, cluster_levels, max_cu_levels, n_opens, for_commutator=True, expand_hole=True, single_reference=False, unitary=False, n_process=1, hermitian_tensor=True): """ Compute the BCH nested commutator in coupled cluster theory using recursive commutator formalism. :param nested_level: the level of nested commutator :param cluster_levels: a list of integers for cluster operator, e.g., [1,2,3] for T1 + T2 + T3 :param max_cu_levels: a list of integers for max cumulant level of each level of commutator :param n_opens: a list of tuple [(min, max)] for numbers of open indices of each level of commutator :param for_commutator: compute only non-zero terms for commutators if True :param expand_hole: expand HoleDensity to Kronecker minus Cumulant if True :param single_reference: use single-reference amplitudes if True :param unitary: use unitary formalism if True :param n_process: number of processes launched for tensor canonicalization :param hermitian_tensor: assume tensors being Hermitian if True :return: a map of nested level to a list of contracted canonicalized Term objects """ if not isinstance(nested_level, int): raise ValueError("Invalid nested_level (must be an integer)") if not all(isinstance(t, int) for t in cluster_levels): raise ValueError( "Invalid content in cluster_operator (must be all integers)") if isinstance(max_cu_levels, int): max_cu_levels = [max_cu_levels] * nested_level if len(max_cu_levels) != nested_level: raise ValueError( f"Inconsistent size of max_cu_levels ({max_cu_levels}), required {nested_level}" ) if any(not isinstance(i, int) for i in max_cu_levels): raise ValueError( f"Invalid max_cu_levels ({max_cu_levels}): not all integers") if isinstance(n_opens, tuple): n_opens = [n_opens] * nested_level if len(n_opens) != nested_level: raise ValueError( f"Inconsistent size of n_opens ({n_opens}), required {nested_level}" ) for n in n_opens: if len(n) != 2: raise ValueError( f"Invalid element in n_opens: {n} cannot be used for min/max numbers of open indices." ) if not (isinstance(n[0], int) and isinstance(n[1], int)): raise ValueError( f"Invalid element in n_opens: {n} contains non-integer elements" ) max_amp = max(cluster_levels) * 2 amps = [ cluster_operators(cluster_levels, start=(i * max_amp) + 4, unitary=unitary, single_reference=single_reference) for i in range(nested_level) ] out = defaultdict(list) out[0] = combine_terms([x for x in hamiltonian_operator(1).expand_composite_indices(True)]) + \ combine_terms([x for x in hamiltonian_operator(2).expand_composite_indices(True)]) left_pool = combine_terms([x for x in hamiltonian_operator(1).expand_composite_indices(True)]) + \ combine_terms([x for x in hamiltonian_operator(2).expand_composite_indices(True)]) for i in range(1, nested_level + 1): factor = 1.0 / i max_cu = max_cu_levels[i - 1] min_n_open, max_n_open = n_opens[i - 1] for left in left_pool: for right in amps[i - 1]: out[i] += single_commutator(left, right, max_cu, max_n_open, min_n_open, factor, for_commutator, expand_hole, n_process, hermitian_tensor) out[i] = combine_terms([Term.from_term(term) for term in out[i]]) left_pool = [Term.from_term(term) for term in out[i]] return out