示例#1
0
    def test_split_operator_error_operator_VT_order_against_definition(self):
        hamiltonian = (normal_ordered(fermi_hubbard(3, 3, 1., 4.0)) -
                       2.3 * FermionOperator.identity())
        potential_terms, kinetic_terms = (
            diagonal_coulomb_potential_and_kinetic_terms_as_arrays(
                hamiltonian))
        potential = sum(potential_terms, FermionOperator.zero())
        kinetic = sum(kinetic_terms, FermionOperator.zero())

        error_operator = (
            split_operator_trotter_error_operator_diagonal_two_body(
                hamiltonian, order='V+T'))

        # V-then-T ordered double commutators: [V, [T, V]] + [T, [T, V]] / 2
        inner_commutator = normal_ordered(commutator(kinetic, potential))
        error_operator_definition = normal_ordered(
            commutator(potential, inner_commutator))
        error_operator_definition += normal_ordered(
            commutator(kinetic, inner_commutator)) / 2.0
        error_operator_definition /= 12.0

        self.assertEqual(error_operator, error_operator_definition)
示例#2
0
def test_erpa_eom_ham_lih():
    filename = os.path.join(DATA_DIRECTORY, "H1-Li1_sto-3g_singlet_1.45.hdf5")
    molecule = MolecularData(filename=filename)
    reduced_ham = make_reduced_hamiltonian(
        molecule.get_molecular_hamiltonian(), molecule.n_electrons)
    rha_fermion = of.get_fermion_operator(reduced_ham)
    permuted_hijkl = np.einsum('ijlk', reduced_ham.two_body_tensor)
    opdm = np.diag([1] * molecule.n_electrons + [0] *
                   (molecule.n_qubits - molecule.n_electrons))
    tpdm = 2 * of.wedge(opdm, opdm, (1, 1), (1, 1))
    rdms = of.InteractionRDM(opdm, tpdm)
    dim = 3  # so we don't do the full basis.  This would make the test long
    full_basis = {}  # erpa basis.  A, B basis in RPA language
    cnt = 0
    # start from 1 to make test shorter
    for p, q in product(range(1, dim), repeat=2):
        if p < q:
            full_basis[(p, q)] = cnt
            full_basis[(q, p)] = cnt + dim * (dim - 1) // 2
            cnt += 1
    for rkey in full_basis.keys():
        p, q = rkey
        for ckey in full_basis.keys():
            r, s = ckey
            for sigma, tau in product([0, 1], repeat=2):
                test = erpa_eom_hamiltonian(permuted_hijkl, tpdm,
                                            2 * q + sigma, 2 * p + sigma,
                                            2 * r + tau, 2 * s + tau).real
                qp_op = of.FermionOperator(
                    ((2 * q + sigma, 1), (2 * p + sigma, 0)))
                rs_op = of.FermionOperator(
                    ((2 * r + tau, 1), (2 * s + tau, 0)))
                erpa_op = of.normal_ordered(
                    of.commutator(qp_op, of.commutator(rha_fermion, rs_op)))
                true = rdms.expectation(of.get_interaction_operator(erpa_op))
                assert np.isclose(true, test)
def benchmark_commutator_diagonal_coulomb_operators_2D_spinless_jellium(
        side_length):
    """Test speed of computing commutators using specialized functions.

    Args:
        side_length: The side length of the 2D jellium grid. There are
            side_length ** 2 qubits, and O(side_length ** 4) terms in the
            Hamiltonian.

    Returns:
        runtime_commutator: The time it takes to compute a commutator, after
            partitioning the terms and normal ordering, using the regular
            commutator function.
        runtime_diagonal_commutator: The time it takes to compute the same
            commutator using methods restricted to diagonal Coulomb operators.
    """
    hamiltonian = normal_ordered(
        jellium_model(Grid(2, side_length, 1.), plane_wave=False))

    part_a = FermionOperator.zero()
    part_b = FermionOperator.zero()
    add_to_a_or_b = 0  # add to a if 0; add to b if 1
    for term, coeff in hamiltonian.terms.items():
        # Partition terms in the Hamiltonian into part_a or part_b
        if add_to_a_or_b:
            part_a += FermionOperator(term, coeff)
        else:
            part_b += FermionOperator(term, coeff)
        add_to_a_or_b ^= 1

    start = time.time()
    _ = normal_ordered(commutator(part_a, part_b))
    end = time.time()
    runtime_commutator = end - start

    start = time.time()
    _ = commutator_ordered_diagonal_coulomb_with_two_body_operator(
        part_a, part_b)
    end = time.time()
    runtime_diagonal_commutator = end - start

    return runtime_commutator, runtime_diagonal_commutator
