def process_composite_contractions(contraction, elementary_contractions, n_indices, expand_hole, base_order_map, upper_indices_set, lower_indices_set): """ Process a single composite contraction expressed in terms of indices of elementary contractions. :param contraction: a composite contraction :param elementary_contractions: a list of density cumulants / hole densities :param n_indices: the total number of indices :param expand_hole: expand hole densities to Kronecker delta minus one density if True :param base_order_map: the index map to ordering index, e.g., {"ug0": 0, "lg0": 1, ...}, u/l for upper/lower :param upper_indices_set: the set of all creation operators :param lower_indices_set: the set of all annihilation operators :return: a list of contractions in terms of (sign, list_of_densities, sq_op) """ list_of_densities = [] current_order = [] n_open = 0 for con in contraction: ele_con = elementary_contractions[con] list_of_densities.append(ele_con) n_open += ele_con.n_upper if isinstance(ele_con, HoleDensity): current_order += [ f"l{ele_con.lower_indices[0].name}", f"u{ele_con.upper_indices[0].name}" ] else: current_order += [f"u{i.name}" for i in ele_con.upper_indices] current_order += [ f"l{i.name}" for i in ele_con.lower_indices[::-1] ] n_open = n_indices - 2 * n_open # sort the open indices if n_open != 0: contracted = set(current_order) open_upper_indices = IndicesSpinOrbital( sorted(Index(i[1:]) for i in upper_indices_set - contracted)) open_lower_indices = IndicesSpinOrbital( sorted(Index(i[1:]) for i in lower_indices_set - contracted)) current_order += [f"u{i.name}" for i in open_upper_indices] current_order += [f"l{i.name}" for i in open_lower_indices[::-1]] sq_op = SecondQuantizedOperator(open_upper_indices, open_lower_indices) else: sq_op = SecondQuantizedOperator.make_empty() # expand hole densities to delta - lambda_1 sign_densities_pairs = expand_hole_densities( list_of_densities) if expand_hole else [(1, list_of_densities)] # determine sign sign = (-1)**Permutation([base_order_map[i] for i in current_order]).inversions() return [(sign * _s, list_of_densities, sq_op) for _s, list_of_densities in sign_densities_pairs]
def test_latex_permute_format_1(): a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'spin-orbital') p_cre = [[Index(i) for i in "g0,g1,g2".split(',')]] p_ann = [[Index(i) for i in "p0,p1,p2".split(',')]] n_perm, perm, latex_str = a.latex_permute_format(p_cre, p_ann) assert n_perm == 1 assert perm == '' assert latex_str == 'a^{ g_{0} g_{1} g_{2} }_{ p_{0} p_{1} p_{2} }'
def test_index_init(): with pytest.raises(ValueError): Index("x0") with pytest.raises(ValueError): Index("ax1") with pytest.raises(ValueError): Index("a1.25") with pytest.raises(TypeError): Index(123)
def test_indices_init(): with pytest.raises(ValueError): Indices("a0 c1, P2, V8") with pytest.raises(ValueError): Indices(["a0"] * 3) a = Indices("a0, P2") assert a.indices == [Index("a0"), Index("P2")] assert a.size == 2 assert a.indices_set == {Index("a0"), Index("P2")} a = Indices([]) assert a == Indices("") assert a.size == 0
def test_simplify(): list_of_tensors = [ make_tensor('H', "g0", "g0"), make_tensor('t', "h0", "p0"), make_tensor('t', "p1", "h1"), make_tensor('L', 'h0', 'g0'), make_tensor('L', 'g0, p1', 'p0, h1') ] a = Term(list_of_tensors, SecondQuantizedOperator.make_empty(), -1) a.simplify() assert a.is_void() list_of_tensors = [ make_tensor('H', "g0", "g0"), make_tensor('t', "h0", "p0"), make_tensor('t', "p1", "h1"), make_tensor('L', 'g0', 'h1'), make_tensor('L', 'h0', 'g0'), make_tensor('K', 'p0', 'p1') ] a = Term(list_of_tensors, SecondQuantizedOperator.make_empty()) a.simplify() assert a.list_of_tensors == [ make_tensor('H', 'h6', 'h6'), make_tensor('t', 'p1', 'h3'), make_tensor('t', 'h4', 'p1'), make_tensor('L', 'h6', 'h3'), make_tensor('L', 'h4', 'h6') ] assert a.sq_op == SecondQuantizedOperator.make_empty() assert a.indices_set == {Index(i) for i in ['h6', 'p1', 'h3', 'h4']} assert a.diagonal_indices == {Index('h6'): 4} list_of_tensors = [ make_tensor('H', "g0", "g0"), make_tensor('t', "h0", "p0"), make_tensor('t', "p1", "c1"), make_tensor('L', 'g0', 'c1'), make_tensor('K', 'p0', 'p1') ] a = Term(list_of_tensors, SecondQuantizedOperator('h0', 'g0')) a.simplify() assert a.list_of_tensors == [ make_tensor('H', "c2", "c2"), make_tensor('t', "p1", "c2"), make_tensor('t', "h0", "p1") ] assert a.sq_op == SecondQuantizedOperator('h0', 'c2') assert a.indices_set == {Index(i) for i in ['c2', 'p1', 'h0']} assert a.diagonal_indices == {Index('c2'): 4}
def test_indices_si_latex_permute_format(): a = IndicesSpinIntegrated(["P0", "P1", "P2", "A3"]) part = [["P2"], ["P0", "P1"], ["A3"]] with pytest.raises(TypeError): a.latex_permute_format(part) part = [[Index("P2")], [Index("P0"), Index("P1")], [Index("A3")]] n_perm, perm_str = a.latex_permute_format(part) assert (n_perm, perm_str) == (12, '{\\cal P} ( P_{2} / P_{0} P_{1} / A_{3} )') a = IndicesSpinIntegrated(["p0", "P1", "V2", "A3"]) with pytest.raises(ValueError): list(a.ambit_permute_format(part))
def test_indices_si_ambit_perm(): a = IndicesSpinIntegrated(["P0", "P1", "V2", "A3"]) part = [[Index("V2")], [Index("P0"), Index("P1")], [Index("A3")]] ref = { "P0,P1,V2,A3", "P0,P1,A3,V2", "P0,A3,P1,V2", "A3,P0,P1,V2", "P0,V2,P1,A3", "V2,P0,P1,A3", "P0,A3,V2,P1", "P0,V2,A3,P1", "V2,P0,A3,P1", "A3,P0,V2,P1", "A3,V2,P0,P1", "V2,A3,P0,P1" } for sign, indices_str in a.ambit_permute_format(part): assert sign == (-1)**a.count_permutations(Indices(indices_str)) assert indices_str in ref ref.remove(indices_str) assert len(ref) == 0 a = IndicesSpinIntegrated(["P0", "P1", "c2", "A3"]) with pytest.raises(ValueError): list(a.ambit_permute_format(part))
def test_multiset_permutation_2(): a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'spin-integrated') p_cre = [[Index(i) for i in "g0,g1,g2".split(',')]] p_ann = [[Index('p0')], [Index('p1')], [Index('p2')]] assert a.exist_permute_format(p_cre, p_ann) assert a.n_multiset_permutation(p_cre, p_ann) == 6 p_ann = [[Index('p0'), Index('p1')], [Index('p2')]] assert a.n_multiset_permutation(p_cre, p_ann) == 3
def test_multiset_permutation_5(): # n_multiset_permutation for spin-adapted operators is always one a = SecondQuantizedOperator("g0,v1,p2", "p0,a1,c2", 'spin-adapted') p_cre = [[Index('g0'), Index('v1'), Index('p2')]] p_ann = [[Index('p0')], [Index('a1')], [Index('c2')]] assert not a.exist_permute_format(p_cre, p_ann) assert a.n_multiset_permutation(p_cre, p_ann) == 1
def test_latex_permute_format_2(): a = SecondQuantizedOperator("g0,v1,p3", "p0,a1,p2", 'spin-integrated') p_cre = [[Index('g0')], [Index('p3')], [Index('v1')]] p_ann = [[Index('p0'), Index('p2')], [Index('a1')]] n_perm, perm, latex_str = a.latex_permute_format(p_cre, p_ann) assert n_perm == 18 assert perm == '{\\cal P} ( g_{0} / p_{3} / v_{1} ) {\\cal P} ( p_{0} p_{2} / a_{1} )' assert latex_str == 'a^{ g_{0} v_{1} p_{3} }_{ p_{0} a_{1} p_{2} }'
def test_perm_part_2(): list_of_tensors = [ make_tensor('H', 'v4, c2', 'v3, c1'), make_tensor('T', 'c1', 'v0'), make_tensor('T', 'c0, c3', 'v1, v4'), make_tensor('T', 'c2, c3', 'v2, v3') ] sq_op = make_sq('v2, c0', 'v0, v1') a = Term(list_of_tensors, sq_op) cre_part, ann_part = a.perm_partition_open() assert cre_part == [[Index('v2')], [Index('c0')]] assert ann_part == [[Index('v0')], [Index('v1')]] list_of_tensors = [ make_tensor('H', 'v3, v4', 'v0, c3'), make_tensor('T', 'c0, c1', 'v1, v3'), make_tensor('T', 'c2, c3', 'v2, v4') ] sq_op = make_sq('v0, v1, v2', 'c0, c1, c2') a = Term(list_of_tensors, sq_op) cre_part, ann_part = a.perm_partition_open() assert cre_part == [[Index('v0')], [Index('v1')], [Index('v2')]] assert ann_part == [[Index('c0'), Index('c1')], [Index('c2')]]
def test_perm_part_3(): list_of_tensors = [make_tensor('H', 'g0, h1', 'p1, g0')] sq_op = make_sq('g0, p1', 'g0, h1') a = Term(list_of_tensors, sq_op, -1) cre_part, ann_part = a.perm_partition_open() assert cre_part == [[Index('g0')], [Index('p1')]] assert ann_part == [[Index('g0')], [Index('h1')]] list_of_tensors = [ make_tensor('H', 'g0, h0, a0', 'g1, p0, p1'), make_tensor('t', 'p0, p1', 'a0,a1') ] sq_op = make_sq('g1, a1', 'g0, h0') a = Term(list_of_tensors, sq_op, -1) cre_part, ann_part = a.perm_partition_open() assert cre_part == [[Index('g1')], [Index('a1')]] assert ann_part == [[Index('g0')], [Index('h0')]]
def test_perm_part_1(): list_of_tensors = [ make_tensor('H', 'g0, g1', 'g2, p0'), make_tensor('T', 'h0, h1', 'p0, p1') ] sq_op = make_sq('g0, g1, p1', 'g2, h0, h1') a = Term(list_of_tensors, sq_op) cre_part, ann_part = a.perm_partition_open() assert cre_part == [[Index('g0'), Index('g1')], [Index('p1')]] assert ann_part == [[Index('g2')], [Index('h0'), Index('h1')]]
def test_latex_permute_format_3(): # TODO: is this necessary? # ignore multiset permutations for mixed spin indices a = SecondQuantizedOperator("g0,v1,p2", "p0,a1,P2", 'spin-integrated') p_cre = [[Index('g0')], [Index('p2')], [Index('v1')]] p_ann = [[Index('p0'), Index('P2')], [Index('a1')]] n_perm, perm, latex_str = a.latex_permute_format(p_cre, p_ann) assert n_perm == 6 assert perm == '{\\cal P} ( g_{0} / p_{2} / v_{1} )' assert latex_str == 'a^{ g_{0} v_{1} p_{2} }_{ p_{0} a_{1} P_{2} }'
def test_ambit_permute_format_2(): a = SecondQuantizedOperator("g0,g1,c2", "p0,p1,p2", 'spin-integrated') p_cre = [[Index('g0'), Index('g1')], [Index('c2')]] p_ann = [[Index('p0'), Index('p1'), Index('p2')]] ref = {(1, '["p0,p1,p2,g0,g1,c2"]'), (-1, '["p0,p1,p2,g0,c2,g1"]'), (1, '["p0,p1,p2,c2,g0,g1"]')} for pair in a.ambit_permute_format(p_cre, p_ann, cre_first=False): assert pair in ref ref.remove(pair) assert len(ref) == 0
def process_composite_categorized(com_cat, ele_con, compatible, upper_indices_set, lower_indices_set, base_order_map, n_indices, expand_hole): """ Process one composite categorized contraction. :param com_cat: a list of connected operator indices :param ele_con: an ElementaryContractionCategorized object :param compatible: compatible elementary contractions :param upper_indices_set: the set of all creation operators :param lower_indices_set: the set of all annihilation operators :param base_order_map: the Index map to ordering index :param n_indices: the total number of cre and ann operators :param expand_hole: expand hole densities to Kronecker delta minus one density if True :return: a list of contractions in terms of (sign, list_of_densities, sq_op) """ n_open = n_indices - sum(len(i) for i in com_cat) out = [] for coded_cons in ele_con.composite_contractions(Counter(com_cat), compatible): contractions = [ele_con.decode(i) for i in coded_cons] # cre/ann ordering of the current composite contraction current_order = [] for con in contractions: if isinstance(con, HoleDensity): current_order += [ f"l{con.lower_indices[0].name}", f"u{con.upper_indices[0].name}" ] else: current_order += [f"u{i.name}" for i in con.upper_indices] current_order += [ f"l{i.name}" for i in con.lower_indices[::-1] ] # sort open indices if n_open != 0: contracted = set(current_order) open_upper = IndicesSpinOrbital( sorted(Index(i[1:]) for i in upper_indices_set - contracted)) open_lower = IndicesSpinOrbital( sorted(Index(i[1:]) for i in lower_indices_set - contracted)) current_order += [f"u{i.name}" for i in open_upper] current_order += [f"l{i.name}" for i in open_lower[::-1]] sq_op = SecondQuantizedOperator(open_upper, open_lower) else: sq_op = SecondQuantizedOperator.make_empty() # determine sign of current ordering sign = (-1)**Permutation([base_order_map[i] for i in current_order]).inversions() # expand hole density to delta - 1-cumulant sign_densities = expand_hole_densities( contractions) if expand_hole else [(1, contractions)] # append results out += [(sign * _s, cons, sq_op) for _s, cons in sign_densities] return out
def test_index_ne_2(): assert Index("a0") != Index("a20")
def test_multiset_permutation_4(): a = SecondQuantizedOperator("g0,v1,p2", "p0,a1,c2", 'spin-orbital') p_cre = [[Index('g0'), Index('v1'), Index('p2')]] p_ann = [[Index('p0'), Index('a1'), Index('c2')]] assert not a.exist_permute_format(p_cre, p_ann) assert a.n_multiset_permutation(p_cre, p_ann) == 1
def test_multiset_permutation_3(): a = SecondQuantizedOperator("g0,v1,p2", "p0,a1,p2", 'spin-integrated') p_cre = [[Index('g0')], [Index('v1')], [Index('p2')]] p_ann = [[Index('p0'), Index('p2')], [Index('a1')]] assert a.exist_permute_format(p_cre, p_ann) assert a.n_multiset_permutation(p_cre, p_ann) == 18
def test_index_gt(): assert Index("H0") > Index("a4")
def test_multiset_permutation_1(): a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'spin-orbital') p_cre = [[Index(i) for i in "g0,g1,g2".split(',')]] p_ann = [[Index(i) for i in "p0,p1,p2".split(',')]] assert not a.exist_permute_format(p_cre, p_ann) assert a.n_multiset_permutation(p_cre, p_ann) == 1
def test_indices_so_ambit_perm(): a = IndicesSpinOrbital(["p0", "p1", "v2", "a3"]) part = [[Index("p0"), Index("p1")], [Index("v2")], [Index("a3")]] for sign, indices_str in a.ambit_permute_format(part): assert sign == (-1)**a.count_permutations(Indices(indices_str))
def test_index_ge(): assert Index("P1") >= Index("P1")
def test_index_le(): assert Index("p0") <= Index("p1")
def test_indices_get(): with pytest.raises(IndexError): assert Indices([])[0] assert Indices("p0, p1, a0, h0, g4, g1, c1, v2")[2] == Index("a0")
def test_index_ne_1(): assert Index("a0") != Index("P0")
def test_index_spin(): assert Index("G1").is_beta() assert not Index("g1").is_beta() assert Index("a0").to_beta() == Index("A0") assert Index("p0").to_alpha() == Index("p0")
def compute_operator_contractions_general(ops_list, max_cu=3, max_n_open=6, min_n_open=0, expand_hole=True, n_process=1, batch_size=1): """ Generate operator contractions for a list of SQOperator (disconnected contractions are included). :param ops_list: a list of SecondQuantizedOperator to be contracted :param max_cu: max level of cumulant :param max_n_open: max number of open indices for contractions kept for return :param min_n_open: min number of open indices for contractions kept for return :param expand_hole: expand hole density to Kronecker delta and 1-cumulant if True :param n_process: the number of processes launched by multiprocessing :param batch_size: the chunk size for multiprocessing :return: a list of contractions in terms of (sign, list_of_densities, sq_op) """ max_cu_allowed = check_max_cu(ops_list, max_cu) # original ordering of the second-quantized operators base_order_map, upper_indices_set, lower_indices_set = generate_base_order_map( ops_list) n_indices = len(base_order_map) # un-contracted term if min_n_open <= n_indices <= max_n_open: sq_op = SecondQuantizedOperator( sorted(Index(i[1:]) for i in upper_indices_set), sorted(Index(i[1:]) for i in lower_indices_set)) current_order = [base_order_map[f"u{i.name}"] for i in sq_op.cre_ops] current_order += [ base_order_map[f"l{i.name}"] for i in sq_op.ann_ops[::-1] ] sign = (-1)**Permutation(current_order).inversions() yield [(sign, [], sq_op)] # max/min numbers of contracted indices max_n_con, min_n_con = n_indices - min_n_open, n_indices - max_n_open elementary_contractions = compute_elementary_contractions_list( ops_list, max_cu_allowed) compatible = compute_compatible_elementary_contractions_list( elementary_contractions) n_ele_con = len(elementary_contractions) if n_ele_con > 1000: sys.setrecursionlimit(n_ele_con) if n_process == 1: for con in composite_contractions_backtrack(set(range(n_ele_con)), set(), compatible, 0, elementary_contractions, (min_n_con, max_n_con)): yield process_composite_contractions(con, elementary_contractions, n_indices, expand_hole, base_order_map, upper_indices_set, lower_indices_set) else: composite = [ list(i) for i in composite_contractions_backtrack(set(range( n_ele_con)), set(), compatible, 0, elementary_contractions, ( min_n_con, max_n_con)) ] n_process = min(n_process, multiprocessing.cpu_count()) if batch_size == 0: n_upper, n_lower = len(upper_indices_set), len(lower_indices_set) batch_size = estimate_batch_size(n_upper, n_lower, max_n_con, min_n_con, n_process) with multiprocessing.Pool(n_process, maxtasksperchild=1000) as pool: tasks = [(process_composite_contractions, (con, elementary_contractions, n_indices, expand_hole, base_order_map, upper_indices_set, lower_indices_set)) for con in composite] imap_unordered_it = pool.imap_unordered(calculate_star, tasks, chunksize=batch_size) for results in imap_unordered_it: yield results
def test_index_lt(): assert Index("h0") < Index("G2")
def test_indices_so_latex_perm(): part = [[Index("g2")], [Index("p0"), Index("p1")], [Index("a4")]] n_perm, perm = IndicesSpinOrbital("p0, p1, g2, a4").latex_permute_format( part) assert n_perm == 12 assert perm == "{\\cal P} ( g_{2} / p_{0} p_{1} / a_{4} )"