def test_probabilities(): p = 1 n_qubits = 2 # known set of angles for barbell angles = [1.96348709, 4.71241069] wf = np.array([ -1.17642098e-05 - 1j * 7.67538040e-06, -7.67563580e-06 - 1j * 7.07106781e-01, -7.67563580e-06 - 1j * 7.07106781e-01, -1.17642098e-05 - 1j * 7.67538040e-06 ]) with patch("grove.pyqaoa.qaoa.WavefunctionSimulator") as mock_wfs: fake_wfs = Mock(WavefunctionSimulator) fake_wfs.wavefunction.return_value = Wavefunction(wf) mock_wfs.return_value = fake_wfs fake_qc = Mock(QuantumComputer) inst = QAOA(qc=fake_qc, qubits=list(range(n_qubits)), steps=p, rand_seed=42) probs = inst.probabilities(angles) assert isinstance(probs, np.ndarray) prob_true = np.zeros((inst.nstates, 1)) prob_true[1] = 0.5 prob_true[2] = 0.5 assert np.isclose(probs, prob_true).all()
def recover_complexes(coef_string, classical_addresses): """ From a bit packed string, unpacks to get the wavefunction and classical measurement results :param coef_string: :param classical_addresses: :return: """ num_octets = len(coef_string) num_addresses = len(classical_addresses) num_memory_octets = _round_to_next_multiple(num_addresses, 8) // 8 num_wavefunction_octets = num_octets - num_memory_octets # Parse the classical memory mem = [] for i in range(num_memory_octets): octet = struct.unpack('B', coef_string[i:i + 1])[0] mem.extend(_octet_bits(octet)) mem = mem[0:num_addresses] # Parse the wavefunction wf = np.zeros(num_wavefunction_octets // OCTETS_PER_COMPLEX_DOUBLE, dtype=np.cfloat) for i, p in enumerate( range(num_memory_octets, num_octets, OCTETS_PER_COMPLEX_DOUBLE)): re_be = coef_string[p:p + OCTETS_PER_DOUBLE_FLOAT] im_be = coef_string[p + OCTETS_PER_DOUBLE_FLOAT:p + OCTETS_PER_COMPLEX_DOUBLE] re = struct.unpack('>d', re_be)[0] im = struct.unpack('>d', im_be)[0] wf[i] = complex(re, im) return Wavefunction(wf), mem
def get_wavefunction(self, circuit): """Run a circuit and get the wavefunction of the resulting statevector. Args: circuit (zquantum.core.circuit.Circuit): the circuit to prepare the state Returns: pyquil.wavefunction.Wavefunction """ self.num_circuits_run += 1 self.num_jobs_run += 1 ibmq_circuit = circuit.to_qiskit() coupling_map = None if self.device_connectivity is not None: coupling_map = CouplingMap(self.device_connectivity.connectivity) # Execute job to get wavefunction job = execute( ibmq_circuit, self.device, noise_model=self.noise_model, coupling_map=coupling_map, basis_gates=self.basis_gates, ) wavefunction = job.result().get_statevector(ibmq_circuit, decimals=20) return Wavefunction(wavefunction)
def test_sample_from_wavefunction_list(self): n_qubits = 4 # NOTE: our indexing places the state of qubit i at the ith index of the tuple. Hence |01> will result in # the tuple (1, 0) expected_bitstring = (1, 0, 0, 0) amplitudes = [0] * (2**n_qubits) amplitudes[1] = 1 # |0001> will be measured in all cases. wavefunction = Wavefunction(amplitudes) sample = set(sample_from_wavefunction(wavefunction, 500)) self.assertEqual(len(sample), 1) self.assertEqual(sample.pop(), expected_bitstring)
def test_sample_from_wavefunction_row_vector(): n_qubits = 4 # NOTE: our indexing places the state of qubit i at the ith index of the tuple. Hence |01> will result in # the tuple (1, 0) expected_bitstring = (1, 0, 0, 0) amplitudes = np.array([0] * (2**n_qubits)) amplitudes[1] = 1 # |0001> will be measured in all cases. wavefunction = Wavefunction(amplitudes) sample = set(sample_from_wavefunction(wavefunction, 500)) assert len(sample) == 1 assert sample.pop() == expected_bitstring
def jw_get_ground_state_at_particle_number(particle_number, qubit_operator): qubit_operator = load_qubit_operator(qubit_operator) sparse_matrix = qubit_operator_sparse(qubit_operator) ground_energy, ground_state_amplitudes = _jw_get_ground_state_at_particle_number( sparse_matrix, particle_number ) ground_state = Wavefunction(ground_state_amplitudes) value_estimate = ValueEstimate(ground_energy) save_wavefunction(ground_state, "ground-state.json") save_value_estimate(value_estimate, "value-estimate.json")
def create_random_wavefunction(n_qubits, seed=None): if seed: np.random.seed(seed) random_vector = [ complex(a, b) for a, b in zip(np.random.rand(2**n_qubits), np.random.rand(2**n_qubits)) ] normalization_factor = np.sqrt(np.sum(np.abs(random_vector)**2)) random_vector /= normalization_factor return Wavefunction(random_vector)
def wavefunction(self, program): """ Simulate the program and then project out the final state. Return the final state as a wavefunction pyquil object :param program: pyQuil program composed of stabilizer operations only :return: pyquil.Wavefunction.wavefunction object. """ self.load_program(program) self.tableau = self._n_qubit_tableau(self.num_qubits) self.kernel() stabilizers = binary_stabilizer_to_pauli_stabilizer( self.stabilizer_tableau()) stabilizer_state = project_stabilized_state(stabilizers) stabilizer_state = stabilizer_state.toarray() return Wavefunction(stabilizer_state.flatten())
def test_expectation(): """ expectation() routine can take a PauliSum operator on a matrix. Check this functionality and the return of the correct scalar value. """ X = np.array([[0, 1], [1, 0]]) def RX_gate(phi): return expm(-1j * phi * X) def rotation_wavefunction(phi): state = np.array([[1], [0]]) return RX_gate(phi).dot(state) prog = Program([RX(-2.5, 0)]) hamiltonian = PauliTerm("Z", 0, 1.0) minimizer = MagicMock() fake_result = Mock() fake_result.fun = 1.0 minimizer.return_value = fake_result with patch("pyquil.api.QuantumComputer") as fake_qc, \ patch("grove.pyvqe.vqe.WavefunctionSimulator") as mock_wfs: fake_qc.run.return_value = [[0], [0]] fake_wfs = Mock(WavefunctionSimulator) fake_wfs.wavefunction.return_value = Wavefunction( rotation_wavefunction(-2.5)) fake_wfs.expectation.return_value = [0.28366219] mock_wfs.return_value = fake_wfs inst = VQE(minimizer) energy = inst.expectation(prog, PauliSum([hamiltonian]), None, fake_qc) assert np.isclose(energy, 0.28366219) hamiltonian = np.array([[1, 0], [0, -1]]) energy = inst.expectation(prog, hamiltonian, None, fake_qc) assert np.isclose(energy, 0.28366219) prog = Program(H(0)) hamiltonian = PauliSum([PauliTerm('X', 0)]) energy = inst.expectation(prog, hamiltonian, 2, fake_qc) assert np.isclose(energy, 1.0)
def wavefunction(self, pyquil_program, classical_addresses=None): """ Simulate a pyQuil program and get the wavefunction back. :param Program pyquil_program: A pyQuil program. :param list classical_addresses: An optional list of classical addresses. :return: A tuple whose first element is a Wavefunction object, and whose second element is the list of classical bits corresponding to the classical addresses. :rtype: tuple """ # load program self.load_program(pyquil_program) # check valid classical memory access if not isinstance(classical_addresses, type(None)): # check that no classical addresses are repeated assert len(set(classical_addresses)) == len(classical_addresses) # check that all classical addresses are valid if np.min(classical_addresses) < 0 or \ np.max(classical_addresses) >= len(self.classical_memory): raise RuntimeError("Improper classical memory access outside " "allocated classical memory range.") # set classical bitmask mask = np.array(classical_addresses) else: mask = None # setup wavefunction self.wf = np.zeros(2**self.num_qubits, dtype=np.complex128) self.wf[0] = complex(1.0, 0) # evolve wf with program, via kernel self.kernel() # convert bools (False, True) to ints (0, 1) if isinstance(mask, type(None)): # return all results = [int(x) for x in self.classical_memory] else: results = [int(x) for x in self.classical_memory[mask]] return Wavefunction(self.wf), results
def load_wavefunction(file: TextIO) -> Wavefunction: """Load a qubit wavefunction from a file. Args: file (str or file-like object): the name of the file, or a file-like object. Returns: wavefunction (pyquil.wavefunction.Wavefunction): the wavefunction object """ if isinstance(file, str): with open(file, 'r') as f: data = json.load(f) else: data = json.load(file) wavefunction = Wavefunction(convert_dict_to_array(data['amplitudes'])) return wavefunction
def jw_get_ground_state_at_particle_number( particle_number: int, qubit_operator: Union[str, SymbolicOperator]): """Get the ground state wavefunction of the operator for the input particle number. Outputs are serialized to JSON within the files: "ground-state.json" and "value-estimate.json" ARGS: particle_number (int): The given number of particles in the system qubit_operator (Union[str, SymbolicOperator]): The operator for which to find the ground state """ if isinstance(qubit_operator, str): qubit_operator = load_qubit_operator(qubit_operator) sparse_matrix = qubit_operator_sparse(qubit_operator) ground_energy, ground_state_amplitudes = _jw_get_ground_state_at_particle_number( sparse_matrix, particle_number) ground_state = Wavefunction(ground_state_amplitudes) value_estimate = ValueEstimate(ground_energy) save_wavefunction(ground_state, "ground-state.json") save_value_estimate(value_estimate, "value-estimate.json")
def test_expectation(): """expectation() routine can take a PauliSum operator on a matrix. Check this functionality and the return of the correct scalar value""" X = np.array([[0, 1], [1, 0]]) def RX_gate(phi): return expm(-1j * phi * X) def rotation_wavefunction(phi): state = np.array([[1], [0]]) return RX_gate(phi).dot(state) prog = Program([RX(-2.5)(0)]) hamiltonian = PauliTerm("Z", 0, 1.0) minimizer = MagicMock() fake_result = Mock() fake_result.fun = 1.0 minimizer.return_value = fake_result fake_qvm = Mock(spec=['wavefunction', 'expectation', 'run']) fake_qvm.wavefunction.return_value = (Wavefunction( rotation_wavefunction(-2.5)), [0]) fake_qvm.expectation.return_value = [0.28366219] # for testing expectation fake_qvm.run.return_value = [[0], [0]] inst = VQE(minimizer) energy = inst.expectation(prog, PauliSum([hamiltonian]), None, fake_qvm) assert np.isclose(energy, 0.28366219) hamiltonian = np.array([[1, 0], [0, -1]]) energy = inst.expectation(prog, hamiltonian, None, fake_qvm) assert np.isclose(energy, 0.28366219) prog = Program(H(0)) hamiltonian = PauliSum([PauliTerm('X', 0)]) energy = inst.expectation(prog, hamiltonian, 2, fake_qvm) assert np.isclose(energy, 1.0)
def test_probabilities(): p = 1 n_qubits = 2 # known set of angles for barbell angles = [1.96348709, 4.71241069] wf = np.array([-1.17642098e-05 - 1j*7.67538040e-06, -7.67563580e-06 - 1j*7.07106781e-01, -7.67563580e-06 - 1j*7.07106781e-01, -1.17642098e-05 - 1j*7.67538040e-06]) fakeQVM = Mock(spec=qvm_module.SyncConnection()) fakeQVM.wavefunction = Mock(return_value=(Wavefunction(wf), 0)) inst = QAOA(fakeQVM, n_qubits, steps=p, rand_seed=42) true_probs = np.zeros_like(wf) for xx in range(wf.shape[0]): true_probs[xx] = np.conj(wf[xx]) * wf[xx] probs = inst.probabilities(angles) assert isinstance(probs, np.ndarray) prob_true = np.zeros((2**inst.n_qubits, 1)) prob_true[1] = 0.5 prob_true[2] = 0.5 assert np.isclose(probs, prob_true).all()
def get_wavefunction(self, circuit): """ Returns a wavefunction representing quantum state produced by a circuit Args: circuit (core.circuit.Circuit): quantum circuit to be executed. Returns: pyquil.Wafefunction: wavefunction object. """ num_qubits = len(circuit.get_qubits()) dev = qml.device(self.device, wires=num_qubits) ansatz = qml.from_qiskit(circuit.to_qiskit()) @qml.qnode(dev) def _circuit(): ansatz(wires=list(range(num_qubits))) return qml.expval(qml.Identity(0)) _circuit() return Wavefunction(dev.state)
def test_imag_wavefunction_io(): wf = Wavefunction([0, 1j, 0, 0, 0, 0, 0, 0]) save_wavefunction(wf, "wavefunction.json") loaded_wf = load_wavefunction("wavefunction.json") assert np.allclose(wf.amplitudes, loaded_wf.amplitudes) remove_file_if_exists("wavefunction.json")
def get_wavefunction(self, circuit): qulacs_state = self.get_qulacs_state_from_circuit(circuit) amplitudes = qulacs_state.get_vector() return Wavefunction(amplitudes)
def test_imag_wavefunction_io(self): wf = Wavefunction([0, 1j, 0, 0, 0, 0, 0, 0]) save_wavefunction(wf, "wavefunction.json") loaded_wf = load_wavefunction("wavefunction.json") self.assertTrue(np.allclose(wf.amplitudes, loaded_wf.amplitudes)) os.remove("wavefunction.json")
def wvf(): return Wavefunction(np.array([1.0, 1.j, 0.000005, 0.02]))
def test_real_wavefunction_io(self): wf = Wavefunction([0, 1, 0, 0, 0, 0, 0, 0]) save_wavefunction(wf, 'wavefunction.json') loaded_wf = load_wavefunction('wavefunction.json') self.assertTrue(np.allclose(wf.amplitudes, loaded_wf.amplitudes)) os.remove('wavefunction.json')
def wvf(): amps = np.array([1.0, 1.j, 0.000005, 0.02]) amps /= np.sqrt(np.sum(np.abs(amps)**2)) return Wavefunction(amps)