예제 #1
0
def d1_q1_mapping(dim):
    """
    Map the ck to kc

    D1 + Q1 = I

    :param dim: linear dimension of the 1-RDM
    :return: the dual basis of the mapping
    :rtype: DualBasis
    """
    db = DualBasis()
    dbe_list = []
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            if i != j:
                dbe.add_element('ck', (i, j), 0.5)
                dbe.add_element('ck', (j, i), 0.5)
                dbe.add_element('kc', (j, i), 0.5)
                dbe.add_element('kc', (i, j), 0.5)
                dbe.dual_scalar = 0.0
            else:
                dbe.add_element('ck', (i, j), 1.0)
                dbe.add_element('kc', (i, j), 1.0)
                dbe.dual_scalar = 1.0

            # db += dbe
            dbe_list.append(dbe)

    return DualBasis(elements=dbe_list)  # db
예제 #2
0
def d2_d1_mapping(dim, normalization):
    """
    Construct dual basis for contracting d2 -> d1

    :param dim: linear dimension of the 1-RDM
    :param normalization: normalization constant for coeff of D1 elememnts
    :return: the dual basis of the contraction
    :rtype: DualBasis
    """
    db_basis = DualBasis()
    dbe_list = []
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            for r in range(dim):
                # duplicate entries get summed in DualBasisElement
                dbe.add_element('cckk', (i, r, j, r), 0.5)
                dbe.add_element('cckk', (j, r, i, r), 0.5)

            # D1 terms
            dbe.add_element('ck', (i, j), -0.5 * normalization)
            dbe.add_element('ck', (j, i), -0.5 * normalization)
            dbe.simplify()
            # db_basis += dbe
            dbe_list.append(dbe)

    return DualBasis(elements=dbe_list)  # db_basis
예제 #3
0
def d2_q2_mapping(dim):
    """
    Map each d2 block to the q2 block

    :param dim: rank of spatial single-particle basis
    :return:
    """
    krond = np.eye(dim)

    def d2q2element(p, q, r, s, factor, tname_d1_1, tname_d1_2, tname_d2,
                    tname_q2):
        dbe = DualBasisElement()
        dbe.add_element(tname_d1_1, (p, r), 2.0 * krond[q, s] * factor)
        dbe.add_element(tname_d1_2, (q, s), 2.0 * krond[p, r] * factor)
        dbe.add_element(tname_d1_1, (p, s), -2.0 * krond[r, q] * factor)
        dbe.add_element(tname_d1_2, (q, r), -2.0 * krond[p, s] * factor)
        dbe.add_element(tname_q2, (r, s, p, q), 1.0 * factor)
        dbe.add_element(tname_d2, (p, q, r, s), -1.0 * factor)

        # remember the negative sign because AX = b
        dbe.dual_scalar = -2.0 * krond[s, p] * krond[
            r, q] * factor + 2.0 * krond[q, s] * krond[r, p] * factor
        return dbe

    def d2q2element_ab(p, q, r, s, factor, tname_d1_1, tname_d1_2, tname_d2,
                       tname_q2):
        if tname_d1_1 != 'ck_a':
            raise TypeError("For some reason I am expecting a ck_a. Ask Nick")

        dbe = DualBasisElement()
        dbe.add_element(tname_d1_1, (p, r), krond[q, s] * factor)
        dbe.add_element(tname_d1_2, (q, s), krond[p, r] * factor)
        dbe.add_element(tname_q2, (r, s, p, q), 1.0 * factor)
        dbe.add_element(tname_d2, (p, q, r, s), -1.0 * factor)
        dbe.dual_scalar = krond[q, s] * krond[p, r] * factor
        return dbe

    db = DualBasis()
    d2_names = ['cckk_aa', 'cckk_bb', 'cckk_ab']
    q2_names = ['kkcc_aa', 'kkcc_bb', 'kkcc_ab']
    d1_names_1 = ['ck_a', 'ck_b', 'ck_a']
    d1_names_2 = ['ck_a', 'ck_b', 'ck_b']
    dual_basis_list = []
    for key in zip(d1_names_1, d1_names_2, d2_names, q2_names):
        d1_1, d1_2, d2_n, q2_n = key
        for p, q, r, s in product(range(dim), repeat=4):
            if (d2_n == 'cckk_aa' or d2_n == 'cckk_bb'
                ) and p < q and r < s and p * dim + q <= r * dim + s:
                dbe_1 = d2q2element(p, q, r, s, 0.5, d1_1, d1_2, d2_n, q2_n)
                dbe_2 = d2q2element(r, s, p, q, 0.5, d1_1, d1_2, d2_n, q2_n)
                # db += dbe_1.join_elements(dbe_2)
                dual_basis_list.append(dbe_1.join_elements(dbe_2))
            elif d2_n == 'cckk_ab' and p * dim + q <= r * dim + s:
                dbe_1 = d2q2element_ab(p, q, r, s, 0.5, d1_1, d1_2, d2_n, q2_n)
                dbe_2 = d2q2element_ab(r, s, p, q, 0.5, d1_1, d1_2, d2_n, q2_n)
                # db += dbe_1.join_elements(dbe_2)
                dual_basis_list.append(dbe_1.join_elements(dbe_2))

    return DualBasis(elements=dual_basis_list)