示例#4
0
def test_generalized_doubles():
    generator = generate_antisymm_generator(2)
    nso = generator.shape[0]
    for p, q, r, s in product(range(nso), repeat=4):
        if p < q and s < r:
            assert np.isclose(generator[p, q, r, s], -generator[q, p, r, s])

    ul, vl, one_body_residual, ul_ops, vl_ops, one_body_op = \
        doubles_factorization_svd(generator)

    generator_mat = np.reshape(np.transpose(generator, [0, 3, 1, 2]),
                               (nso**2, nso**2)).astype(np.float)
    one_body_residual_test = -np.einsum('pqrq->pr', generator)
    assert np.allclose(generator_mat, generator_mat.T)
    assert np.allclose(one_body_residual, one_body_residual_test)

    tgenerator_mat = np.zeros_like(generator_mat)
    for row_gem, col_gem in product(range(nso**2), repeat=2):
        p, s = row_gem // nso, row_gem % nso
        q, r = col_gem // nso, col_gem % nso
        tgenerator_mat[row_gem, col_gem] = generator[p, q, r, s]

    assert np.allclose(tgenerator_mat, generator_mat)

    u, sigma, vh = np.linalg.svd(generator_mat)

    fop = copy.deepcopy(one_body_op)
    fop2 = copy.deepcopy(one_body_op)
    fop3 = copy.deepcopy(one_body_op)
    fop4 = copy.deepcopy(one_body_op)
    for ll in range(len(sigma)):
        ul.append(np.sqrt(sigma[ll]) * u[:, ll].reshape((nso, nso)))
        ul_ops.append(
            get_fermion_op(np.sqrt(sigma[ll]) * u[:, ll].reshape((nso, nso))))
        vl.append(np.sqrt(sigma[ll]) * vh[ll, :].reshape((nso, nso)))
        vl_ops.append(
            get_fermion_op(np.sqrt(sigma[ll]) * vh[ll, :].reshape((nso, nso))))
        Smat = ul[ll] + vl[ll]
        Dmat = ul[ll] - vl[ll]

        S = ul_ops[ll] + vl_ops[ll]
        Sd = of.hermitian_conjugated(S)
        D = ul_ops[ll] - vl_ops[ll]
        Dd = of.hermitian_conjugated(D)
        op1 = S + 1j * of.hermitian_conjugated(S)
        op2 = S - 1j * of.hermitian_conjugated(S)
        op3 = D + 1j * of.hermitian_conjugated(D)
        op4 = D - 1j * of.hermitian_conjugated(D)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op1, of.hermitian_conjugated(op1))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op2, of.hermitian_conjugated(op2))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op3, of.hermitian_conjugated(op3))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op4, of.hermitian_conjugated(op4))).induced_norm(), 0)

        fop3 += (1 / 8) * ((S**2 - Sd**2) - (D**2 - Dd**2))
        fop4 += (1 / 16) * ((op1**2 + op2**2) - (op3**2 + op4**2))

        op1mat = Smat + 1j * Smat.T
        op2mat = Smat - 1j * Smat.T
        op3mat = Dmat + 1j * Dmat.T
        op4mat = Dmat - 1j * Dmat.T

        assert np.allclose(of.commutator(op1mat, op1mat.conj().T), 0)
        assert np.allclose(of.commutator(op2mat, op2mat.conj().T), 0)
        assert np.allclose(of.commutator(op3mat, op3mat.conj().T), 0)
        assert np.allclose(of.commutator(op4mat, op4mat.conj().T), 0)

        # check that we have normal operators and that the outer product
        # of their eigenvalues is imaginary. Also check vv is unitary
        if not np.isclose(sigma[ll], 0):
            assert np.isclose(
                of.normal_ordered(get_fermion_op(op1mat) - op1).induced_norm(),
                0)
            assert np.isclose(
                of.normal_ordered(get_fermion_op(op2mat) - op2).induced_norm(),
                0)
            assert np.isclose(
                of.normal_ordered(get_fermion_op(op3mat) - op3).induced_norm(),
                0)
            assert np.isclose(
                of.normal_ordered(get_fermion_op(op4mat) - op4).induced_norm(),
                0)

            ww, vv = np.linalg.eig(op1mat)
            eye = np.eye(nso)
            assert np.allclose(np.outer(ww, ww).real, 0)
            assert np.allclose(vv.conj().T @ vv, eye)
            ww, vv = np.linalg.eig(op2mat)
            assert np.allclose(np.outer(ww, ww).real, 0)
            assert np.allclose(vv.conj().T @ vv, eye)
            ww, vv = np.linalg.eig(op3mat)
            assert np.allclose(np.outer(ww, ww).real, 0)
            assert np.allclose(vv.conj().T @ vv, eye)
            ww, vv = np.linalg.eig(op4mat)
            assert np.allclose(np.outer(ww, ww).real, 0)
            assert np.allclose(vv.conj().T @ vv, eye)

        fop2 += 0.25 * ul_ops[ll] * vl_ops[ll]
        fop2 += 0.25 * vl_ops[ll] * ul_ops[ll]
        fop2 += -0.25 * of.hermitian_conjugated(
            vl_ops[ll]) * of.hermitian_conjugated(ul_ops[ll])
        fop2 += -0.25 * of.hermitian_conjugated(
            ul_ops[ll]) * of.hermitian_conjugated(vl_ops[ll])

        fop += vl_ops[ll] * ul_ops[ll]

    true_fop = get_fermion_op(generator)
    assert np.isclose(of.normal_ordered(fop - true_fop).induced_norm(), 0)
    assert np.isclose(of.normal_ordered(fop2 - true_fop).induced_norm(), 0)
    assert np.isclose(of.normal_ordered(fop3 - true_fop).induced_norm(), 0)
    assert np.isclose(of.normal_ordered(fop4 - true_fop).induced_norm(), 0)
