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)
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)
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)
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)
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