def test_solver_via_rdms(): molecule = build_lih_moleculardata() n_electrons = molecule.n_electrons sz = 0 oei, tei = molecule.get_integrals() elec_hamil = fqe.restricted_hamiltonian.RestrictedHamiltonian( (oei, np.einsum("ijlk", -0.5 * tei))) soei, stei = spinorb_from_spatial(oei, tei) astei = np.einsum('ijkl', stei) - np.einsum('ijlk', stei) molecular_hamiltonian = of.InteractionOperator(0, soei, 0.25 * astei) reduced_ham = of.chem.make_reduced_hamiltonian(molecular_hamiltonian, molecule.n_electrons) fqe_wf = fqe.Wavefunction([[n_electrons, sz, molecule.n_orbitals]]) graph = fqe_wf.sector((n_electrons, sz)).get_fcigraph() fci_coeffs = np.zeros((graph.lena(), graph.lenb()), dtype=np.complex128) fci_coeffs[0, 0] = 1.0 fqe_wf.set_wfn(strategy="from_data", raw_data={(n_electrons, sz): fci_coeffs}) bcsolve = BrillouinCondition(molecule, run_parallel=False) assert bcsolve.reduced_ham == reduced_ham for pp, qq in zip(elec_hamil.tensors(), bcsolve.elec_hamil.tensors()): assert np.allclose(pp, qq) bcsolve.iter_max = 1 bcsolve.bc_solve_rdms(fqe_wf) assert np.allclose(bcsolve.acse_energy, [-8.957417182801088, -8.969256797233033])
def test_trotter_ansatzes_default_initial_params_iterations_1( ansatz_factory, trotter_algorithm, order, hamiltonian, atol): """Check that a Trotter ansatz with one iteration and default parameters is consistent with time evolution with one Trotter step.""" ansatz = ansatz_factory(hamiltonian, iterations=1) objective = HamiltonianObjective(hamiltonian) qubits = ansatz.qubits if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): one_body = hamiltonian.one_body elif isinstance(hamiltonian, openfermion.InteractionOperator): one_body = hamiltonian.one_body_tensor preparation_circuit = cirq.Circuit.from_ops( prepare_gaussian_state(qubits, openfermion.QuadraticHamiltonian(one_body), occupied_orbitals=range(len(qubits) // 2))) # Compute value using ansatz circuit and objective circuit = (preparation_circuit + ansatz.circuit).with_parameters_resolved_by( ansatz.param_resolver(ansatz.default_initial_params())) result = circuit.apply_unitary_effect_to_state( qubit_order=ansatz.qubit_permutation(qubits)) obj_val = objective.value(result) # Compute value using study study = VariationalStudy('study', ansatz, objective, preparation_circuit=preparation_circuit) study_val = study.value_of(ansatz.default_initial_params()) # Compute value by simulating time evolution if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): half_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.5 * hamiltonian.two_body) elif isinstance(hamiltonian, openfermion.InteractionOperator): half_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.5 * hamiltonian.two_body_tensor) simulation_circuit = cirq.Circuit.from_ops( simulate_trotter(qubits, half_way_hamiltonian, time=ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm)) final_state = (preparation_circuit + simulation_circuit).apply_unitary_effect_to_state() correct_val = openfermion.expectation(objective._hamiltonian_linear_op, final_state).real numpy.testing.assert_allclose(obj_val, study_val, atol=atol) numpy.testing.assert_allclose(obj_val, correct_val, atol=atol)
def test_fqe_givens(): """Test Givens Rotation evolution for correctness.""" # set up norbs = 4 n_elec = norbs sz = 0 n_qubits = 2 * norbs time = 0.126 fqe_wfn = fqe.Wavefunction([[n_elec, sz, norbs]]) fqe_wfn.set_wfn(strategy="random") ikappa = random_quadratic_hamiltonian( norbs, conserves_particle_number=True, real=False, expand_spin=False, seed=2, ) fqe_ham = RestrictedHamiltonian((ikappa.n_body_tensors[1, 0], )) u = expm(-1j * ikappa.n_body_tensors[1, 0] * time) # time-evolve final_fqe_wfn = fqe_wfn.time_evolve(time, fqe_ham) spin_ham = np.kron(ikappa.n_body_tensors[1, 0], np.eye(2)) assert of.is_hermitian(spin_ham) ikappa_spin = of.InteractionOperator( constant=0, one_body_tensor=spin_ham, two_body_tensor=np.zeros((n_qubits, n_qubits, n_qubits, n_qubits)), ) bigU = expm(-1j * of.get_sparse_operator(ikappa_spin).toarray() * time) initial_wf = fqe.to_cirq(fqe_wfn).reshape((-1, 1)) final_wf = bigU @ initial_wf final_wfn_test = fqe.from_cirq(final_wf.flatten(), 1.0e-12) assert np.allclose(final_fqe_wfn.rdm("i^ j"), final_wfn_test.rdm("i^ j")) assert np.allclose(final_fqe_wfn.rdm("i^ j^ k l"), final_wfn_test.rdm("i^ j^ k l")) final_wfn_test2 = fqe.from_cirq( evolve_wf_givens(initial_wf.copy(), u.copy()).flatten(), 1.0e-12) givens_fqe_wfn = evolve_fqe_givens(fqe_wfn, u.copy()) assert np.allclose(givens_fqe_wfn.rdm("i^ j"), final_wfn_test2.rdm("i^ j")) assert np.allclose(givens_fqe_wfn.rdm("i^ j^ k l"), final_wfn_test2.rdm("i^ j^ k l"))
def test_adapt(): molecule = build_lih_moleculardata() n_electrons = molecule.n_electrons oei, tei = molecule.get_integrals() norbs = molecule.n_orbitals nalpha = molecule.n_electrons // 2 nbeta = nalpha sz = nalpha - nbeta occ = list(range(nalpha)) virt = list(range(nalpha, norbs)) soei, stei = spinorb_from_spatial(oei, tei) astei = np.einsum('ijkl', stei) - np.einsum('ijlk', stei) molecular_hamiltonian = of.InteractionOperator(0, soei, 0.25 * astei) reduced_ham = of.chem.make_reduced_hamiltonian(molecular_hamiltonian, molecule.n_electrons) fqe_wf = fqe.Wavefunction([[n_electrons, sz, molecule.n_orbitals]]) fqe_wf.set_wfn(strategy='hartree-fock') sop = OperatorPool(norbs, occ, virt) sop.two_body_sz_adapted() # initialize pool adapt = ADAPT(oei, tei, sop, nalpha, nbeta, iter_max=1, verbose=False) assert np.isclose( np.linalg.norm(adapt.reduced_ham.two_body_tensor - reduced_ham.two_body_tensor), 0) adapt.adapt_vqe(fqe_wf) assert np.isclose(adapt.energies[0], -8.957417182801091) assert np.isclose(adapt.energies[-1], -8.970532463968661) sop = OperatorPool(norbs, occ, virt) sop.one_body_sz_adapted() adapt = ADAPT(oei, tei, sop, nalpha, nbeta, iter_max=10, stopping_epsilon=10, verbose=True) adapt.adapt_vqe(fqe_wf) assert np.isclose(adapt.energies[-1], -8.957417182801091) assert np.isclose(adapt.energies[0], -8.95741717733075)
def test_first_factorization(): molecule = build_lih_moleculardata() oei, tei = molecule.get_integrals() lrt_obj = LowRankTrotter(oei=oei, tei=tei) ( eigenvalues, one_body_squares, one_body_correction, ) = lrt_obj.first_factorization() # get true op n_qubits = molecule.n_qubits fermion_tei = of.FermionOperator() test_tei_tensor = np.zeros((n_qubits, n_qubits, n_qubits, n_qubits)) for p, q, r, s in product(range(oei.shape[0]), repeat=4): if np.abs(tei[p, q, r, s]) < EQ_TOLERANCE: coefficient = 0.0 else: coefficient = tei[p, q, r, s] / 2.0 for sigma, tau in product(range(2), repeat=2): if 2 * p + sigma == 2 * q + tau or 2 * r + tau == 2 * s + sigma: continue term = ( (2 * p + sigma, 1), (2 * q + tau, 1), (2 * r + tau, 0), (2 * s + sigma, 0), ) fermion_tei += of.FermionOperator(term, coefficient=coefficient) test_tei_tensor[2 * p + sigma, 2 * q + tau, 2 * r + tau, 2 * s + sigma] = coefficient mol_ham = of.InteractionOperator( one_body_tensor=np.zeros((n_qubits, n_qubits)), two_body_tensor=test_tei_tensor, constant=0, ) # check induced norm on operator checked_op = of.FermionOperator() for ( p, q, ) in product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_correction[p, q] checked_op += of.FermionOperator(term, coefficient) # Build back two-body component. for l in range(one_body_squares.shape[0]): one_body_operator = of.FermionOperator() for p, q in product(range(n_qubits), repeat=2): term = ((p, 1), (q, 0)) coefficient = one_body_squares[l, p, q] one_body_operator += of.FermionOperator(term, coefficient) checked_op += eigenvalues[l] * (one_body_operator**2) true_fop = of.normal_ordered(of.get_fermion_operator(mol_ham)) difference = of.normal_ordered(checked_op - true_fop) assert np.isclose(0, difference.induced_norm())
def test_generalized_doubles_takagi(): molecule = build_lih_moleculardata() oei, tei = molecule.get_integrals() nele = 4 nalpha = 2 nbeta = 2 sz = 0 norbs = oei.shape[0] nso = 2 * norbs fqe_wf = fqe.Wavefunction([[nele, sz, norbs]]) fqe_wf.set_wfn(strategy='hartree-fock') fqe_wf.normalize() _, tpdm = fqe_wf.sector((nele, sz)).get_openfermion_rdms() d3 = fqe_wf.sector((nele, sz)).get_three_pdm() soei, stei = spinorb_from_spatial(oei, tei) astei = np.einsum('ijkl', stei) - np.einsum('ijlk', stei) molecular_hamiltonian = of.InteractionOperator(0, soei, 0.25 * astei) reduced_ham = make_reduced_hamiltonian(molecular_hamiltonian, nalpha + nbeta) acse_residual = two_rdo_commutator_symm(reduced_ham.two_body_tensor, tpdm, d3) for p, q, r, s in product(range(nso), repeat=4): if p == q or r == s: continue assert np.isclose(acse_residual[p, q, r, s], -acse_residual[s, r, q, p].conj()) Zlp, Zlm, _, one_body_residual = doubles_factorization_takagi(acse_residual) test_fop = get_fermion_op(one_body_residual) # test the first four factors for ll in range(4): test_fop += 0.25 * get_fermion_op(Zlp[ll])**2 test_fop += 0.25 * get_fermion_op(Zlm[ll])**2 op1mat = Zlp[ll] op2mat = Zlm[ll] w1, v1 = sp.linalg.schur(op1mat) w1 = np.diagonal(w1) assert np.allclose(v1 @ np.diag(w1) @ v1.conj().T, op1mat) v1c = v1.conj() w2, v2 = sp.linalg.schur(op2mat) w2 = np.diagonal(w2) assert np.allclose(v2 @ np.diag(w2) @ v2.conj().T, op2mat) oww1 = np.outer(w1, w1) fqe_wf = fqe.Wavefunction([[nele, sz, norbs]]) fqe_wf.set_wfn(strategy='hartree-fock') fqe_wf.normalize() nfqe_wf = fqe.get_number_conserving_wavefunction(nele, norbs) nfqe_wf.sector((nele, sz)).coeff = fqe_wf.sector((nele, sz)).coeff this_generatory = np.einsum('pi,si,ij,qj,rj->pqrs', v1, v1c, oww1, v1, v1c) fop = of.FermionOperator() for p, q, r, s in product(range(nso), repeat=4): op = ((p, 1), (s, 0), (q, 1), (r, 0)) fop += of.FermionOperator(op, coefficient=this_generatory[p, q, r, s]) fqe_fop = build_hamiltonian(1j * fop, norb=norbs, conserve_number=True) exact_wf = fqe.apply_generated_unitary(nfqe_wf, 1, 'taylor', fqe_fop) test_wf = fqe.algorithm.low_rank.evolve_fqe_givens_unrestricted( nfqe_wf, v1.conj().T) test_wf = fqe.algorithm.low_rank.evolve_fqe_charge_charge_unrestricted( test_wf, -oww1.imag) test_wf = fqe.algorithm.low_rank.evolve_fqe_givens_unrestricted( test_wf, v1) assert np.isclose(abs(fqe.vdot(test_wf, exact_wf))**2, 1)
def test_trotter_ansatzes_default_initial_params_iterations_2( ansatz, trotter_algorithm, order, hamiltonian, atol): """Check that a Trotter ansatz with two iterations and default parameters is consistent with time evolution with two Trotter steps.""" objective = HamiltonianObjective(hamiltonian) qubits = ansatz.qubits if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): one_body = hamiltonian.one_body elif isinstance(hamiltonian, openfermion.InteractionOperator): one_body = hamiltonian.one_body_tensor if isinstance(ansatz, SwapNetworkTrotterHubbardAnsatz): occupied_orbitals = (range(len(qubits) // 4), range(len(qubits) // 4)) else: occupied_orbitals = range(len(qubits) // 2) preparation_circuit = cirq.Circuit( prepare_gaussian_state(qubits, openfermion.QuadraticHamiltonian(one_body), occupied_orbitals=occupied_orbitals)) # Compute value using ansatz circuit and objective circuit = cirq.resolve_parameters( preparation_circuit + ansatz.circuit, ansatz.param_resolver(ansatz.default_initial_params())) result = circuit.final_wavefunction( qubit_order=ansatz.qubit_permutation(qubits)) obj_val = objective.value(result) # Compute value using study study = VariationalStudy('study', ansatz, objective, preparation_circuit=preparation_circuit) study_val = study.value_of(ansatz.default_initial_params()) # Compute value by simulating time evolution if isinstance(hamiltonian, openfermion.DiagonalCoulombHamiltonian): quarter_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.25 * hamiltonian.two_body) three_quarters_way_hamiltonian = openfermion.DiagonalCoulombHamiltonian( one_body=hamiltonian.one_body, two_body=0.75 * hamiltonian.two_body) elif isinstance(hamiltonian, openfermion.InteractionOperator): quarter_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.25 * hamiltonian.two_body_tensor) three_quarters_way_hamiltonian = openfermion.InteractionOperator( constant=hamiltonian.constant, one_body_tensor=hamiltonian.one_body_tensor, two_body_tensor=0.75 * hamiltonian.two_body_tensor) simulation_circuit = cirq.Circuit( simulate_trotter(qubits, quarter_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm), simulate_trotter(qubits, three_quarters_way_hamiltonian, time=0.5 * ansatz.adiabatic_evolution_time, n_steps=1, order=order, algorithm=trotter_algorithm)) final_state = (preparation_circuit + simulation_circuit).final_wavefunction() correct_val = openfermion.expectation(objective._hamiltonian_linear_op, final_state).real numpy.testing.assert_allclose(obj_val, study_val, atol=atol) numpy.testing.assert_allclose(obj_val, correct_val, atol=atol)