def test_simulate_dual_basis_hamiltonian(self): hamiltonian = dual_basis_hamiltonian(1, self.size) self.engine.flush() # Choose random state. initial_state = numpy.zeros(2**self.size, dtype=complex) for i in range(len(initial_state)): initial_state[i] = (random.random() * numpy.exp(1j * 2 * numpy.pi * random.random())) initial_state /= numpy.linalg.norm(initial_state) # Put randomly chosen state in the registers. self.engine.backend.set_wavefunction(initial_state, self.register) _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, hamiltonian, trotter_steps=7, first_order=False) self.engine.flush() # get_sparse_operator reverses the indices, but the jellium # Hamiltonian is symmetric. evol_matrix = expm( -1j * get_sparse_operator(hamiltonian, n_qubits=self.size)).todense() initial_state = numpy.matrix(initial_state).T expected = evol_matrix * initial_state self.assertTrue( numpy.allclose(ordered_wavefunction(self.engine), expected.T, atol=1e-2), msg=str( numpy.array(ordered_wavefunction(self.engine) - expected.T)))
def test_simulate_overlapping_number_and_hopping_terms(self): hamiltonian = (0.37 * FermionOperator('1^ 0^ 1 0') + FermionOperator('2^ 0') + FermionOperator('0^ 2')) projectq.ops.All(projectq.ops.H) | self.register _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, hamiltonian, trotter_steps=2, first_order=False) self.engine.flush() # get_sparse_operator reverses the indices, so reverse the sites # the Hamiltonian acts on so as to compare them. reversed_operator = (0.37 * FermionOperator('3^ 2^ 3 2') + FermionOperator('3^ 1') + FermionOperator('1^ 3')) evol_matrix = expm(-1j * get_sparse_operator( reversed_operator, n_qubits=self.size)).todense() expected = evol_matrix * numpy.matrix( [2**(-self.size / 2.)] * 2**self.size).T self.assertTrue( numpy.allclose(ordered_wavefunction(self.engine), expected.T, atol=1e-2), msg=str( numpy.array(ordered_wavefunction(self.engine) - expected.T)))
def test_trotter_order_does_not_matter_for_high_trotter_number(self): size = 4 hamiltonian = dual_basis_hamiltonian(n_dimensions=1, system_size=size) hamiltonian.compress() eng1 = projectq.MainEngine() eng2 = projectq.MainEngine() reg1 = eng1.allocate_qureg(size) reg2 = eng2.allocate_qureg(size) eng1.flush() eng2.flush() # Choose random state. state = numpy.zeros(2**size, dtype=complex) for i in range(len(state)): state[i] = (random.random() * numpy.exp(1j * 2 * numpy.pi * random.random())) state /= numpy.linalg.norm(state) # Put randomly chosen state in the registers. eng1.backend.set_wavefunction(state, reg1) eng2.backend.set_wavefunction(state, reg2) # Swap and change the input ordering for reg1. These operations should # cancel each other out. projectq.ops.Swap | (reg1[1], reg1[2]) projectq.ops.C(projectq.ops.Z) | (reg1[1], reg1[2]) _low_depth_trotter_simulation.simulate_dual_basis_evolution( reg1, hamiltonian=hamiltonian, trotter_steps=7, input_ordering=[0, 2, 1, 3], first_order=False) _low_depth_trotter_simulation.simulate_dual_basis_evolution( reg2, hamiltonian=hamiltonian, trotter_steps=7, first_order=False) # Undo the inital swaps on reg1. projectq.ops.Swap | (reg1[1], reg1[2]) projectq.ops.C(projectq.ops.Z) | (reg1[1], reg1[2]) projectq.ops.All(projectq.ops.H) | reg1 eng1.flush() projectq.ops.All(projectq.ops.H) | reg2 eng2.flush() self.assertTrue( numpy.allclose(ordered_wavefunction(eng1), ordered_wavefunction(eng2), atol=1e-2)) projectq.ops.All(projectq.ops.Measure) | reg1 projectq.ops.All(projectq.ops.Measure) | reg2
def test_simulate_hopping_0_to_3(self): hamiltonian = FermionOperator('0^ 3') + FermionOperator('3^ 0') projectq.ops.All(projectq.ops.H) | self.register _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, hamiltonian, trotter_steps=1, first_order=False) self.engine.flush() # Use 0^ 2 + 2^ 0 because get_sparse_operator reverses the indices. evol_matrix = expm(-1j * get_sparse_operator( hamiltonian, n_qubits=self.size)).todense() expected = evol_matrix * numpy.matrix([2 ** (-self.size / 2.)] * 2 ** self.size).T self.assertTrue(numpy.allclose(ordered_wavefunction(self.engine), expected.T))
def test_simulate_dual_basis_hamiltonian_with_spin_and_potentials(self): big_eng = projectq.MainEngine() big_reg = big_eng.allocate_qureg(2 * self.size) hamiltonian = dual_basis_hamiltonian(1, self.size, spinless=False) for i in range(2 * self.size): coefficient = 1. / (i + 1) if i % 3: coefficient = -coefficient hamiltonian += FermionOperator(((i, 1), (i, 0)), coefficient) # Choose random state. initial_state = numpy.zeros(2**(2 * self.size), dtype=complex) for i in range(len(initial_state)): initial_state[i] = (random.random() * numpy.exp(1j * 2 * numpy.pi * random.random())) initial_state /= numpy.linalg.norm(initial_state) # Put randomly chosen state in the registers. big_eng.flush() big_eng.backend.set_wavefunction(initial_state, big_reg) _low_depth_trotter_simulation.simulate_dual_basis_evolution( big_reg, hamiltonian, trotter_steps=7, first_order=False, input_ordering=list(range(7, -1, -1))) big_eng.flush() # get_sparse_operator reverses the indices - we've accounted for this # with the reversed input_ordering. evol_matrix = expm(-1j * get_sparse_operator( hamiltonian, n_qubits=2 * self.size)).todense() initial_state = numpy.matrix(initial_state).T expected = evol_matrix * initial_state self.assertTrue( numpy.allclose(ordered_wavefunction(big_eng), expected.T, atol=1e-2), msg=str(numpy.array(ordered_wavefunction(big_eng) - expected.T))) projectq.ops.All(projectq.ops.Measure) | big_reg
def test_first_order_even_number_of_steps_no_reversal(self): hamiltonian = FermionOperator('2^ 3') + FermionOperator('3^ 2') projectq.ops.All(projectq.ops.H) | self.register _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, hamiltonian, trotter_steps=2, first_order=True) self.engine.flush() # Use 0^ 1 + 1^ 0 because get_sparse_operator reverses the indices. reversed_operator = FermionOperator('0^ 1') + FermionOperator('1^ 0') evol_matrix = expm(-1j * get_sparse_operator( reversed_operator, n_qubits=self.size)).todense() expected = evol_matrix * numpy.matrix( [2**(-self.size / 2.)] * 2**self.size).T self.assertTrue( numpy.allclose(ordered_wavefunction(self.engine), expected.T))
def test_simulate_n0n3(self): hamiltonian = FermionOperator('3^ 0^ 3 0') projectq.ops.All(projectq.ops.H) | self.register _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, hamiltonian, trotter_steps=1, first_order=False) self.engine.flush() # Though get_sparse_operator reverses the indices, this is symmetric. evol_matrix = expm( -1j * get_sparse_operator(hamiltonian, n_qubits=self.size)).todense() expected = evol_matrix * numpy.matrix( [2**(-self.size / 2.)] * 2**self.size).T self.assertTrue( numpy.allclose(ordered_wavefunction(self.engine), expected.T), msg=str(ordered_wavefunction(self.engine) - expected.T))
def test_simulate_dual_basis_evolution_bad_n_trotter_steps(self): with self.assertRaises(ValueError): _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, FermionOperator(), trotter_steps=0)
def test_simulate_dual_basis_evolution_bad_input_ordering(self): with self.assertRaises(ValueError): _low_depth_trotter_simulation.simulate_dual_basis_evolution( self.register, FermionOperator(), input_ordering=[1, 2])