示例#1
0
def test_rhf_params_to_matrix():
    test_kappa = rhf_params_to_matrix(np.array([0.1, 0.2, 0.3, 0.4]), 4)
    kappa = np.zeros((4, 4))
    kappa[0, 2] = -0.1
    kappa[0, 3] = -0.3
    kappa[1, 2] = -0.2
    kappa[1, 3] = -0.4
    kappa -= kappa.T
    assert np.allclose(test_kappa, kappa)

    with pytest.raises(ValueError):
        rhf_params_to_matrix(np.array([1.0 + 1j]), 2)
示例#2
0
def test_fidelity():
    parameters = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
    u = sp.linalg.expm(rhf_params_to_matrix(parameters, 6))
    opdm = np.array([[
        0.766034130, -0.27166330, -0.30936072, -0.08471057, -0.04878244,
        -0.01285432
    ],
                     [
                         -0.27166330, 0.67657015, -0.37519640, -0.02101843,
                         -0.03568214, -0.05034585
                     ],
                     [
                         -0.30936072, -0.37519640, 0.55896791, 0.04267370,
                         -0.02258184, -0.08783738
                     ],
                     [
                         -0.08471057, -0.02101843, 0.04267370, 0.05450848,
                         0.11291253, 0.17131658
                     ],
                     [
                         -0.04878244, -0.03568214, -0.02258184, 0.11291253,
                         0.26821219, 0.42351185
                     ],
                     [
                         -0.01285432, -0.05034585, -0.08783738, 0.17131658,
                         0.42351185, 0.67570713
                     ]])

    assert np.isclose(fidelity(u, opdm), 1.0)
    opdm += 0.1
    opdm = 0.5 * (opdm + opdm.T)
    assert np.isclose(fidelity(u, opdm), 0.3532702370138279)
def test_fidelity_witness():
    parameters = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
    u = sp.linalg.expm(rhf_params_to_matrix(parameters, 6))
    omega = [1] * 3 + [0] * 3
    opdm = np.array([[0.766034130, -0.27166330, -0.30936072, -0.08471057, -0.04878244, -0.01285432],
                     [-0.27166330,  0.67657015, -0.37519640, -0.02101843, -0.03568214, -0.05034585],
                     [-0.30936072, -0.37519640,  0.55896791,  0.04267370, -0.02258184, -0.08783738],
                     [-0.08471057, -0.02101843,  0.04267370,  0.05450848,  0.11291253,  0.17131658],
                     [-0.04878244, -0.03568214, -0.02258184,  0.11291253,  0.26821219,  0.42351185],
                     [-0.01285432, -0.05034585, -0.08783738,  0.17131658,  0.42351185,  0.67570713]])

    assert np.isclose(fidelity_witness(u, omega, opdm), 1.0)

    opdm += 0.1
    opdm = 0.5 * (opdm + opdm.T)

    # higher than fidelity because of particle number breaking
    assert np.isclose(fidelity_witness(u, omega, opdm), 0.7721525013371697)
示例#4
0
def test_prepare_slater():
    qubits = cirq.LineQubit.range(4)
    kappa = rhf_params_to_matrix(np.array([0.1, 0.2, 0.3, 0.4]), 4)
    u = sp.linalg.expm(kappa)

    with pytest.raises(ValueError):
        list(prepare_slater_determinant(qubits, u[:, :2].T, clean_ryxxy=5))

    test_circuit = cirq.Circuit(prepare_slater_determinant(qubits, u[:, :2].T))
    true_moments = [
        cirq.Moment(operations=[
            cirq.X.on(cirq.LineQubit(0)),
            cirq.X.on(cirq.LineQubit(1)),
        ]),
        cirq.Moment(operations=[
            (cirq.ISWAP**0.5).on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.1676697243144354).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.1676697243144355).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            (cirq.ISWAP**0.5).on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(1)),
            (cirq.ISWAP**0.5).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            (cirq.ISWAP**0.5).on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.3947664179536838).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * -0.3947664179536837).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 0.795779308536894).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.20422069146310598).on(cirq.LineQubit(1)),
            (cirq.ISWAP**0.5).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            (cirq.ISWAP**0.5).on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(0)),
            (cirq.ISWAP**0.5).on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0212853739870422).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.02128537398704223).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            (cirq.ISWAP**0.5).on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(1)),
        ])
    ]
    assert cirq.approx_eq(true_moments, test_circuit._moments, atol=1e-8)

    test_circuit = cirq.Circuit(
        prepare_slater_determinant(qubits, u[:, :2].T, clean_ryxxy=2))
    true_circuit = [
        cirq.Moment(operations=[
            cirq.X.on(cirq.LineQubit(0)),
            cirq.X.on(cirq.LineQubit(1)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.1676697243144354).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.1676697243144355).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.3947664179536838).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * -0.3947664179536837).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 0.795779308536894).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.20422069146310598).on(cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(0)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0212853739870422).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.02128537398704223).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0).on(cirq.LineQubit(1)),
        ])
    ]
    assert cirq.approx_eq(true_circuit, test_circuit._moments, atol=1e-8)

    test_circuit = cirq.Circuit(
        prepare_slater_determinant(qubits, u[:, :2].T, clean_ryxxy=3))
    true_circuit = [
        cirq.Moment(operations=[
            cirq.X.on(cirq.LineQubit(0)),
            cirq.X.on(cirq.LineQubit(1)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.1885030576477686).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.14683639098110218).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747
                          ).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 0.8166126418702274).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.22505402479643932).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.4155997512870173).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * -0.3739330846203504).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747
                          ).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0421187073203755).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.000452040653708897).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(2)),
        ])
    ]
    assert cirq.approx_eq(true_circuit, test_circuit._moments, atol=1e-8)

    test_circuit = cirq.Circuit(
        prepare_slater_determinant(qubits, u[:, :2].T, clean_ryxxy=4))
    true_circuit = [
        cirq.Moment(operations=[
            cirq.X.on(cirq.LineQubit(0)),
            cirq.X.on(cirq.LineQubit(1)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.1885030576477686).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.14683639098110218).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747
                          ).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 0.8166126418702274).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.22505402479643932).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.4155997512870173).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * -0.3739330846203504).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(0), cirq.LineQubit(1)),
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747
                          ).on(cirq.LineQubit(2), cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(0)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(2)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(3)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0421187073203755).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * -0.000452040653708897).on(cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.FSimGate(theta=-0.7853981633974483, phi=0.1308996938995747).
            on(cirq.LineQubit(1), cirq.LineQubit(2)),
        ]),
        cirq.Moment(operations=[
            cirq.rz(np.pi * 1.0208333333333333).on(cirq.LineQubit(1)),
            cirq.rz(np.pi * 0.020833333333333332).on(cirq.LineQubit(2)),
        ])
    ]
    assert cirq.approx_eq(true_circuit, test_circuit._moments, atol=1e-8)
