def test_big_gates(self): """Test large gates with params""" qr = QuantumRegister(6, "q") circuit = QuantumCircuit(qr) circuit.append(IQP([[6, 5, 3], [5, 4, 5], [3, 5, 1]]), [0, 1, 2]) desired_vector = [ 1 / math.sqrt(16) * complex(0, 1), 1 / math.sqrt(8) * complex(1, 0), 1 / math.sqrt(16) * complex(1, 1), 0, 0, 1 / math.sqrt(8) * complex(1, 2), 1 / math.sqrt(16) * complex(1, 0), 0, ] circuit.initialize(desired_vector, [qr[3], qr[4], qr[5]]) circuit.unitary([[1, 0], [0, 1]], [qr[0]]) matrix = np.zeros((4, 4)) theta = Parameter("theta") circuit.append(HamiltonianGate(matrix, theta), [qr[1], qr[2]]) circuit = circuit.bind_parameters({theta: 1}) circuit.isometry(np.eye(4, 4), list(range(3, 5)), []) self.circuit_drawer(circuit, filename="big_gates.png")
def test_big_gates(self): """Test large gates with params""" filename = self._get_resource_path('test_latex_big_gates.tex') qr = QuantumRegister(6, 'q') circuit = QuantumCircuit(qr) circuit.append(IQP([[6, 5, 3], [5, 4, 5], [3, 5, 1]]), [0, 1, 2]) desired_vector = [ 1 / math.sqrt(16) * complex(0, 1), 1 / math.sqrt(8) * complex(1, 0), 1 / math.sqrt(16) * complex(1, 1), 0, 0, 1 / math.sqrt(8) * complex(1, 2), 1 / math.sqrt(16) * complex(1, 0), 0] circuit.initialize(desired_vector, [qr[3], qr[4], qr[5]]) circuit.unitary([[1, 0], [0, 1]], [qr[0]]) matrix = np.zeros((4, 4)) theta = Parameter('theta') circuit.append(HamiltonianGate(matrix, theta), [qr[1], qr[2]]) circuit = circuit.bind_parameters({theta: 1}) circuit.isometry(np.eye(4, 4), list(range(3, 5)), []) circuit_drawer(circuit, filename=filename, output='latex_source') self.assertEqualToReference(filename)
def ad_hoc_hhl(A, t0, r): reg_b = QuantumRegister(2) reg_c = QuantumRegister(4) ancil = QuantumRegister(1) circ = QuantumCircuit(reg_b, reg_c, ancil) circ.append(quantum_phase_estimation(2, 4, HamiltonianGate(A, t0 / 16)), range(6)) circ.swap(reg_c[1], reg_c[3]) for i in range(4): circ.cry(np.pi * (2**(4 - i - r)), reg_c[i], ancil[0]) circ.barrier() circ.swap(reg_c[1], reg_c[3]) circ.append( quantum_phase_estimation(2, 4, HamiltonianGate(A, t0 / 16)).inverse(), range(6)) return circ
def build_varckt(self): # Build variational circuit circ = QuantumCircuit(self.n) circ.h(range(self.n)) for i in range(self.p): eC = QuantumCircuit(self.n, name='$U(C,\\gamma_' + str(i + 1) + ')$') eC.append(HamiltonianGate(self.C, self.gamma[i]), range(self.n)) eB = QuantumCircuit(self.n, name='$U(B,\\beta_' + str(i + 1) + ')$') eB.rx(2 * self.beta[i], range(self.n)) circ.append(eC.to_gate(), range(self.n)) circ.append(eB.to_gate(), range(self.n)) circ.measure_all() return circ
def hhl_forward_ckt(n, t, m, l, A, t0, vis=False): reg_b = QuantumRegister(n, name='b') reg_c = QuantumRegister(t, name='c') reg_m = QuantumRegister(m, name='m') reg_l = QuantumRegister(l, name='l') temp = QuantumCircuit(reg_b, name='$U$') temp.append(HamiltonianGate(A, t0 / (2**t)), reg_b) circ = QuantumCircuit(reg_b, reg_c, reg_m, reg_l, name='$Fwd$') circ.append(quantum_phase_estimation(n, t, temp.to_gate(), vis=vis), range(n + t)) circ.h(reg_m) circ.h(reg_l) for i in range(m): circ.rz(t0 / (2**(m - i)), reg_m[i]) circ.append(subroutine_b(t, m, l, t0, vis=vis), range(n, n + t + m + l)) if vis: circ.draw('mpl', reverse_bits=True, style={'fontsize': 6, 'subfontsize': 3})\ .suptitle('HHL Forward Computation', fontsize=16) return circ.to_gate()
def get_loss( self, hamiltonian: OperatorBase, ansatz: QuantumCircuit, dt: float, current_parameters: np.ndarray, ) -> Tuple[Callable[[np.ndarray], float], Optional[Callable[[np.ndarray], np.ndarray]]]: """Get a function to evaluate the infidelity between Trotter step and ansatz. Args: hamiltonian: The Hamiltonian under which to evolve. ansatz: The parameterized quantum circuit which attempts to approximate the time-evolved state. dt: The time step. current_parameters: The current parameters. Returns: A callable to evaluate the infidelity and, if gradients are supported and required, a second callable to evaluate the gradient of the infidelity. """ self._validate_setup(skip={"optimizer"}) # use Trotterization to evolve the current state trotterized = ansatz.bind_parameters(current_parameters) if isinstance(hamiltonian, MatrixOp): evolution_gate = HamiltonianGate(hamiltonian.primitive, time=dt) else: evolution_gate = PauliEvolutionGate(hamiltonian, time=dt, synthesis=self.evolution) trotterized.append(evolution_gate, ansatz.qubits) # define the overlap of the Trotterized state and the ansatz x = ParameterVector("w", ansatz.num_parameters) shifted = ansatz.assign_parameters(current_parameters + x) overlap = StateFn(trotterized).adjoint() @ StateFn(shifted) converted = self.expectation.convert(overlap) def evaluate_loss( displacement: Union[np.ndarray, List[np.ndarray]] ) -> Union[float, List[float]]: """Evaluate the overlap of the ansatz with the Trotterized evolution. Args: displacement: The parameters for the ansatz. Returns: The fidelity of the ansatz with parameters ``theta`` and the Trotterized evolution. """ if isinstance(displacement, list): displacement = np.asarray(displacement) value_dict = {x_i: displacement[:, i].tolist() for i, x_i in enumerate(x)} else: value_dict = dict(zip(x, displacement)) sampled = self._sampler.convert(converted, params=value_dict) # in principle we could add different loss functions here, but we're currently # not aware of a use-case for a different one than in the paper return 1 - np.abs(sampled.eval()) ** 2 if _is_gradient_supported(ansatz) and self.use_parameter_shift: def evaluate_gradient(displacement: np.ndarray) -> np.ndarray: """Evaluate the gradient with the parameter-shift rule. This is hardcoded here since the gradient framework does not support computing gradients for overlaps. Args: displacement: The parameters for the ansatz. Returns: The gradient. """ # construct lists where each element is shifted by plus (or minus) pi/2 dim = displacement.size plus_shifts = (displacement + np.pi / 2 * np.identity(dim)).tolist() minus_shifts = (displacement - np.pi / 2 * np.identity(dim)).tolist() evaluated = evaluate_loss(plus_shifts + minus_shifts) gradient = (evaluated[:dim] - evaluated[dim:]) / 2 return gradient else: evaluate_gradient = None return evaluate_loss, evaluate_gradient