def test_possible_excitation(): assert SecondQuantizedOperator("g0, g1", "g2, p0").is_possible_excitation() assert SecondQuantizedOperator("p0, p1", "c0, h0").is_possible_excitation() assert not SecondQuantizedOperator("c0, h0", "p0, p1").is_possible_excitation() assert not SecondQuantizedOperator("a0, A0", "a1, A1", 'si').is_possible_excitation()
def test_init(): id_type = 'spin-orbital' assert SecondQuantizedOperator([], []).is_empty() a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", id_type) assert a.cre_ops == Indices.make_indices("g0,g1,g2", id_type) assert a.ann_ops == Indices.make_indices("p0,p1,p2", id_type) assert a.n_ann == 3 assert a.n_cre == 3
def test_eq(): a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'spin-orbital') b = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'so') assert a is not b assert a == b with pytest.raises(TypeError): assert a == IndicesPair("g0,g1,g2", "p0,p1,p2", 'spin-orbital') with pytest.raises(TypeError): assert a == SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'spin-integrated')
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_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 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_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_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_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_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 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_canonicalize_1(): 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')) with pytest.raises(NotImplementedError): assert a.canonicalize()
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_is_spin_conserving(): assert SecondQuantizedOperator("p0", "p0", 'si').is_spin_conserving() assert not SecondQuantizedOperator("p0", "H0", 'si').is_spin_conserving() with pytest.raises(ValueError): assert SecondQuantizedOperator("p0", "p0, p1", 'so').is_spin_conserving()
def test_ambit_permute_format_3(): # TODO: is this necessary? # ignore all input partitions for mixed spin indices a = SecondQuantizedOperator("g0,G1,c2", "p0,p1,P2", 'spin-integrated') for pair in a.ambit_permute_format([], [], cre_first=True): assert pair == (1, '["g0,G1,c2,p0,p1,P2"]')
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_base_strong_generating_set(): with pytest.raises(ValueError): SecondQuantizedOperator("", "", 'si').base_strong_generating_set()
def test_void(): a = SecondQuantizedOperator("G2, p0, p1", "g0, A0, h2", 'si') b = a.void() assert a.indices_type == b.indices_type assert b.size == 0 assert b is not SecondQuantizedOperator.make_empty('si')
def test_ambit_permute_format_1(): # empty sq_op ignores all input partitions a = SecondQuantizedOperator([], [], 'spin-orbital') for pair in a.ambit_permute_format([], []): assert pair == (1, '')
def test_canonicalize(): a = SecondQuantizedOperator("G2, p0, p1", "g0, A0, h2, A2", 'si') c, sign = a.canonicalize() assert c == SecondQuantizedOperator("p0, p1, G2", "g0, h2, A0, A2", 'si') assert sign == -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_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_lt(): a = SecondQuantizedOperator("g0,g1,g2", "p0,P1,p2", 'spin-integrated') assert a < SecondQuantizedOperator("g0,g1,g2", "p0,P1,p2,p3", 'si') assert a < SecondQuantizedOperator("g0,g1,g2", "p0,P2,p2", 'si')
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_ge(): a = SecondQuantizedOperator("G0,G1,g2", "p0,P1,P2", 'spin-integrated') assert a >= SecondQuantizedOperator("g0,g1,g2", "p0,P1,p2,p3", 'si') with pytest.raises(TypeError): assert a >= 1
def test_ne(): a = SecondQuantizedOperator("g0,g1,g2", "p0,p1,p2", 'so') assert a != SecondQuantizedOperator(["g0", "v1", "p2"], ["p0", "a1", "p2"])
def test_is_particle_conserving(): assert SecondQuantizedOperator("G0,G1,g2", "p0,P1,P2", 'spin-integrated').is_particle_conserving() assert SecondQuantizedOperator("p0", "p0", 'so').is_particle_conserving() assert not SecondQuantizedOperator("p0", "p0, p1", 'so').is_particle_conserving()