示例#5
0
 def unitary(params):
     kappa = rhf_params_to_matrix(
         params,
         len(rhf_objective.occ) + len(rhf_objective.virt),
         rhf_objective.occ, rhf_objective.virt)
     return sp.linalg.expm(kappa)
def test_global_gradient_h4():
    """
    Test the gradient at the solution given by psi4
    """
    # first get molecule
    rhf_objective, molecule, params, _, _ = make_h6_1_3()
    # molecule = h4_linear_molecule(1.0)
    nocc = molecule.n_electrons // 2
    occ = list(range(nocc))
    virt = list(range(nocc, molecule.n_orbitals))

    qubits = cirq.LineQubit.range(molecule.n_orbitals)
    u = sp.linalg.expm(
        rhf_params_to_matrix(params, len(qubits), occ=occ, virt=virt))
    circuit = cirq.Circuit(prepare_slater_determinant(qubits, u[:, :nocc].T))

    simulator = cirq.Simulator(dtype=np.complex128)
    wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
    opdm_alpha = get_opdm(wf, molecule.n_orbitals)
    opdm = np.zeros((molecule.n_qubits, molecule.n_qubits),
                    dtype=np.complex128)
    opdm[::2, ::2] = opdm_alpha
    opdm[1::2, 1::2] = opdm_alpha

    grad = rhf_objective.global_gradient_opdm(params, opdm_alpha)

    # get finite difference gradient
    finite_diff_grad = np.zeros(9)
    epsilon = 0.0001
    for i in range(9):
        params_epsilon = params.copy()
        params_epsilon[i] += epsilon
        u = sp.linalg.expm(
            rhf_params_to_matrix(params_epsilon,
                                 len(qubits),
                                 occ=occ,
                                 virt=virt))
        circuit = cirq.Circuit(
            prepare_slater_determinant(qubits, u[:, :nocc].T))
        wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
        opdm_pepsilon = get_opdm(wf, molecule.n_orbitals)
        energy_plus_epsilon = rhf_objective.energy_from_opdm(opdm_pepsilon)

        params_epsilon[i] -= 2 * epsilon
        u = sp.linalg.expm(
            rhf_params_to_matrix(params_epsilon,
                                 len(qubits),
                                 occ=occ,
                                 virt=virt))
        circuit = cirq.Circuit(
            prepare_slater_determinant(qubits, u[:, :nocc].T))
        wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
        opdm_pepsilon = get_opdm(wf, molecule.n_orbitals)
        energy_minus_epsilon = rhf_objective.energy_from_opdm(opdm_pepsilon)

        finite_diff_grad[i] = (energy_plus_epsilon -
                               energy_minus_epsilon) / (2 * epsilon)

    assert np.allclose(finite_diff_grad, grad, atol=epsilon)

    # random parameters now
    params = np.random.randn(9)
    u = sp.linalg.expm(
        rhf_params_to_matrix(params, len(qubits), occ=occ, virt=virt))
    circuit = cirq.Circuit(prepare_slater_determinant(qubits, u[:, :nocc].T))

    simulator = cirq.Simulator(dtype=np.complex128)
    wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
    opdm_alpha = get_opdm(wf, molecule.n_orbitals)
    opdm = np.zeros((molecule.n_qubits, molecule.n_qubits),
                    dtype=np.complex128)
    opdm[::2, ::2] = opdm_alpha
    opdm[1::2, 1::2] = opdm_alpha
    grad = rhf_objective.global_gradient_opdm(params, opdm_alpha)

    # get finite difference gradient
    finite_diff_grad = np.zeros(9)
    epsilon = 0.0001
    for i in range(9):
        params_epsilon = params.copy()
        params_epsilon[i] += epsilon
        u = sp.linalg.expm(
            rhf_params_to_matrix(params_epsilon,
                                 len(qubits),
                                 occ=occ,
                                 virt=virt))
        circuit = cirq.Circuit(
            prepare_slater_determinant(qubits, u[:, :nocc].T))
        wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
        opdm_pepsilon = get_opdm(wf, molecule.n_orbitals)
        energy_plus_epsilon = rhf_objective.energy_from_opdm(opdm_pepsilon)

        params_epsilon[i] -= 2 * epsilon
        u = sp.linalg.expm(
            rhf_params_to_matrix(params_epsilon,
                                 len(qubits),
                                 occ=occ,
                                 virt=virt))
        circuit = cirq.Circuit(
            prepare_slater_determinant(qubits, u[:, :nocc].T))
        wf = simulator.simulate(circuit).final_state.reshape((-1, 1))
        opdm_pepsilon = get_opdm(wf, molecule.n_orbitals)
        energy_minus_epsilon = rhf_objective.energy_from_opdm(opdm_pepsilon)

        finite_diff_grad[i] = (energy_plus_epsilon -
                               energy_minus_epsilon) / (2 * epsilon)

    assert np.allclose(finite_diff_grad, grad, atol=epsilon)
