def suspend_test_phase_estimation_debug(self): theta = 5*np.pi/16 n_qubits = 2 a_idx = 1 k = 2 circuit = QuantumCircuit(n_qubits) psi = QuantumState(n_qubits) # |ancilla>|logical> phi = 1.25/2 print('k={}, phi={} mod (np.pi)'.format(k, phi)) # Apply H to ancilla bit to get |+> state circuit.add_H_gate(a_idx) # Apply kickback phase rotation to ancilla bit circuit.add_RZ_gate(a_idx, -np.pi * phi) # Apply C-U(Z0) theta_k = 2 ** (k-1) * theta print('phase:{} mod (np.pi)'.format(theta_k/np.pi)) circuit.add_RZ_gate(0, -theta_k) circuit.add_CNOT_gate(a_idx, 0) circuit.add_RZ_gate(0, theta_k) circuit.add_CNOT_gate(a_idx, 0) # Apply H to ancilla bit to get |+> state circuit.add_H_gate(a_idx) # run circuit circuit.update_quantum_state(psi) print(psi.get_vector()) # partial trace p0 = psi.get_marginal_probability([2, 0]) p1 = psi.get_marginal_probability([2, 1]) print(p0, p1)
def test_rotations() -> None: # https://github.com/CQCL/pytket/issues/35 circ = Circuit(1).Rx(0.5, 0) qulacs_circ = tk_to_qulacs(circ) state = QuantumState(1) qulacs_circ.update_quantum_state(state) v = state.get_vector() assert np.isclose(v[0], np.sqrt(0.5)) assert np.isclose(v[1], -1j * np.sqrt(0.5))
def _simulate_on_qulacs( self, data: _StateAndBuffer, shape: tuple, qulacs_state: qulacs.QuantumState, qulacs_circuit: qulacs.QuantumCircuit, ) -> None: data.buffer = data.state cirq_state = np.array(data.state).flatten().astype(np.complex64) qulacs_state.load(cirq_state) qulacs_circuit.update_quantum_state(qulacs_state) data.state = qulacs_state.get_vector().reshape(shape)
def test_prepstate(self): n_qubit = 4 dim = 2**n_qubit from qulacs import QuantumState from qulacs.state import inner_product s0 = QuantumState(n_qubit) s0.set_Haar_random_state() s1 = freqerica.circuit.universal.prepstate(n_qubit, s0.get_vector()) print(inner_product(s0, s1)) civec = {0b0011: .5, 0b0101: +.5j, 0b1001: -.5j, 0b0110: -.5} s2 = freqerica.circuit.universal.prepstate(n_qubit, civec) print(s2) assert True
class QulacsDevice(QubitDevice): """Qulacs device""" name = "Qulacs device" short_name = "qulacs.simulator" pennylane_requires = ">=0.11.0" version = __version__ author = "Steven Oud and Xanadu" gpu_supported = GPU_SUPPORTED _capabilities = { "model": "qubit", "tensor_observables": True, "inverse_operations": True } _operation_map = { "QubitStateVector": None, "BasisState": None, "QubitUnitary": None, "Toffoli": gate.TOFFOLI, "CSWAP": gate.FREDKIN, "CRZ": crz, "SWAP": gate.SWAP, "CNOT": gate.CNOT, "CZ": gate.CZ, "S": gate.S, "T": gate.T, "RX": gate.RX, "RY": gate.RY, "RZ": gate.RZ, "PauliX": gate.X, "PauliY": gate.Y, "PauliZ": gate.Z, "Hadamard": gate.H, "PhaseShift": phase_shift, } _observable_map = { "PauliX": "X", "PauliY": "Y", "PauliZ": "Z", "Identity": "I", "Hadamard": None, "Hermitian": None, } operations = _operation_map.keys() observables = _observable_map.keys() # Add inverse gates to _operation_map _operation_map.update({k + ".inv": v for k, v in _operation_map.items()}) def __init__(self, wires, shots=1000, analytic=True, gpu=False, **kwargs): super().__init__(wires=wires, shots=shots, analytic=analytic) if gpu: if not QulacsDevice.gpu_supported: raise DeviceError( "GPU not supported with installed version of qulacs. " "Please install 'qulacs-gpu' to use GPU simulation.") self._state = QuantumStateGpu(self.num_wires) else: self._state = QuantumState(self.num_wires) self._circuit = QuantumCircuit(self.num_wires) self._pre_rotated_state = self._state.copy() def apply(self, operations, **kwargs): rotations = kwargs.get("rotations", []) self.apply_operations(operations) self._pre_rotated_state = self._state.copy() # Rotating the state for measurement in the computational basis if rotations: self.apply_operations(rotations) def apply_operations(self, operations): """Apply the circuit operations to the state. This method serves as an auxiliary method to :meth:`~.QulacsDevice.apply`. Args: operations (List[pennylane.Operation]): operations to be applied """ for i, op in enumerate(operations): if i > 0 and isinstance(op, (QubitStateVector, BasisState)): raise DeviceError( "Operation {} cannot be used after other Operations have already been applied " "on a {} device.".format(op.name, self.short_name)) if isinstance(op, QubitStateVector): self._apply_qubit_state_vector(op) elif isinstance(op, BasisState): self._apply_basis_state(op) elif isinstance(op, QubitUnitary): self._apply_qubit_unitary(op) elif isinstance(op, (CRZ, PhaseShift)): self._apply_matrix(op) else: self._apply_gate(op) def _apply_qubit_state_vector(self, op): """Initialize state with a state vector""" wires = op.wires input_state = op.parameters[0] if len(input_state) != 2**len(wires): raise ValueError("State vector must be of length 2**wires.") if input_state.ndim != 1 or len(input_state) != 2**len(wires): raise ValueError("State vector must be of length 2**wires.") if not np.isclose(np.linalg.norm(input_state, 2), 1.0, atol=tolerance): raise ValueError("Sum of amplitudes-squared does not equal one.") input_state = _reverse_state(input_state) # call qulacs' state initialization self._state.load(input_state) def _apply_basis_state(self, op): """Initialize a basis state""" wires = op.wires par = op.parameters # translate from PennyLane to Qulacs wire order bits = par[0][::-1] n_basis_state = len(bits) if not set(bits).issubset({0, 1}): raise ValueError( "BasisState parameter must consist of 0 or 1 integers.") if n_basis_state != len(wires): raise ValueError( "BasisState parameter and wires must be of equal length.") basis_state = 0 for bit in bits: basis_state = (basis_state << 1) | bit # call qulacs' basis state initialization self._state.set_computational_basis(basis_state) def _apply_qubit_unitary(self, op): """Apply unitary to state""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters if len(par[0]) != 2**len(device_wires): raise ValueError( "Unitary matrix must be of shape (2**wires, 2**wires).") if op.inverse: par[0] = par[0].conj().T # reverse wires (could also change par[0]) reverse_wire_labels = device_wires.tolist()[::-1] unitary_gate = gate.DenseMatrix(reverse_wire_labels, par[0]) self._circuit.add_gate(unitary_gate) unitary_gate.update_quantum_state(self._state) def _apply_matrix(self, op): """Apply predefined gate-matrix to state (must follow qulacs convention)""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters mapped_operation = self._operation_map[op.name] if op.inverse: mapped_operation = self._get_inverse_operation( mapped_operation, device_wires, par) if callable(mapped_operation): gate_matrix = mapped_operation(*par) else: gate_matrix = mapped_operation # gate_matrix is already in correct order => no wire-reversal needed dense_gate = gate.DenseMatrix(device_wires.labels, gate_matrix) self._circuit.add_gate(dense_gate) gate.DenseMatrix(device_wires.labels, gate_matrix).update_quantum_state(self._state) def _apply_gate(self, op): """Apply native qulacs gate""" # translate op wire labels to consecutive wire labels used by the device device_wires = self.map_wires(op.wires) par = op.parameters mapped_operation = self._operation_map[op.name] if op.inverse: mapped_operation = self._get_inverse_operation( mapped_operation, device_wires, par) # Negating the parameters such that it adheres to qulacs par = np.negative(par) # mapped_operation is already in correct order => no wire-reversal needed self._circuit.add_gate(mapped_operation(*device_wires.labels, *par)) mapped_operation(*device_wires.labels, *par).update_quantum_state(self._state) @staticmethod def _get_inverse_operation(mapped_operation, device_wires, par): """Return the inverse of an operation""" if mapped_operation is None: return mapped_operation # if an inverse variant of the operation exists try: inverse_operation = getattr(gate, mapped_operation.get_name() + "dag") except AttributeError: # if the operation is hard-coded try: if callable(mapped_operation): inverse_operation = np.conj(mapped_operation(*par)).T else: inverse_operation = np.conj(mapped_operation).T # if mapped_operation is a qulacs.gate and np.conj is applied on it except TypeError: # else, redefine the operation as the inverse matrix def inverse_operation(*p): # embed the gate in a unitary matrix with shape (2**wires, 2**wires) g = mapped_operation(*p).get_matrix() mat = reduce(np.kron, [np.eye(2)] * len(device_wires)).astype(complex) mat[-len(g):, -len(g):] = g # mat follows PL convention => reverse wire-order reverse_wire_labels = device_wires.tolist()[::-1] gate_mat = gate.DenseMatrix(reverse_wire_labels, np.conj(mat).T) return gate_mat return inverse_operation def analytic_probability(self, wires=None): """Return the (marginal) analytic probability of each computational basis state.""" if self._state is None: return None all_probs = self._abs(self.state)**2 prob = self.marginal_prob(all_probs, wires) return prob def expval(self, observable): if self.analytic: qulacs_observable = Observable(self.num_wires) if isinstance(observable.name, list): observables = [ self._observable_map[obs] for obs in observable.name ] else: observables = [self._observable_map[observable.name]] if None not in observables: applied_wires = self.map_wires(observable.wires).tolist() opp = " ".join([ f"{obs} {applied_wires[i]}" for i, obs in enumerate(observables) ]) qulacs_observable.add_operator(1.0, opp) return qulacs_observable.get_expectation_value( self._pre_rotated_state) # exact expectation value eigvals = self._asarray(observable.eigvals, dtype=self.R_DTYPE) prob = self.probability(wires=observable.wires) return self._dot(eigvals, prob) # estimate the ev return np.mean(self.sample(observable)) @property def state(self): # returns the state after all operations are applied return _reverse_state(self._state.get_vector()) def reset(self): self._state.set_zero_state() self._pre_rotated_state = self._state.copy() self._circuit = QuantumCircuit(self.num_wires)
class QulacsDevice(Device): """Qulacs device""" name = 'Qulacs device' short_name = 'qulacs.simulator' pennylane_requires = '>=0.5.0' version = __version__ author = 'Steven Oud' _capabilities = {'model': 'qubit', 'tensor_observables': True} _operations_map = { 'QubitStateVector': None, 'BasisState': None, 'QubitUnitary': None, 'Toffoli': toffoli, 'CSWAP': CSWAP, 'CRZ': crz, 'Rot': None, 'SWAP': gate.SWAP, 'CNOT': gate.CNOT, 'CZ': gate.CZ, 'S': gate.S, 'Sdg': gate.Sdag, 'T': gate.T, 'Tdg': gate.Tdag, 'RX': gate.RX, 'RY': gate.RY, 'RZ': gate.RZ, 'PauliX': gate.X, 'PauliY': gate.Y, 'PauliZ': gate.Z, 'Hadamard': gate.H } _observable_map = { 'PauliX': X, 'PauliY': Y, 'PauliZ': Z, 'Hadamard': H, 'Identity': I, 'Hermitian': hermitian } operations = _operations_map.keys() observables = _observable_map.keys() def __init__(self, wires, gpu=False, **kwargs): super().__init__(wires=wires) if gpu: if not GPU_SUPPORTED: raise DeviceError( 'GPU not supported with installed version of qulacs. ' 'Please install "qulacs-gpu" to use GPU simulation.') self._state = QuantumStateGpu(wires) else: self._state = QuantumState(wires) self._circuit = QuantumCircuit(wires) self._first_operation = True def apply(self, operation, wires, par): par = np.negative(par) if operation == 'BasisState' and not self._first_operation: raise DeviceError( 'Operation {} cannot be used after other Operations have already been applied ' 'on a {} device.'.format(operation, self.short_name)) self._first_operation = False if operation == 'QubitStateVector': if len(par[0]) != 2**len(wires): raise ValueError('State vector must be of length 2**wires.') self._state.load(par[0]) elif operation == 'BasisState': if len(par[0]) != len(wires): raise ValueError('Basis state must prepare all qubits.') basis_state = 0 for bit in reversed(par[0]): basis_state = (basis_state << 1) | bit self._state.set_computational_basis(basis_state) elif operation == 'QubitUnitary': if len(par[0]) != 2**len(wires): raise ValueError( 'Unitary matrix must be of shape (2**wires, 2**wires).') unitary_gate = gate.DenseMatrix(wires, par[0]) self._circuit.add_gate(unitary_gate) elif operation == 'Rot': self._circuit.add_gate( gate.merge([ gate.RZ(wires[0], par[0]), gate.RY(wires[0], par[1]), gate.RZ(wires[0], par[2]) ])) elif operation in ('CRZ', 'Toffoli', 'CSWAP'): mapped_operation = self._operations_map[operation] if callable(mapped_operation): gate_matrix = mapped_operation(*par) else: gate_matrix = mapped_operation dense_gate = gate.DenseMatrix(wires, gate_matrix) self._circuit.add_gate(dense_gate) else: mapped_operation = self._operations_map[operation] self._circuit.add_gate(mapped_operation(*wires, *par)) @property def state(self): return self._state.get_vector() def pre_measure(self): self._circuit.update_quantum_state(self._state) def expval(self, observable, wires, par): bra = self._state.copy() if isinstance(observable, list): A = self._get_tensor_operator_matrix(observable, par) wires = [item for sublist in wires for item in sublist] else: A = self._get_operator_matrix(observable, par) dense_gate = gate.DenseMatrix(wires, A) dense_gate.update_quantum_state(self._state) expectation = inner_product(bra, self._state) return expectation.real def probabilities(self): states = itertools.product(range(2), repeat=self.num_wires) probs = np.abs(self.state)**2 return OrderedDict(zip(states, probs)) def reset(self): self._state.set_zero_state() self._circuit = QuantumCircuit(self.num_wires) def _get_operator_matrix(self, operation, par): A = self._observable_map[operation] if not callable(A): return A return A(*par) def _get_tensor_operator_matrix(self, obs, par): ops = [self._get_operator_matrix(o, p) for o, p in zip(obs, par)] return functools.reduce(np.kron, ops)
observable = Observable(nqubit) observable.add_operator(1, "Z 0") observable.add_operator(2, "Z 1") #observable.add_operator(4, "Z 2") data = list() x_value = list() y_value = list() for i in range(n_data): #state.set_Haar_random_state() x = random.random() state.set_zero_state() # U_in|000> U_in(x).update_quantum_state(state) state_vec = state.get_vector() circuit.update_quantum_state(state) value = observable.get_expectation_value(state) #print(value) # data.append((state_vec, value)) data.append((x, value)) x_value.append(x) y_value.append(value) with open('Training.data', 'wb') as f: pickle.dump(data, f) plt.plot(x_value, y_value, 'o', color='black') plt.show() plt.savefig('qcl_training.png')
#### Preprare teacher data x_train = x_min + (x_max - x_min) * np.random.rand(num_x_train) y_train = func_to_learn(x_train) # Add noise to data mag_noise = 0.05 y_train = y_train + mag_noise * np.random.randn(num_x_train) plt.plot(x_train, y_train, "o"); plt.show() # Construct the input quantum state from qulacs import QuantumState, QuantumCircuit state = QuantumState(nqubit) # Initial state |000> state.set_zero_state() print(state.get_vector()) # Function to encode x def U_in(x): U = QuantumCircuit(nqubit) angle_y = np.arcsin(x) angle_z = np.arccos(x**2) for i in range(nqubit): U.add_RY_gate(i, angle_y) U.add_RZ_gate(i, angle_z) return U # Test an input state