示例#5
0
def doubles_factorization_svd(generator_tensor: np.ndarray, eig_cutoff=None):
    """
    Given an antisymmetric antihermitian tensor perform a double factorized
    low-rank decomposition.

    Given:

    A = sum_{pqrs}A^{pq}_{sr}p^ q^ r s

    with A^{pq}_{sr} = -A^{qp}_{sr} = -A^{pq}_{rs} = -A^{sr}_{pq}

    Rewrite A as a sum-of squares s.t

    A = sum_{l}Y_{l}^2

    where Y_{l} are normal operator one-body operators such that the spectral
    theorem holds and we can use the double factorization to implement an
    approximate evolution.
    """
    if not np.allclose(generator_tensor.imag, 0):
        raise TypeError("generator_tensor must be a real matrix")

    if eig_cutoff is not None:
        if eig_cutoff % 2 != 0:
            raise ValueError("eig_cutoff must be an even number")

    nso = generator_tensor.shape[0]
    generator_tensor = generator_tensor.real
    generator_mat = np.zeros((nso**2, nso**2))
    for row_gem, col_gem in product(range(nso**2), repeat=2):
        p, s = row_gem // nso, row_gem % nso
        q, r = col_gem // nso, col_gem % nso
        generator_mat[row_gem, col_gem] = generator_tensor[p, q, r, s]
    test_generator_mat = np.reshape(
        np.transpose(generator_tensor, [0, 3, 1, 2]),
        (nso**2, nso**2)).astype(np.float)

    assert np.allclose(test_generator_mat, generator_mat)

    if not np.allclose(generator_mat, generator_mat.T):
        raise ValueError("generator tensor does not correspond to four-fold"
                         " antisymmetry")

    one_body_residual = -np.einsum('pqrq->pr', generator_tensor)
    u, sigma, vh = np.linalg.svd(generator_mat)

    ul = []
    ul_ops = []
    vl = []
    vl_ops = []
    if eig_cutoff is None:
        max_sigma = len(sigma)
    else:
        max_sigma = eig_cutoff

    for ll in range(max_sigma):
        ul.append(np.sqrt(sigma[ll]) * u[:, ll].reshape((nso, nso)))
        ul_ops.append(
            get_fermion_op(np.sqrt(sigma[ll]) * u[:, ll].reshape((nso, nso))))
        vl.append(np.sqrt(sigma[ll]) * vh[ll, :].reshape((nso, nso)))
        vl_ops.append(
            get_fermion_op(np.sqrt(sigma[ll]) * vh[ll, :].reshape((nso, nso))))
        S = ul_ops[ll] + vl_ops[ll]
        D = ul_ops[ll] - vl_ops[ll]
        op1 = S + 1j * of.hermitian_conjugated(S)
        op2 = S - 1j * of.hermitian_conjugated(S)
        op3 = D + 1j * of.hermitian_conjugated(D)
        op4 = D - 1j * of.hermitian_conjugated(D)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op1, of.hermitian_conjugated(op1))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op2, of.hermitian_conjugated(op2))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op3, of.hermitian_conjugated(op3))).induced_norm(), 0)
        assert np.isclose(
            of.normal_ordered(of.commutator(
                op4, of.hermitian_conjugated(op4))).induced_norm(), 0)

    one_body_op = of.FermionOperator()
    for p, q in product(range(nso), repeat=2):
        tfop = ((p, 1), (q, 0))
        one_body_op += of.FermionOperator(tfop,
                                          coefficient=one_body_residual[p, q])

    return ul, vl, one_body_residual, ul_ops, vl_ops, one_body_op