示例#7
0
    def global_gradient_opdm(self, params: np.ndarray, alpha_opdm: np.ndarray):
        opdm = np.zeros((self.num_qubits, self.num_qubits),
                        dtype=np.complex128)
        opdm[::2, ::2] = alpha_opdm
        opdm[1::2, 1::2] = alpha_opdm
        tpdm = 2 * wedge(opdm, opdm, (1, 1), (1, 1))

        # now go through and generate all the necessary Z, Y, Y_kl matrices
        kappa_matrix = rhf_params_to_matrix(params,
                                            len(self.occ) + len(self.virt),
                                            self.occ, self.virt)
        kappa_matrix_full = np.kron(kappa_matrix, np.eye(2))
        w_full, v_full = np.linalg.eigh(
            -1j * kappa_matrix_full)  # so that kappa = i U lambda U^
        eigs_scaled_full = get_matrix_of_eigs(w_full)

        grad = np.zeros(self.nocc * self.nvirt, dtype=np.complex128)
        kdelta = np.eye(self.num_qubits)

        # NOW GENERATE ALL TERMS ASSOCIATED WITH THE GRADIENT!!!!!!
        for p in range(self.nocc * self.nvirt):
            grad_params = np.zeros_like(params)
            grad_params[p] = 1
            Y = rhf_params_to_matrix(grad_params,
                                     len(self.occ) + len(self.virt), self.occ,
                                     self.virt)
            Y_full = np.kron(Y, np.eye(2))

            # Now rotate Y int othe basis that diagonalizes Z
            Y_kl_full = v_full.conj().T @ Y_full @ v_full
            # now rotate Y_{kl} * (exp(i(l_{k} - l_{l})) - 1) / (i(l_{k} - l_{l}))
            # into the original basis
            pre_matrix_full = v_full @ (eigs_scaled_full *
                                        Y_kl_full) @ v_full.conj().T

            grad_expectation = -1.0 * np.einsum(
                'ab,pq,aq,pb',
                self.hamiltonian.one_body_tensor,
                pre_matrix_full,
                kdelta,
                opdm,
                optimize='optimal').real
            grad_expectation += 1.0 * np.einsum(
                'ab,pq,bp,aq',
                self.hamiltonian.one_body_tensor,
                pre_matrix_full,
                kdelta,
                opdm,
                optimize='optimal').real
            grad_expectation += 1.0 * np.einsum(
                'ijkl,pq,iq,jpkl',
                self.hamiltonian.two_body_tensor,
                pre_matrix_full,
                kdelta,
                tpdm,
                optimize='optimal').real
            grad_expectation += -1.0 * np.einsum(
                'ijkl,pq,jq,ipkl',
                self.hamiltonian.two_body_tensor,
                pre_matrix_full,
                kdelta,
                tpdm,
                optimize='optimal').real
            grad_expectation += -1.0 * np.einsum(
                'ijkl,pq,kp,ijlq',
                self.hamiltonian.two_body_tensor,
                pre_matrix_full,
                kdelta,
                tpdm,
                optimize='optimal').real
            grad_expectation += 1.0 * np.einsum(
                'ijkl,pq,lp,ijkq',
                self.hamiltonian.two_body_tensor,
                pre_matrix_full,
                kdelta,
                tpdm,
                optimize='optimal').real
            grad[p] = grad_expectation

        return grad