def test_d2_trace():
    n_density, rdm_generator, transform, molecule = system()
    assert np.isclose(molecule.fci_energy, -2.84383506834)

    density = AntiSymmOrbitalDensity(n_density, molecule.n_qubits)
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()
    bas_aa, bas_ab = geminal_spin_basis(molecule.n_orbitals)

    tpdm_aa = Tensor(tpdm_aa, name='cckk_aa', basis=bas_aa)
    tpdm_bb = Tensor(tpdm_bb, name='cckk_bb', basis=bas_aa)
    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([tpdm_aa, tpdm_bb, tpdm_ab])

    dual_basis = trace_d2_aa(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, b, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    bmat = b.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_bb(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_ab(molecule.n_orbitals, molecule.n_electrons / 2,
                             molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    db = DualBasis()
    db += trace_d2_aa(molecule.n_orbitals, molecule.n_electrons / 2)
    db += trace_d2_ab(molecule.n_orbitals, molecule.n_electrons / 2,
                      molecule.n_electrons / 2)
    db += trace_d2_bb(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = db
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))
예제 #5
0
def test_d2_trace_hubbard():
    n_density, rdm_generator = system_hubbard()

    density = AntiSymmOrbitalDensity(n_density, 8)
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()
    bas_aa, bas_ab = geminal_spin_basis(4)

    tpdm_aa = Tensor(tpdm_aa, name='cckk_aa', basis=bas_aa)
    tpdm_bb = Tensor(tpdm_bb, name='cckk_bb', basis=bas_aa)
    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([tpdm_aa, tpdm_bb, tpdm_ab])

    dual_basis = trace_d2_aa(4, 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, b, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    bmat = b.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_bb(4, 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_ab(4, 2, 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    db = DualBasis()
    db += trace_d2_aa(4, 2)
    db += trace_d2_ab(4, 2, 2)
    db += trace_d2_bb(4, 2)
    rdms.dual_basis = db
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))
예제 #6
0
    def __init__(self, tensors, dual_basis=DualBasis()):
        """
        A collection of tensor objects with algebraic maps from tensor to tensor

        In order to define a linear relationship between two tensors--i.e. the opdm
        and the oqdm-- a collection of maps objects can be generated.

        Mathematically, this is an object that allows you to define the dual basis on
        the vector space defined by the direct sum of all the tensors

        :param tensors: a dictionary or tuple of tensors and their associated call name
        :param DualBasisElement dual_basis:
        """
        if not isinstance(tensors, list):
            raise TypeError("MultiTensor accepts a list")

        # this preserves the order the user passes with the tensors
        self.tensors = TMap(tensors)

        # since all the tensors are indexed from zero...I need to know their
        # numbering offset when combined with everything.
        self.off_set_map = self.make_offset_dict(self.tensors)

        # An iterable object that provides access to the dual basis elements
        self.dual_basis = dual_basis
        self.vec_dim = sum([vec.size for vec in self.tensors])
예제 #7
0
def antisymmetry_constraints(dim):
    """
    The dual basis elements representing the antisymmetry constraints

    :param dim: spinless Fermion basis rank
    :return: the dual basis of antisymmetry_constraints
    :rtype: DualBasis
    """
    # dual_basis = DualBasis()
    dbe_list = []
    for p, q, r, s in product(range(dim), repeat=4):
        if p * dim + q <= r * dim + s:
            if p < q and r < s:
                tensor_elements = [
                    tuple(indices) for indices in _coord_generator(p, q, r, s)
                ]
                tensor_names = ['cckk'] * len(tensor_elements)
                tensor_coeffs = [0.5] * len(tensor_elements)
                dbe = DualBasisElement()
                for n, e, c in zip(tensor_names, tensor_elements,
                                   tensor_coeffs):
                    dbe.add_element(n, e, c)

                # dual_basis += dbe
                dbe_list.append(dbe)

    return DualBasis(elements=dbe_list)
예제 #8
0
def test_d2_spin_sz_rep():
    n_density, rdm_generator, transform, molecule = system()
    assert np.isclose(molecule.fci_energy, -2.84383506834)

    density = AntiSymmOrbitalDensity(n_density, molecule.n_qubits)
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()
    opdm_a, opdm_b = density.construct_opdm()
    bas_aa, bas_ab = geminal_spin_basis(molecule.n_orbitals)

    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    opdm_a = Tensor(opdm_a, name='ck_a')
    opdm_b = Tensor(opdm_b, name='ck_b')
    rdms = MultiTensor([opdm_a, opdm_b, tpdm_ab])

    dim = int(np.sqrt(tpdm_ab.data.shape[0]))
    sz_rep_value = 0
    for i in range(dim):
        sz_rep_value += 0.5 * (opdm_a.data[i, i] - opdm_b.data[i, i])

    N = molecule.n_electrons
    M = 0
    S = 0
    db = DualBasis()
    db += s_representability_d2ab(dim, N, M, S)
    db += sz_representability(dim, M)
    rdms.dual_basis = db
    xvec = rdms.vectorize_tensors()
    A, _, b = rdms.synthesize_dual_basis()
    assert np.allclose(A.dot(xvec) - b, 0.0)
예제 #9
0
def test_d2_spin_rep_hubbard():
    n_density, rdm_generator = system_hubbard()

    density = AntiSymmOrbitalDensity(n_density, 8)
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()
    bas_aa, bas_ab = geminal_spin_basis(4)

    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([tpdm_ab])

    dim = int(np.sqrt(tpdm_ab.data.shape[0]))
    s_rep_dual_constant = 0
    for i, j in product(range(dim), repeat=2):
        s_rep_dual_constant += tpdm_ab.data[bas_ab.rev((i, j)),
                                            bas_ab.rev((j, i))]

    N = 4
    M = 0
    S = 0
    db = DualBasis()
    db += s_representability_d2ab(dim, N, M, S)
    rdms.dual_basis = db
    xvec = rdms.vectorize_tensors()
    A, _, b = rdms.synthesize_dual_basis()
    assert np.allclose(A.dot(xvec) - b, 0.0)
    assert np.allclose(A.dot(xvec), s_rep_dual_constant)
예제 #10
0
def test_d2_spin_rep():
    n_density, rdm_generator, transform, molecule = system()
    assert np.isclose(molecule.fci_energy, -2.84383506834)

    density = AntiSymmOrbitalDensity(n_density, molecule.n_qubits)
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()
    bas_aa, bas_ab = geminal_spin_basis(molecule.n_orbitals)

    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([tpdm_ab])

    dim = int(np.sqrt(tpdm_ab.data.shape[0]))
    s_rep_dual_constant = 0
    for i, j in product(range(dim), repeat=2):
        s_rep_dual_constant += tpdm_ab.data[bas_ab.rev((i, j)),
                                            bas_ab.rev((j, i))]

    N = molecule.n_electrons
    M = 0
    S = 0
    db = DualBasis()
    db += s_representability_d2ab(dim, N, M, S)
    rdms.dual_basis = db
    xvec = rdms.vectorize_tensors()
    A, _, b = rdms.synthesize_dual_basis()
    assert np.allclose(A.dot(xvec) - b, 0.0)
    assert np.allclose(A.dot(xvec), s_rep_dual_constant)
예제 #11
0
def d2_to_t1_from_iterator(dim):
    """
    Generate T1 from the iteratively generated dbe elements

    :param dim:
    :return:
    """
    db = []
    # NOTE: Figure out why join_elements is not working
    for p, q, r, i, j, k in product(range(dim), repeat=6):
        if p != q and q != r and p != r and i != j and j != k and i != k:
            print(p, q, r, i, j, k)
            dbe = DualBasisElement()
            dbe.dual_scalar -= t1_dual_scalar(p, q, r, i, j, k)
            for element in t1_opdm_component(p, q, r, i, j, k):
                # dbe.join_elements(element)
                # print(element.primal_tensors_names, element.primal_elements, element.primal_coeffs)
                dbe.add_element(element.primal_tensors_names[0],
                                element.primal_elements[0],
                                element.primal_coeffs[0])
            for element in t1_tpdm_component(p, q, r, i, j, k):
                # dbe.join_elements(element)
                # print(element.primal_tensors_names, element.primal_elements, element.primal_coeffs)
                dbe.add_element(element.primal_tensors_names[0],
                                element.primal_elements[0],
                                element.primal_coeffs[0])
            dbe.add_element('t1', (p, q, r, i, j, k), -1.0)

            db.append(dbe)

    return DualBasis(elements=db)
예제 #12
0
def d2_to_t1(dim):
    """
    Generate the dual basis elements for mapping d2 and d1 to the T1-matrix

    The T1 condition is the sum of three-marginals

    T1 = <p^ q^ r^ i j k>  i j k p^ q^ r^>

    in such a fashion that any triples component cancels out. T1 will be
    represented over antisymmeterized basis functions to save a significant amount
    of space

    :param dim: spin-orbital basis dimension
    :return:
    """
    db = []  # DualBasis()
    for p, q, r, i, j, k in product(range(dim), repeat=6):
        # if (p * dim**2 + q * dim + r <= i * dim**2 + j * dim + k):
        print(p, q, r, i, j, k)
        dbe = DualBasisElement()
        dbe.dual_scalar -= (
            (-1.0) * kdelta(i, p) * kdelta(j, q) * kdelta(k, r) +
            (1.0) * kdelta(i, p) * kdelta(j, r) * kdelta(k, q) +
            (1.0) * kdelta(i, q) * kdelta(j, p) * kdelta(k, r) +
            (-1.0) * kdelta(i, q) * kdelta(j, r) * kdelta(k, p) +
            (-1.0) * kdelta(i, r) * kdelta(j, p) * kdelta(k, q) +
            (1.0) * kdelta(i, r) * kdelta(j, q) * kdelta(k, p))
        dbe.add_element('ck', (r, k), (1.0) * kdelta(i, p) * kdelta(j, q))
        dbe.add_element('ck', (q, k), (-1.0) * kdelta(i, p) * kdelta(j, r))
        dbe.add_element('ck', (r, j), (-1.0) * kdelta(i, p) * kdelta(k, q))
        dbe.add_element('ck', (q, j), (1.0) * kdelta(i, p) * kdelta(k, r))
        dbe.add_element('ck', (r, k), (-1.0) * kdelta(i, q) * kdelta(j, p))
        dbe.add_element('ck', (p, k), (1.0) * kdelta(i, q) * kdelta(j, r))
        dbe.add_element('ck', (r, j), (1.0) * kdelta(i, q) * kdelta(k, p))
        dbe.add_element('ck', (p, j), (-1.0) * kdelta(i, q) * kdelta(k, r))
        dbe.add_element('ck', (q, k), (1.0) * kdelta(i, r) * kdelta(j, p))
        dbe.add_element('ck', (p, k), (-1.0) * kdelta(i, r) * kdelta(j, q))
        dbe.add_element('ck', (q, j), (-1.0) * kdelta(i, r) * kdelta(k, p))
        dbe.add_element('ck', (p, j), (1.0) * kdelta(i, r) * kdelta(k, q))
        dbe.add_element('ck', (r, i), (1.0) * kdelta(j, p) * kdelta(k, q))
        dbe.add_element('ck', (q, i), (-1.0) * kdelta(j, p) * kdelta(k, r))
        dbe.add_element('ck', (r, i), (-1.0) * kdelta(j, q) * kdelta(k, p))
        dbe.add_element('ck', (p, i), (1.0) * kdelta(j, q) * kdelta(k, r))
        dbe.add_element('ck', (q, i), (1.0) * kdelta(j, r) * kdelta(k, p))
        dbe.add_element('ck', (p, i), (-1.0) * kdelta(j, r) * kdelta(k, q))
        dbe.add_element('cckk', (q, r, j, k), (1.0) * kdelta(i, p))
        dbe.add_element('cckk', (p, r, j, k), (-1.0) * kdelta(i, q))
        dbe.add_element('cckk', (p, q, j, k), (1.0) * kdelta(i, r))
        dbe.add_element('cckk', (q, r, i, k), (-1.0) * kdelta(j, p))
        dbe.add_element('cckk', (p, r, i, k), (1.0) * kdelta(j, q))
        dbe.add_element('cckk', (p, q, i, k), (-1.0) * kdelta(j, r))
        dbe.add_element('cckk', (q, r, i, j), (1.0) * kdelta(k, p))
        dbe.add_element('cckk', (p, r, i, j), (-1.0) * kdelta(k, q))
        dbe.add_element('cckk', (p, q, i, j), (1.0) * kdelta(k, r))
        dbe.add_element('t1', (p, q, r, i, j, k), -1.0)
        dbe.simplify()
        db.append(dbe)
    return DualBasis(elements=db)
예제 #13
0
def sz_adapted_linear_constraints(dim, Na, Nb, constraint_list, S=0, M=0):
    """
    Generate the dual basis for the v2-RDM program

    :param dim: rank of the spatial single-particle basis
    :param Na: Number of alpha electrons
    :param Nb: Number of beta electrons
    :param constraint_list:  List of strings indicating which constraints to make
    :return:
    """
    if Na != Nb and M == 0:
        raise TypeError("you gave me impossible quantum numbers")

    dual_basis = DualBasis()
    if 'cckk' in constraint_list:
        dual_basis += trace_d2_ab(dim, Na, Nb)
        dual_basis += s_representability_d2ab(dim, Na + Nb, M, S)

        # Including these would introduce linear independence.  Why?
        dual_basis += trace_d2_aa(dim, Na)
        dual_basis += trace_d2_bb(dim, Nb)

        if Na == Nb:
            dual_basis += s_representability_d2ab_to_d2aa(dim)
            dual_basis += s_representability_d2ab_to_d2bb(dim)

    if 'ck' in constraint_list:
        if Na > 1:
            dual_basis += d2aa_d1a_mapping(dim, Na)
            dual_basis += trace_d2_aa(dim, Na)
        else:
            dual_basis += trace_d2_aa(dim, Na)
        if Nb > 1:
            dual_basis += d2bb_d1b_mapping(dim, Nb)
            dual_basis += trace_d2_bb(dim, Nb)
        else:
            dual_basis += trace_d2_bb(dim, Nb)

        dual_basis += d2ab_d1b_mapping(dim, Na)
        dual_basis += d2ab_d1a_mapping(dim, Nb)

        dual_basis += d1a_q1a_mapping(dim)
        dual_basis += d1b_q1b_mapping(dim)

        # dual_basis += d1a_d1b_mapping('ck_a', 'ck_b', dim)

        # this might not be needed if s_representability is enforced
        if Na + Nb > 2:
            dual_basis += sz_representability(dim, M)

    if 'kkcc' in constraint_list:
        dual_basis += d2_q2_mapping(dim)

    if 'ckck' in constraint_list:
        dual_basis += d2_g2_mapping(dim)

    return dual_basis
예제 #14
0
def nb_constraint(dim, nb):
    """
    :param dim:
    :param sz:
    :return:
    """
    dbe = DualBasisElement()
    for i in range(dim // 2):
        dbe.add_element('ck', (2 * i + 1, 2 * i + 1), 1.0)
    dbe.dual_scalar = nb
    return DualBasis(elements=[dbe])
예제 #15
0
def d2_g2_mapping(dim):
    """
    Generate the mapping between d2 and g2

    :param dim: linear dimension of the 1-RDM
    :return: the dual basis of the mapping
    :rtype: DualBasis
    """
    krond = np.eye(dim)
    db = DualBasis()
    dbe_list = []

    def g2d2map(p, q, r, s, factor=1):
        """
        Build the dual basis element for a symmetric 2-marginal

        :param p: tensor index
        :param q: tensor index
        :param r: tensor index
        :param s: tensor index
        :param factor: weighting of the element
        :return: the dual basis element
        """
        dbe = DualBasisElement()
        dbe.add_element('ck', (p, r), -1. * krond[q, s] * factor)
        dbe.add_element('ckck', (p, s, r, q), 1.0 * factor)
        dbe.add_element('cckk', (p, q, r, s), 1.0 * factor)
        dbe.dual_scalar = 0

        return dbe

    for p, q, r, s in product(range(dim), repeat=4):
        if p * dim + q <= r * dim + s:
            db_element = g2d2map(p, q, r, s, factor=0.5)
            db_element_2 = g2d2map(r, s, p, q, factor=0.5)
            # db += db_element.join_elements(db_element_2)
            dbe_list.append(db_element.join_elements(db_element_2))

    return DualBasis(elements=dbe_list)  # db
예제 #16
0
def sz_constraint(dim, sz):
    """
    Sz constraint is on the 1-RDM
    :param dim:
    :param sz:
    :return:
    """
    dbe = DualBasisElement()
    for i in range(dim // 2):
        dbe.add_element('ck', (2 * i, 2 * i), 0.5)
        dbe.add_element('ck', (2 * i + 1, 2 * i + 1), -0.5)
    dbe.dual_scalar = sz
    return DualBasis(elements=[dbe])
예제 #17
0
def d2_e2_mapping(dim, measured_tpdm):
    """
    Generate the constraints between the error matrix, d2, and a measured d2.

    :param dim: dimension of the spin-orbital basis
    :param measured_tpdm:  a 4-tensor of the measured 2-p
    :return:
    """
    db_elements = []
    for p, q, r, s in product(range(dim), repeat=4):
        if p * dim + q >= r * dim + s:
            dbe = DualBasisElement()
            # two elements of d2
            dbe.add_element('cckk', (p, q, r, s), 0.5)
            dbe.add_element('cckk', (r, s, p, q), 0.5)

            # add four elements of the error matrix
            dbe.add_element('cckk_me', (p * dim + q + dim**2, r * dim + s),
                            -0.25)
            dbe.add_element('cckk_me', (r * dim + s + dim**2, p * dim + q),
                            -0.25)
            dbe.add_element('cckk_me', (p * dim + q, r * dim + s + dim**2),
                            -0.25)
            dbe.add_element('cckk_me', (r * dim + s, p * dim + q + dim**2),
                            -0.25)

            dbe.dual_scalar = measured_tpdm[p, q, r, s].real
            dbe.simplify()

            # construct the dual basis element for constraining the [0, 0] orthant to be identity matrix
            dbe_idenity = DualBasisElement()
            if p * dim + q == r * dim + s:
                dbe_idenity.add_element('cckk_me', (p * dim + q, r * dim + s),
                                        1.0)
                dbe_idenity.dual_scalar = 1.0
            else:
                # will a symmetric constraint provide variational freedom?
                dbe_idenity.add_element('cckk_me', (p * dim + q, r * dim + s),
                                        0.5)
                dbe_idenity.add_element('cckk_me', (r * dim + s, p * dim + q),
                                        0.5)
                dbe_idenity.dual_scalar = 0.0

            db_elements.append(dbe)
            db_elements.append(dbe_idenity)

    return DualBasis(elements=db_elements)
예제 #18
0
def _contraction_base(tname_d2, tname_d1, dim, normalization, offset):
    db = DualBasis()
    for i in range(dim):
        for j in range(i + offset, dim):
            dbe = DualBasisElement()
            for r in range(dim):
                dbe.add_element(tname_d2, (i, r, j, r), 0.5)
                dbe.add_element(tname_d2, (j, r, i, r), 0.5)

            dbe.add_element(tname_d1, (i, j), -0.5 * normalization)
            dbe.add_element(tname_d1, (j, i), -0.5 * normalization)
            dbe.dual_scalar = 0

            # dbe.simplify()
            db += dbe

    return db
예제 #19
0
def d2bb_d1b_mapping(dim, Nb):
    """
    Map the d2_spin-adapted 2-RDM to the D1 rdm

    :param Nb: number of beta electrons
    :param dim:
    :return:
    """
    db = DualBasis()
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            for r in range(dim):
                # Not in the basis because always zero
                if i == r or j == r:
                    continue
                else:
                    sir = 1 if i < r else -1
                    sjr = 1 if j < r else -1
                    ir_pair = (i, r) if i < r else (r, i)
                    jr_pair = (j, r) if j < r else (r, j)
                    if i == j:
                        dbe.add_element(
                            'cckk_bb',
                            (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]),
                            sir * sjr * 0.5)
                    else:
                        # TODO: Remember why I derived a factor of 0.25 (0.5 above) for this equation.
                        dbe.add_element(
                            'cckk_bb',
                            (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]),
                            sir * sjr * 0.25)
                        dbe.add_element(
                            'cckk_bb',
                            (jr_pair[0], jr_pair[1], ir_pair[0], ir_pair[1]),
                            sir * sjr * 0.25)

            dbe.add_element('ck_b', (i, j), -0.5 * (Nb - 1))
            dbe.add_element('ck_b', (j, i), -0.5 * (Nb - 1))
            dbe.dual_scalar = 0

            dbe.simplify()
            db += dbe

    return db
예제 #20
0
def spin_orbital_linear_constraints(dim, N, constraint_list):
    """
    Genrate the dual basis for the v2-RDM program

    :param dim: rank of spinless fermion basis
    :param N: Total number of electrons
    :param constraint_list:  List of strings indicating which constraints to make
    :return:  Dual basis for the constraint program
    :rtype: DualBasis
    """

    dual_basis = DualBasis()
    if 'cckk' in constraint_list:
        print("d2 constraints")
        # trace constraint on D2
        dual_basis += trace_constraint(dim, N * (N - 1))

        # antisymmetry constraint
        print("antisymmetry constraint")
        dual_basis += antisymmetry_constraints(dim)

    if 'ck' in constraint_list:
        print("opdm constraints")
        dual_basis += d2_d1_mapping(dim, N - 1)
        dual_basis += d1_q1_mapping(dim)

    # d2 -> q2
    if 'kkcc' in constraint_list:
        print('tqdm constraints')
        dual_basis += d2_q2_mapping(dim)

    # d2 -> g2
    if "ckck" in constraint_list:
        print('phdm constraints')
        dual_basis += d2_g2_mapping(dim)

    # d2, d1 -> T1
    if "t1" in constraint_list:
        # this uses an antisymmeterized form of the T1 matrix since it's really
        # not feasible to store r^{6} elements
        print('t1 constrinat')
        dual_basis += d2_to_t1_matrix_antisym(dim)

    return dual_basis
예제 #21
0
def d2aa_d1a_mapping(dim, Na):
    """
    Map the d2_spin-adapted 2-RDM to the D1 rdm

    :param Nb: number of beta electrons
    :param dim:
    :return:
    """
    db = DualBasis()
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            for r in range(dim):
                # Not in the basis because always zero
                if i == r or j == r:
                    continue
                else:
                    sir = 1 if i < r else -1
                    sjr = 1 if j < r else -1
                    ir_pair = (i, r) if i < r else (r, i)
                    jr_pair = (j, r) if j < r else (r, j)
                    if i == j:
                        dbe.add_element(
                            'cckk_aa',
                            (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]),
                            sir * sjr)
                    else:
                        dbe.add_element(
                            'cckk_aa',
                            (ir_pair[0], ir_pair[1], jr_pair[0], jr_pair[1]),
                            sir * sjr * 0.5)
                        dbe.add_element(
                            'cckk_aa',
                            (jr_pair[0], jr_pair[1], ir_pair[0], ir_pair[1]),
                            sir * sjr * 0.5)

            dbe.add_element('ck_a', (i, j), -0.5 * (Na - 1))
            dbe.add_element('ck_a', (j, i), -0.5 * (Na - 1))
            dbe.dual_scalar = 0

            # dbe.simplify()
            db += dbe

    return db
예제 #22
0
def d2_q2_mapping(dim):
    """
    Generate dual basis elements for d2-> q2 mapping

    :param dim: linear dimension of the 1-RDM
    :return: the dual basis of the mapping
    :rtype: DualBasis
    """
    krond = np.eye(dim)
    # db = DualBasis()
    dbe_list = []

    def d2q2element(p, q, r, s, factor):
        """
        Build the dual basis element for symmetric form of 2-marginal

        :param p: tensor index
        :param q: tensor index
        :param r: tensor index
        :param s: tensor index
        :param factor: scaling coeff for a symmetric constraint
        :return: the dual basis of the mapping
        """
        dbe = DualBasisElement()
        dbe.add_element('cckk', (p, q, r, s), -1.0 * factor)
        dbe.add_element('kkcc', (r, s, p, q), +1.0 * factor)
        dbe.add_element('ck', (p, r), krond[q, s] * factor)
        dbe.add_element('ck', (q, s), krond[p, r] * factor)
        dbe.add_element('ck', (p, s), -1. * krond[q, r] * factor)
        dbe.add_element('ck', (q, r), -1. * krond[p, s] * factor)
        dbe.dual_scalar = (krond[q, s] * krond[p, r] -
                           krond[q, r] * krond[p, s]) * factor

        return dbe

    for p, q, r, s in product(range(dim), repeat=4):
        if p * dim + q <= r * dim + s:
            db_element = d2q2element(p, q, r, s, 0.5)
            db_element_2 = d2q2element(r, s, p, q, 0.5)
            # db += db_element.join_elements(db_element_2)
            dbe_list.append(db_element.join_elements(db_element_2))

    return DualBasis(elements=dbe_list)  # db
예제 #23
0
def _d1_q1_mapping(tname_d1, tname_q1, dim):
    db = DualBasis()
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            if i != j:
                dbe.add_element(tname_d1, (i, j), 0.5)
                dbe.add_element(tname_d1, (j, i), 0.5)
                dbe.add_element(tname_q1, (i, j), 0.5)
                dbe.add_element(tname_q1, (j, i), 0.5)
                dbe.dual_scalar = 0.0
            else:
                dbe.add_element(tname_d1, (i, j), 1.0)
                dbe.add_element(tname_q1, (i, j), 1.0)
                dbe.dual_scalar = 1.0

            db += dbe.simplify()

    return db
예제 #24
0
def d1a_d1b_mapping(tname_d1a, tname_d1b, dim):
    db = DualBasis()
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            if i != j:
                dbe.add_element(tname_d1a, (i, j), 0.5)
                dbe.add_element(tname_d1a, (j, i), 0.5)
                dbe.add_element(tname_d1b, (i, j), -0.5)
                dbe.add_element(tname_d1b, (j, i), -0.5)
                dbe.dual_scalar = 0.0
            else:
                dbe.add_element(tname_d1a, (i, j), 1.0)
                dbe.add_element(tname_d1b, (i, j), -1.0)
                dbe.dual_scalar = 0.0

            db += dbe  # .simplify()

    return db
예제 #25
0
def d2ab_d1b_mapping(dim, Na):
    """
    Map the d2_spin-adapted 2-RDM to the D1 rdm

    :param Nb: number of beta electrons
    :param dim:
    :return:
    """
    db = DualBasis()
    for i in range(dim):
        for j in range(i, dim):
            dbe = DualBasisElement()
            for r in range(dim):
                dbe.add_element('cckk_ab', (r, i, r, j), 0.5)
                dbe.add_element('cckk_ab', (r, j, r, i), 0.5)

            dbe.add_element('ck_b', (i, j), -0.5 * Na)
            dbe.add_element('ck_b', (j, i), -0.5 * Na)
            dbe.dual_scalar = 0

            # dbe.simplify()
            db += dbe

    return db
예제 #26
0
def test_d2_d1_mapping():
    n_density, rdm_generator, transform, molecule = system_h4()

    density = AntiSymmOrbitalDensity(n_density, molecule.n_qubits)
    tpdm_aa, tpdm_bb, tpdm_ab, [bas_aa, bas_ab] = density.construct_tpdm()
    opdm_a, opdm_b = density.construct_opdm()

    from itertools import product
    test_opdm = np.zeros_like(opdm_a)
    for i, j in product(range(opdm_a.shape[0]), repeat=2):
        if i <= j:
            for r in range(opdm_a.shape[0]):
                if i != r and j != r:
                    top_gem = tuple(sorted([i, r]))
                    bot_gem = tuple(sorted([j, r]))
                    parity = (-1)**(r < i) * (-1)**(r < j)
                    if i == j:
                        test_opdm[i, j] += tpdm_aa[bas_aa[top_gem],
                                                   bas_aa[bot_gem]] * parity
                    else:
                        test_opdm[j,
                                  i] += tpdm_aa[bas_aa[top_gem],
                                                bas_aa[bot_gem]] * parity * 0.5
                        test_opdm[j,
                                  i] += tpdm_aa[bas_aa[bot_gem],
                                                bas_aa[top_gem]] * parity * 0.5
                        test_opdm[i,
                                  j] += tpdm_aa[bas_aa[top_gem],
                                                bas_aa[bot_gem]] * parity * 0.5
                        test_opdm[i,
                                  j] += tpdm_aa[bas_aa[bot_gem],
                                                bas_aa[top_gem]] * parity * 0.5

    assert np.allclose(test_opdm, opdm_a)

    bas_aa, bas_ab = geminal_spin_basis(molecule.n_orbitals)
    opdm_a = Tensor(opdm_a, name='ck_a')
    opdm_b = Tensor(opdm_b, name='ck_b')
    tpdm_aa = Tensor(tpdm_aa, name='cckk_aa', basis=bas_aa)
    tpdm_bb = Tensor(tpdm_bb, name='cckk_bb', basis=bas_aa)
    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([opdm_a, opdm_b, tpdm_aa, tpdm_bb, tpdm_ab])

    # d2ab_d1a test
    dual_basis = DualBasis()
    dual_basis = d2ab_d1a_mapping(molecule.n_orbitals,
                                  molecule.n_electrons / 2)
    dual_basis += d2ab_d1b_mapping(molecule.n_orbitals,
                                   molecule.n_electrons / 2)
    dual_basis += d2aa_d1a_mapping(molecule.n_orbitals,
                                   molecule.n_electrons / 2)
    dual_basis += d2bb_d1b_mapping(molecule.n_orbitals,
                                   molecule.n_electrons / 2)
    rdms.dual_basis = dual_basis
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    w, v = np.linalg.eigh(np.dot(Amat, Amat.T))
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))
예제 #27
0
def d2_q2_mapping(dim):
    """
    Map each d2 block to the q2 block

    :param dim: rank of spatial single-particle basis
    :return:
    """
    krond = np.eye(dim)

    def d2q2element(p, q, r, s, factor, tname_d1_1, tname_d2,
                    tname_q2):  # , spin_string):
        """
        # (   1.00000) cre(r) cre(s) des(q) des(p)

        # (   1.00000) kdelta(p,s) cre(r) des(q)

        # (  -1.00000) kdelta(p,r) cre(s) des(q)

        # (  -1.00000) kdelta(q,s) cre(r) des(p)

        # (   1.00000) kdelta(q,r) cre(s) des(p)

        # (  -1.00000) kdelta(p,s) kdelta(q,r)
        # (   1.00000) kdelta(p,r) kdelta(q,s)
        """
        dbe = DualBasisElement()
        dbe.add_element(tname_q2, (p, q, r, s), -factor)
        dbe.add_element(tname_d2, (r, s, p, q), factor)

        if p == s:
            dbe.add_element(tname_d1_1, (r, q), factor)
        if p == r:
            dbe.add_element(tname_d1_1, (s, q), -factor)
        if q == s:
            dbe.add_element(tname_d1_1, (r, p), -factor)
        if q == r:
            dbe.add_element(tname_d1_1, (s, p), factor)

        # remember the negative sign because AX = b
        dbe.dual_scalar = -factor * (krond[p, r] * krond[q, s] -
                                     krond[p, s] * krond[q, r])

        # dbe.add_element('kkcc_' + spin_string + spin_string, (r, s, p, q), factor)
        # if q == s:
        #     dbe.add_element('ck_' + spin_string, (p, r), factor)
        # if p == s:
        #     dbe.add_element('ck_' + spin_string, (q, r), -factor)
        # if q == r:
        #     dbe.add_element('kc_' + spin_string, (s, p), factor)
        # if p == r:
        #     dbe.add_element('kc_' + spin_string, (s, q), -factor)

        # dbe.add_element('cckk_' + spin_string + spin_string, (p, q, r, s), -factor)
        # dbe.dual_scalar = 0
        return dbe

    def d2q2element_ab(p, q, r, s, factor):
        dbe = DualBasisElement()
        if q == s:
            dbe.add_element('ck_a', (p, r), factor)
        if p == r:
            dbe.add_element('kc_b', (s, q), -factor)

        dbe.add_element('kkcc_ab', (r, s, p, q), factor)
        dbe.add_element('cckk_ab', (p, q, r, s), -factor)
        # dbe.dual_scalar = -krond[q, s]*krond[p, r] * factor
        dbe.dual_scalar = 0
        return dbe

    dual_basis_list = []
    # for p, q, r, s in product(range(dim), repeat=4):
    from representability.tensor import index_tuple_basis
    gem_aa = []
    gem_ab = []
    for p, q in product(range(dim), repeat=2):
        if p < q:
            gem_aa.append((p, q))
        gem_ab.append((p, q))

    bas_aa = index_tuple_basis(gem_aa)
    bas_ab = index_tuple_basis(gem_ab)

    for i, j in product(range(dim * (dim - 1) // 2), repeat=2):
        if i >= j:
            p, q = bas_aa.fwd(i)
            r, s = bas_aa.fwd(j)
            # if p < q and r < s and p * dim + q < r * dim + s:
            dbe1 = d2q2element(p, q, r, s, 0.5, 'ck_a', 'cckk_aa', 'kkcc_aa')
            dbe2 = d2q2element(r, s, p, q, 0.5, 'ck_a', 'cckk_aa', 'kkcc_aa')
            # dbe1 = d2q2element(p, q, r, s, 0.5, 'a')
            # dbe2 = d2q2element(r, s, p, q, 0.5, 'a')
            dual_basis_list.append(dbe1.join_elements(dbe2))

            # dbe1 = d2q2element(p, q, r, s, 0.5, 'b')
            # dbe2 = d2q2element(r, s, p, q, 0.5, 'b')
            dbe1 = d2q2element(p, q, r, s, 0.5, 'ck_b', 'cckk_bb', 'kkcc_bb')
            dbe2 = d2q2element(r, s, p, q, 0.5, 'ck_b', 'cckk_bb', 'kkcc_bb')
            dual_basis_list.append(dbe1.join_elements(dbe2))

        # # if p < q and r < s and p == r and q == s:
        #     # dbe1 = d2q2element(p, q, r, s, 1., 'a')
        #     dbe = d2q2element(p, q, r, s, 1., 'ck_a', 'cckk_aa', 'kkcc_aa')
        #     dual_basis_list.append(dbe)

        #     # # dbe1 = d2q2element(p, q, r, s, 1., 'b')
        #     dbe = d2q2element(p, q, r, s, 1., 'ck_b', 'cckk_bb', 'kkcc_bb')
        #     dual_basis_list.append(dbe)

    for i, j in product(range(dim * dim), repeat=2):
        if i >= j:
            p, q = bas_ab.fwd(i)
            r, s = bas_ab.fwd(j)
            # if p * dim + q <= r * dim + s:
            dbe1 = d2q2element_ab(p, q, r, s, 0.5)
            dbe2 = d2q2element_ab(r, s, p, q, 0.5)
            dual_basis_list.append(dbe1.join_elements(dbe2))

    return DualBasis(elements=dual_basis_list)
예제 #28
0
def d2_e2_mapping(dim, bas_aa, bas_ab, measured_tpdm_aa, measured_tpdm_bb,
                  measured_tpdm_ab):
    """
    Generate constraints such that the error matrix and the d2 matrices look like the measured matrices

    :param dim: spatial basis dimension
    :param measured_tpdm_aa: two-marginal of alpha-alpha spins
    :param measured_tpdm_bb: two-marginal of beta-beta spins
    :param measured_tpdm_ab: two-marginal of alpha-beta spins
    :return:
    """
    db = DualBasis()
    # first constrain the aa-matrix
    aa_dim = dim * (dim - 1) / 2
    ab_dim = dim**2

    # map the aa matrix to the measured_tpdm_aa
    for p, q, r, s in product(range(dim), repeat=4):
        if p < q and r < s and bas_aa[(p, q)] <= bas_aa[(r, s)]:
            dbe = DualBasisElement()

            # two elements of D2aa
            dbe.add_element('cckk_aa', (p, q, r, s), 0.5)
            dbe.add_element('cckk_aa', (r, s, p, q), 0.5)

            # four elements of the E2aa
            dbe.add_element('cckk_me_aa',
                            (bas_aa[(p, q)] + aa_dim, bas_aa[(r, s)]), 0.25)
            dbe.add_element('cckk_me_aa',
                            (bas_aa[(r, s)] + aa_dim, bas_aa[(p, q)]), 0.25)
            dbe.add_element('cckk_me_aa',
                            (bas_aa[(p, q)], bas_aa[(r, s)] + aa_dim), 0.25)
            dbe.add_element('cckk_me_aa',
                            (bas_aa[(r, s)], bas_aa[(p, q)] + aa_dim), 0.25)

            dbe.dual_scalar = measured_tpdm_aa[bas_aa[(p, q)],
                                               bas_aa[(r, s)]].real
            dbe.simplify()

            # construct the dbe for constraining the [0, 0] orthant to the idenity matrix
            dbe_identity_aa = DualBasisElement()
            if bas_aa[(p, q)] == bas_aa[(r, s)]:
                dbe_identity_aa.add_element('cckk_me_aa',
                                            (bas_aa[(p, q)], bas_aa[(r, s)]),
                                            1.0)
                dbe_identity_aa.dual_scalar = 1.0
            else:
                dbe_identity_aa.add_element('cckk_me_aa',
                                            (bas_aa[(p, q)], bas_aa[(r, s)]),
                                            0.5)
                dbe_identity_aa.add_element('cckk_me_aa',
                                            (bas_aa[(r, s)], bas_aa[(p, q)]),
                                            0.5)
                dbe_identity_aa.dual_scalar = 0.0

            db += dbe
            db += dbe_identity_aa

    # map the bb matrix to the measured_tpdm_bb
    for p, q, r, s in product(range(dim), repeat=4):
        if p < q and r < s and bas_aa[(p, q)] <= bas_aa[(r, s)]:
            dbe = DualBasisElement()

            # two elements of D2bb
            dbe.add_element('cckk_bb', (p, q, r, s), 0.5)
            dbe.add_element('cckk_bb', (r, s, p, q), 0.5)

            # four elements of the E2bb
            dbe.add_element('cckk_me_bb',
                            (bas_aa[(p, q)] + aa_dim, bas_aa[(r, s)]), 0.25)
            dbe.add_element('cckk_me_bb',
                            (bas_aa[(r, s)] + aa_dim, bas_aa[(p, q)]), 0.25)
            dbe.add_element('cckk_me_bb',
                            (bas_aa[(p, q)], bas_aa[(r, s)] + aa_dim), 0.25)
            dbe.add_element('cckk_me_bb',
                            (bas_aa[(r, s)], bas_aa[(p, q)] + aa_dim), 0.25)

            dbe.dual_scalar = measured_tpdm_bb[bas_aa[(p, q)],
                                               bas_aa[(r, s)]].real
            dbe.simplify()

            # construct the dbe for constraining the [0, 0] orthant to the idenity matrix
            dbe_identity_bb = DualBasisElement()
            if bas_aa[(p, q)] == bas_aa[(r, s)]:
                dbe_identity_bb.add_element('cckk_me_bb',
                                            (bas_aa[(p, q)], bas_aa[(r, s)]),
                                            1.0)
                dbe_identity_bb.dual_scalar = 1.0
            else:
                dbe_identity_bb.add_element('cckk_me_bb',
                                            (bas_aa[(p, q)], bas_aa[(r, s)]),
                                            0.5)
                dbe_identity_bb.add_element('cckk_me_bb',
                                            (bas_aa[(r, s)], bas_aa[(p, q)]),
                                            0.5)
                dbe_identity_bb.dual_scalar = 0.0

            db += dbe
            db += dbe_identity_bb

    # map the ab matrix to the measured_tpdm_ab
    for p, q, r, s in product(range(dim), repeat=4):
        if bas_ab[(p, q)] <= bas_ab[(r, s)]:
            dbe = DualBasisElement()

            # two elements of D2ab
            dbe.add_element('cckk_ab', (p, q, r, s), 0.5)
            dbe.add_element('cckk_ab', (r, s, p, q), 0.5)

            # four elements of the E2ab
            dbe.add_element('cckk_me_ab',
                            (bas_ab[(p, q)] + ab_dim, bas_ab[(r, s)]), 0.25)
            dbe.add_element('cckk_me_ab',
                            (bas_ab[(r, s)] + ab_dim, bas_ab[(p, q)]), 0.25)
            dbe.add_element('cckk_me_ab',
                            (bas_ab[(p, q)], bas_ab[(r, s)] + ab_dim), 0.25)
            dbe.add_element('cckk_me_ab',
                            (bas_ab[(r, s)], bas_ab[(p, q)] + ab_dim), 0.25)

            dbe.dual_scalar = measured_tpdm_ab[bas_ab[(p, q)],
                                               bas_ab[(r, s)]].real
            dbe.simplify()

            # construct the dbe for constraining the [0, 0] orthant to the idenity matrix
            dbe_identity_ab = DualBasisElement()
            if bas_ab[(p, q)] == bas_ab[(r, s)]:
                dbe_identity_ab.add_element('cckk_me_ab',
                                            (bas_ab[(p, q)], bas_ab[(r, s)]),
                                            1.0)
                dbe_identity_ab.dual_scalar = 1.0
            else:
                dbe_identity_ab.add_element('cckk_me_ab',
                                            (bas_ab[(p, q)], bas_ab[(r, s)]),
                                            0.5)
                dbe_identity_ab.add_element('cckk_me_ab',
                                            (bas_ab[(r, s)], bas_ab[(p, q)]),
                                            0.5)
                dbe_identity_ab.dual_scalar = 0.0

            db += dbe
            db += dbe_identity_ab

    return db
예제 #29
0
def d2_g2_mapping(dim):
    """
    Map each d2 blcok to the g2 blocks

    :param dim: rank of spatial single-particle basis
    :return:
    """
    krond = np.eye(dim)

    # d2 -> g2

    def g2d2map_aa_or_bb(p, q, r, s, dim, key, factor=1.0):
        """
        Accept pqrs of G2 and map to D2
        """
        dbe = DualBasisElement()
        quad = {'aa': [0, 0], 'bb': [1, 1]}
        dbe.add_element('ckck_aabb', (p * dim + q + quad[key][0] * dim**2,
                                      r * dim + s + quad[key][1] * dim**2),
                        -1.0 * factor)
        if q == s:
            dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor)
        if p != s and r != q:
            gem1 = tuple(sorted([p, s]))
            gem2 = tuple(sorted([r, q]))
            parity = (-1)**(p < s) * (-1)**(r < q)
            # factor of 0.5 is from the spin-adapting
            dbe.add_element('cckk_' + key,
                            (gem1[0], gem1[1], gem2[0], gem2[1]),
                            parity * -factor)

        dbe.dual_scalar = 0
        return dbe

    def g2d2map_aabb(p, q, r, s, dim, key, factor=1.0):
        """
        Accept pqrs of G2 and map to D2
        """
        dbe = DualBasisElement()
        # this is ugly.  :(
        quad = {'aabb': [0, 1], 'bbaa': [1, 0]}
        dbe.add_element('ckck_aabb', (p * dim + q + quad[key][0] * dim**2,
                                      r * dim + s + quad[key][1] * dim**2),
                        1.0 * factor)
        dbe.add_element('ckck_aabb',
                        (r * dim + s + quad[key[::-1]][0] * dim**2,
                         p * dim + q + quad[key[::-1]][1] * dim**2),
                        1.0 * factor)

        dbe.add_element('cckk_ab', (p, s, q, r), -1.0 * factor)
        dbe.add_element('cckk_ab', (q, r, p, s), -1.0 * factor)
        dbe.dual_scalar = 0.0
        return dbe

    def g2d2map_ab(p, q, r, s, key, factor=1.0):
        dbe = DualBasisElement()
        if key == 'ab':
            if q == s:
                dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor)

            dbe.add_element('cckk_' + key, (p, s, r, q), -1.0 * factor)
        elif key == 'ba':
            if q == s:
                dbe.add_element('ck_' + key[0], (p, r), krond[q, s] * factor)

            dbe.add_element('cckk_ab', (s, p, q, r), -1.0 * factor)
        else:
            raise TypeError("I only accept ab or ba blocks")

        dbe.add_element('ckck_' + key, (p, q, r, s), -1.0 * factor)
        dbe.dual_scalar = 0.0
        return dbe

    dual_basis_list = []
    # do aa_aa block then bb_block of the superblock
    for key in ['bb', 'aa']:
        for p, q, r, s in product(range(dim), repeat=4):
            if p * dim + q <= r * dim + s:
                dbe_1 = g2d2map_aa_or_bb(p, q, r, s, dim, key, factor=0.5)
                dbe_2 = g2d2map_aa_or_bb(r, s, p, q, dim, key, factor=0.5)
                dual_basis_list.append(dbe_1.join_elements(dbe_2))

    # this constraint is over the entire block!
    for key in ['aabb']:
        for p, q, r, s in product(range(dim), repeat=4):
            dbe = g2d2map_aabb(p, q, r, s, dim, key, factor=1.0)
            # db += dbe
            dual_basis_list.append(dbe)

    # # ab ba blocks of G2
    for key in ['ab', 'ba']:
        for p, q, r, s in product(range(dim), repeat=4):
            if p * dim + q <= r * dim + s:
                dbe_1 = g2d2map_ab(p, q, r, s, key, factor=0.5)
                dbe_2 = g2d2map_ab(r, s, p, q, key, factor=0.5)
                dual_basis_list.append(dbe_1.join_elements(dbe_2))

    return DualBasis(elements=dual_basis_list)
예제 #30
0
def test_d2_trace_h4():
    n_density, rdm_generator, transform, molecule = system_h4()

    density = AntiSymmOrbitalDensity(n_density, molecule.n_qubits)
    dim = molecule.n_orbitals
    tpdm_aa, tpdm_bb, tpdm_ab, _ = density.construct_tpdm()

    Na, Nb = 2, 2
    trace_ab = 0
    for i, j in product(range(molecule.n_orbitals), repeat=2):
        trace_ab += tpdm_ab[i * dim + j, i * dim + j]
    assert np.isclose(trace_ab, Na, Nb)
    assert np.isclose(np.trace(tpdm_aa), Na * (Na - 1) / 2)
    assert np.isclose(np.trace(tpdm_bb), Nb * (Nb - 1) / 2)
    bas_aa, bas_ab = geminal_spin_basis(molecule.n_orbitals)

    tpdm_aa = Tensor(tpdm_aa, name='cckk_aa', basis=bas_aa)
    tpdm_bb = Tensor(tpdm_bb, name='cckk_bb', basis=bas_aa)
    tpdm_ab = Tensor(tpdm_ab, name='cckk_ab', basis=bas_ab)
    rdms = MultiTensor([tpdm_aa, tpdm_bb, tpdm_ab])

    dual_basis = trace_d2_aa(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, b, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    bmat = b.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_bb(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    dual_basis = trace_d2_ab(molecule.n_orbitals, molecule.n_electrons / 2,
                             molecule.n_electrons / 2)
    rdms.dual_basis = DualBasis(elements=[dual_basis])
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))

    db = DualBasis()
    db += trace_d2_aa(molecule.n_orbitals, molecule.n_electrons / 2)
    db += trace_d2_ab(molecule.n_orbitals, molecule.n_electrons / 2,
                      molecule.n_electrons / 2)
    db += trace_d2_bb(molecule.n_orbitals, molecule.n_electrons / 2)
    rdms.dual_basis = db
    A, _, c = rdms.synthesize_dual_basis()
    Amat = A.todense()
    cmat = c.todense()

    primal_vec = rdms.vectorize_tensors()
    residual = Amat.dot(primal_vec) - cmat
    assert np.allclose(residual, np.zeros_like(residual))