def _reset_registers(self): if self.num_state_qubits: qr_state = QuantumRegister(self.num_state_qubits, name='state') qr_sum = QuantumRegister(self.num_sum_qubits, name='sum') self.qregs = [qr_state, qr_sum] self._qubits = qr_state[:] + qr_sum[:] self._ancillas = [] if self.num_carry_qubits > 0: qr_carry = AncillaRegister(self.num_carry_qubits, name='carry') self.qregs += [qr_carry] self._qubits += qr_carry[:] self._ancillas += qr_carry[:] if self.num_control_qubits > 0: qr_control = AncillaRegister(self.num_control_qubits, name='control') self.qregs += [qr_control] self._qubits += qr_control[:] self._ancillas += qr_control[:] else: self.qregs = [] self._qubits = [] self._ancillas = []
def _reset_registers(self): self.qregs = [] if self.num_state_qubits: qr_state = QuantumRegister(self.num_state_qubits, name="state") qr_sum = QuantumRegister(self.num_sum_qubits, name="sum") self.qregs = [qr_state, qr_sum] if self.num_carry_qubits > 0: qr_carry = AncillaRegister(self.num_carry_qubits, name="carry") self.add_register(qr_carry) if self.num_control_qubits > 0: qr_control = AncillaRegister(self.num_control_qubits, name="control") self.add_register(qr_control)
def _zero_reflection(num_state_qubits: int, qubits: List[int], mcx_mode: Optional[str] = None) -> QuantumCircuit: qr_state = QuantumRegister(num_state_qubits, 'state') reflection = QuantumCircuit(qr_state, name='S_0') num_ancillas = MCXGate.get_num_ancilla_qubits(len(qubits) - 1, mcx_mode) if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas, 'ancilla') reflection.add_register(qr_ancilla) else: qr_ancilla = [] reflection.x(qubits) if len(qubits) == 1: reflection.z( 0 ) # MCX does not allow 0 control qubits, therefore this is separate else: reflection.h(qubits[-1]) reflection.mcx(qubits[:-1], qubits[-1], qr_ancilla[:], mode=mcx_mode) reflection.h(qubits[-1]) reflection.x(qubits) return reflection
def _build(self): num_state_qubits = self.oracle.num_qubits - self.oracle.num_ancillas self.add_register(QuantumRegister(num_state_qubits, name='state')) num_ancillas = numpy.max([ self.oracle.num_ancillas, self.zero_reflection.num_ancillas, self.state_preparation.num_ancillas ]) if num_ancillas > 0: self.add_register(AncillaRegister(num_ancillas, name='ancilla')) self.compose(self.oracle, list(range(self.oracle.num_qubits)), inplace=True) if self._insert_barriers: self.barrier() self.compose(self.state_preparation.inverse(), list(range(self.state_preparation.num_qubits)), inplace=True) if self._insert_barriers: self.barrier() self.compose(self.zero_reflection, list(range(self.zero_reflection.num_qubits)), inplace=True) if self._insert_barriers: self.barrier() self.compose(self.state_preparation, list(range(self.state_preparation.num_qubits)), inplace=True) # minus sign self.global_phase = numpy.pi
def num_state_qubits(self, num_state_qubits: Optional[int]) -> None: """Set the number of state qubits. Note that this will change the quantum registers. Args: num_state_qubits: The new number of state qubits. """ if self._num_state_qubits is None or num_state_qubits != self._num_state_qubits: self._invalidate() # reset data self._num_state_qubits = num_state_qubits if num_state_qubits is not None: # set the new qubit registers qr_state = QuantumRegister(num_state_qubits, name='state') q_compare = QuantumRegister(1, name='compare') self.qregs = [qr_state, q_compare] self._qubits = qr_state[:] + q_compare[:] # add ancillas is required num_ancillas = num_state_qubits - 1 if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla)
def test_aregs(self): """Test getting ancilla registers from circuit. """ ar1 = AncillaRegister(10, "a") self.assertEqual(ar1.name, "a") self.assertEqual(ar1.size, 10) self.assertEqual(type(ar1), AncillaRegister)
def test_ancillas(self): """Test ancillas() method.""" qr1 = QuantumRegister(1, "q1") cr1 = ClassicalRegister(2, "c1") ar1 = AncillaRegister(2, "a1") qr2 = QuantumRegister(2, "q2") cr2 = ClassicalRegister(1, "c2") ar2 = AncillaRegister(1, "a2") qc = QuantumCircuit(qr2, cr2, ar2, qr1, cr1, ar1) ancillas = qc.ancillas self.assertEqual(qc.num_ancillas, 3) self.assertEqual(ancillas[0], ar2[0]) self.assertEqual(ancillas[1], ar1[0]) self.assertEqual(ancillas[2], ar1[1])
def control(num_ctrl_qubits=1, label=None, ctrl_state=None): qr_state = QuantumRegister(self.num_state_qubits + 1, "state") if self.num_state_qubits > 1: qr_ancilla = AncillaRegister(max(1, self.num_state_qubits - 1)) qc = QuantumCircuit(qr_state, qr_ancilla, name="exp(iHk)") else: qc = QuantumCircuit(qr_state, name="exp(iHk)") qr_ancilla = None # Control will be qr[0] q_control = qr_state[0] qr = qr_state[1:] # A1 commutes, so one application with evolution_time*2^{j} to the last qubit is enough qc.append( self._main_diag_circ(self.evolution_time * power).control().to_gate(), [q_control] + qr[:], ) # Update trotter steps to compensate the error trotter_steps_new = int( np.ceil(np.sqrt(power) * self.trotter_steps)) # exp(iA2t/2m) qc.u( self.off_diag * self.evolution_time * power / trotter_steps_new, 3 * np.pi / 2, np.pi / 2, qr[0], ) # for _ in range(power): for _ in range(0, trotter_steps_new): if qr_ancilla: qc.append( self._off_diag_circ( self.evolution_time * power / trotter_steps_new).control().to_gate(), [q_control] + qr[:] + qr_ancilla[:], ) else: qc.append( self._off_diag_circ( self.evolution_time * power / trotter_steps_new).control().to_gate(), [q_control] + qr[:], ) # exp(-iA2t/2m) qc.u( -self.off_diag * self.evolution_time * power / trotter_steps_new, 3 * np.pi / 2, np.pi / 2, qr[0], ) return qc
def _reset_registers(self): if self.num_state_qubits: qr_state = QuantumRegister(self.num_state_qubits, name="state") qr_sum = QuantumRegister(self.num_sum_qubits, name="sum") self.qregs = [qr_state, qr_sum] self._ancillas = [] if self.num_carry_qubits > 0: qr_carry = AncillaRegister(self.num_carry_qubits, name="carry") self.qregs += [qr_carry] self._ancillas += qr_carry[:] if self.num_control_qubits > 0: qr_control = AncillaRegister(self.num_control_qubits, name="control") self.qregs += [qr_control] self._ancillas += qr_control[:] else: self.qregs = [] self._ancillas = []
def _reset_registers(self, num_state_qubits: Optional[int]) -> None: self.qregs = [] if num_state_qubits is not None: qr_state = QuantumRegister(num_state_qubits, "state") qr_target = QuantumRegister(1, "target") self.qregs = [qr_state, qr_target] num_ancillas = num_state_qubits if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla)
def test_ancilla_register_add_register(self): """Verify AncillaRegisters are found by find_bit by their locations in qubits/qregs.""" qreg = QuantumRegister(3, "qr") areg = AncillaRegister(5, "ar") qc = QuantumCircuit() qc.add_register(qreg) qc.add_register(areg) for idx, bit in enumerate(areg): self.assertEqual(qc.find_bit(bit), (idx + len(qreg), [(areg, idx)]))
def _reset_registers(self, num_state_qubits): if num_state_qubits is not None: # set new register of appropriate size qr_state = QuantumRegister(num_state_qubits, name='state') qr_target = QuantumRegister(1, name='target') num_ancillas = max(1, self.degree - 1) qr_ancilla = AncillaRegister(num_ancillas) self.qregs = [qr_state, qr_target, qr_ancilla] self._qubits = qr_state[:] + qr_target[:] + qr_ancilla[:] self._ancillas = qr_ancilla[:] else: self.qregs = [] self._qubits = [] self._ancillas = []
def _reset_registers(self, num_state_qubits: int) -> None: """Reset the quantum registers. Args: num_state_qubits: The number of qubits to represent the matrix. """ qr_state = QuantumRegister(num_state_qubits, "state") self.qregs = [qr_state] self._ancillas = [] self._qubits = qr_state[:] if num_state_qubits > 1: qr_ancilla = AncillaRegister(max(1, num_state_qubits - 1)) self.add_register(qr_ancilla)
def _reset_registers(self, num_state_qubits: Optional[int]) -> None: """Reset the registers.""" self.qregs = [] if num_state_qubits is not None: qr_state = QuantumRegister(num_state_qubits) qr_target = QuantumRegister(1) self.qregs = [qr_state, qr_target] # add ancillas if required if len(self.breakpoints) > 1: num_ancillas = num_state_qubits qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla)
def __init__( self, num_variable_qubits: int, flags: Optional[List[int]] = None, mcx_mode: str = "noancilla", ) -> None: """Create a new logical AND circuit. Args: num_variable_qubits: The qubits of which the OR is computed. The result will be written into an additional result qubit. flags: A list of +1/0/-1 marking negations or omissions of qubits. mcx_mode: The mode to be used to implement the multi-controlled X gate. """ self.num_variable_qubits = num_variable_qubits self.flags = flags # add registers qr_variable = QuantumRegister(num_variable_qubits, name="variable") qr_result = QuantumRegister(1, name="result") circuit = QuantumCircuit(qr_variable, qr_result, name="and") # determine the control qubits: all that have a nonzero flag flags = flags or [1] * num_variable_qubits control_qubits = [ q for q, flag in zip(qr_variable, flags) if flag != 0 ] # determine the qubits that need to be flipped (if a flag is < 0) flip_qubits = [q for q, flag in zip(qr_variable, flags) if flag < 0] # determine the number of ancillas num_ancillas = MCXGate.get_num_ancilla_qubits(len(control_qubits), mode=mcx_mode) if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas, "ancilla") circuit.add_register(qr_ancilla) else: qr_ancilla = [] if len(flip_qubits) > 0: circuit.x(flip_qubits) circuit.mcx(control_qubits, qr_result[:], qr_ancilla[:], mode=mcx_mode) if len(flip_qubits) > 0: circuit.x(flip_qubits) super().__init__(*circuit.qregs, name="and") self.compose(circuit.to_gate(), qubits=self.qubits, inplace=True)
def _reset_registers(self, num_state_qubits: Optional[int]) -> None: self.qregs = [] if num_state_qubits: qr_state = QuantumRegister(num_state_qubits) qr_target = QuantumRegister(1) self.qregs = [qr_state, qr_target] # Calculate number of ancilla qubits required num_ancillas = num_state_qubits + 1 if self.contains_zero_breakpoint: num_ancillas -= 1 if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla)
def control(num_ctrl_qubits=1, label=None, ctrl_state=None): qr_state = QuantumRegister(self.num_state_qubits + 1) if self.num_state_qubits > 1: qr_ancilla = AncillaRegister(max(1, self.num_state_qubits - 1)) qc_control = QuantumCircuit(qr_state, qr_ancilla, name="off_diags") else: qc_control = QuantumCircuit(qr_state, name="off_diags") qr_ancilla = None # Control will be qr[0] q_control = qr_state[0] qr = qr_state[1:] qc_control.cu(-2 * theta, 3 * np.pi / 2, np.pi / 2, 0, q_control, qr[0]) for i in range(0, self.num_state_qubits - 1): q_controls = [] q_controls.append(q_control) qc_control.cx(qr[i], qr[i + 1]) q_controls.append(qr[i + 1]) # Now we want controlled by 0 qc_control.x(qr[i]) for j in range(i, 0, -1): qc_control.cx(qr[i], qr[j - 1]) q_controls.append(qr[j - 1]) qc_control.x(qr[i]) # Multicontrolled x rotation if len(q_controls) > 1: ugate = UGate(-2 * theta, 3 * np.pi / 2, np.pi / 2) qc_control.append( MCMTVChain(ugate, len(q_controls), 1), q_controls[:] + [qr[i]] + qr_ancilla[:len(q_controls) - 1], ) else: qc_control.cu(-2 * theta, 3 * np.pi / 2, np.pi / 2, 0, q_controls[0], qr[i]) # Uncompute qc_control.x(qr[i]) for j in range(0, i): qc_control.cx(qr[i], qr[j]) qc_control.x(qr[i]) qc_control.cx(qr[i], qr[i + 1]) return qc_control
def test_ancilla_qubit(self): """Test ancilla type and that it can be accessed as ordinary qubit.""" qr, ar = QuantumRegister(2), AncillaRegister(2) qc = QuantumCircuit(qr, ar) with self.subTest("num ancillas and qubits"): self.assertEqual(qc.num_ancillas, 2) self.assertEqual(qc.num_qubits, 4) with self.subTest("ancilla is a qubit"): for ancilla in qc.ancillas: self.assertIsInstance(ancilla, AncillaQubit) self.assertIsInstance(ancilla, Qubit) with self.subTest("qubit is not an ancilla"): action_qubits = [qubit for qubit in qc.qubits if not isinstance(qubit, AncillaQubit)] self.assertEqual(len(action_qubits), 2)
def _reset_registers(self, num_state_qubits: Optional[int]) -> None: if num_state_qubits is not None: qr_state = QuantumRegister(num_state_qubits) qr_target = QuantumRegister(1) self.qregs = [qr_state, qr_target] self._qubits = qr_state[:] + qr_target[:] self._ancillas = [] # add ancillas if required if len(self.breakpoints) > 1: num_ancillas = num_state_qubits qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla) else: self.qregs = [] self._qubits = [] self._ancillas = []
def _reset_registers(self, num_state_qubits: Optional[int]) -> None: if num_state_qubits is not None: qr_state = QuantumRegister(num_state_qubits, 'state') qr_target = QuantumRegister(1, 'target') self.qregs = [qr_state, qr_target] self._ancillas = [] self._qubits = qr_state[:] + qr_target[:] num_ancillas = num_state_qubits if num_ancillas > 0: qr_ancilla = AncillaRegister(num_ancillas) self.add_register(qr_ancilla) else: self.qregs = [] self._qubits = [] self._ancillas = []
def test_decomposing_with_boxed_ancillas(self): """Test decomposing a circuit which contains an instruction with ancillas. This was a previous bug where the wire-map in the DAG raised an error upon mapping the Qubit type to the AncillaQubit type. """ ar = AncillaRegister(1) qr = QuantumRegister(1) qc = QuantumCircuit(qr, ar) qc.cx(0, 1) qc.cx(0, 1) qc2 = QuantumCircuit(*qc.qregs) qc2.append(qc, [0, 1]) decomposed = qc2.decompose() # used to raise a DAGCircuitError self.assertEqual(decomposed, qc)
def _build(self): num_state_qubits = self.oracle.num_qubits - self.oracle.num_ancillas circuit = QuantumCircuit(QuantumRegister(num_state_qubits, name="state"), name="Q") num_ancillas = numpy.max( [ self.oracle.num_ancillas, self.zero_reflection.num_ancillas, self.state_preparation.num_ancillas, ] ) if num_ancillas > 0: circuit.add_register(AncillaRegister(num_ancillas, name="ancilla")) circuit.compose(self.oracle, list(range(self.oracle.num_qubits)), inplace=True) if self._insert_barriers: circuit.barrier() circuit.compose( self.state_preparation.inverse(), list(range(self.state_preparation.num_qubits)), inplace=True, ) if self._insert_barriers: circuit.barrier() circuit.compose( self.zero_reflection, list(range(self.zero_reflection.num_qubits)), inplace=True ) if self._insert_barriers: circuit.barrier() circuit.compose( self.state_preparation, list(range(self.state_preparation.num_qubits)), inplace=True ) # minus sign circuit.global_phase = numpy.pi self.add_register(*circuit.qregs) try: circuit_wrapped = circuit.to_gate() except QiskitError: circuit_wrapped = circuit.to_instruction() self.compose(circuit_wrapped, qubits=self.qubits, inplace=True)
def __init__( self, num_state_qubits: int, num_result_qubits: Optional[int] = None, adder: Optional[QuantumCircuit] = None, name: str = "HRSCumulativeMultiplier", ) -> None: r""" Args: num_state_qubits: The number of qubits in either input register for state :math:`|a\rangle` or :math:`|b\rangle`. The two input registers must have the same number of qubits. num_result_qubits: The number of result qubits to limit the output to. If number of result qubits is :math:`n`, multiplication modulo :math:`2^n` is performed to limit the output to the specified number of qubits. Default value is ``2 * num_state_qubits`` to represent any possible result from the multiplication of the two inputs. adder: Half adder circuit to be used for performing multiplication. The CDKMRippleCarryAdder is used as default if no adder is provided. name: The name of the circuit object. Raises: NotImplementedError: If ``num_result_qubits`` is not default and a custom adder is provided. """ super().__init__(num_state_qubits, num_result_qubits, name=name) if self.num_result_qubits != 2 * num_state_qubits and adder is not None: raise NotImplementedError( "Only default adder is supported for modular multiplication.") # define the registers qr_a = QuantumRegister(num_state_qubits, name="a") qr_b = QuantumRegister(num_state_qubits, name="b") qr_out = QuantumRegister(self.num_result_qubits, name="out") self.add_register(qr_a, qr_b, qr_out) # prepare adder as controlled gate if adder is None: from qiskit.circuit.library.arithmetic.adders import CDKMRippleCarryAdder adder = CDKMRippleCarryAdder(num_state_qubits, kind="half") # get the number of helper qubits needed num_helper_qubits = adder.num_ancillas # add helper qubits if required if num_helper_qubits > 0: qr_h = AncillaRegister(num_helper_qubits, name="helper") # helper/ancilla qubits self.add_register(qr_h) # build multiplication circuit for i in range(num_state_qubits): excess_qubits = max( 0, num_state_qubits + i + 1 - self.num_result_qubits) if excess_qubits == 0: num_adder_qubits = num_state_qubits adder_for_current_step = adder else: num_adder_qubits = num_state_qubits - excess_qubits + 1 adder_for_current_step = CDKMRippleCarryAdder(num_adder_qubits, kind="fixed") controlled_adder = adder_for_current_step.to_gate().control(1) qr_list = ([qr_a[i]] + qr_b[:num_adder_qubits] + qr_out[i:num_state_qubits + i + 1 - excess_qubits]) if num_helper_qubits > 0: qr_list.extend(qr_h[:]) self.append(controlled_adder, qr_list)
def _off_diag_circ(self, theta: float = 1) -> QuantumCircuit: """Circuit implementing the matrix consisting of entries in the off diagonals. Args: theta: Scale factor for the off diagonal entries (e.g. evolution_time/trotter_steps). Returns: The quantum circuit implementing the matrix consisting of entries in the off diagonals. """ theta *= self.off_diag qr = QuantumRegister(self.num_state_qubits) if self.num_state_qubits > 1: qr_ancilla = AncillaRegister(max(1, self.num_state_qubits - 2)) qc = QuantumCircuit(qr, qr_ancilla, name="off_diags") else: qc = QuantumCircuit(qr, name="off_diags") qr_ancilla = None qc.u(-2 * theta, 3 * np.pi / 2, np.pi / 2, qr[0]) for i in range(0, self.num_state_qubits - 1): q_controls = [] qc.cx(qr[i], qr[i + 1]) q_controls.append(qr[i + 1]) # Now we want controlled by 0 qc.x(qr[i]) for j in range(i, 0, -1): qc.cx(qr[i], qr[j - 1]) q_controls.append(qr[j - 1]) qc.x(qr[i]) # Multicontrolled rotation if len(q_controls) > 1: ugate = UGate(-2 * theta, 3 * np.pi / 2, np.pi / 2) qc.append( MCMTVChain(ugate, len(q_controls), 1), q_controls[:] + [qr[i]] + qr_ancilla[:len(q_controls) - 1], ) else: qc.cu(-2 * theta, 3 * np.pi / 2, np.pi / 2, 0, q_controls[0], qr[i]) # Uncompute qc.x(qr[i]) for j in range(0, i): qc.cx(qr[i], qr[j]) qc.x(qr[i]) qc.cx(qr[i], qr[i + 1]) # pylint: disable=unused-argument def control(num_ctrl_qubits=1, label=None, ctrl_state=None): qr_state = QuantumRegister(self.num_state_qubits + 1) if self.num_state_qubits > 1: qr_ancilla = AncillaRegister(max(1, self.num_state_qubits - 1)) qc_control = QuantumCircuit(qr_state, qr_ancilla, name="off_diags") else: qc_control = QuantumCircuit(qr_state, name="off_diags") qr_ancilla = None # Control will be qr[0] q_control = qr_state[0] qr = qr_state[1:] qc_control.cu(-2 * theta, 3 * np.pi / 2, np.pi / 2, 0, q_control, qr[0]) for i in range(0, self.num_state_qubits - 1): q_controls = [] q_controls.append(q_control) qc_control.cx(qr[i], qr[i + 1]) q_controls.append(qr[i + 1]) # Now we want controlled by 0 qc_control.x(qr[i]) for j in range(i, 0, -1): qc_control.cx(qr[i], qr[j - 1]) q_controls.append(qr[j - 1]) qc_control.x(qr[i]) # Multicontrolled x rotation if len(q_controls) > 1: ugate = UGate(-2 * theta, 3 * np.pi / 2, np.pi / 2) qc_control.append( MCMTVChain(ugate, len(q_controls), 1), q_controls[:] + [qr[i]] + qr_ancilla[:len(q_controls) - 1], ) else: qc_control.cu(-2 * theta, 3 * np.pi / 2, np.pi / 2, 0, q_controls[0], qr[i]) # Uncompute qc_control.x(qr[i]) for j in range(0, i): qc_control.cx(qr[i], qr[j]) qc_control.x(qr[i]) qc_control.cx(qr[i], qr[i + 1]) return qc_control qc.control = control return qc
def construct_circuit( self, matrix: Union[np.ndarray, QuantumCircuit], vector: Union[np.ndarray, QuantumCircuit]) -> QuantumCircuit: """Construct the HHL circuit. Args: matrix: The matrix specifying the system, i.e. A in Ax=b. vector: The vector specifying the right hand side of the equation in Ax=b. Returns: The HHL circuit. Raises: ValueError: If the input is not in the correct format. ValueError: If the type of the input matrix is not supported. """ # State preparation circuit - default is qiskit if isinstance(vector, QuantumCircuit): nb = vector.num_qubits vector_circuit = vector elif isinstance(vector, np.ndarray): nb = int(np.log2(len(vector))) vector_circuit = QuantumCircuit(nb) vector_circuit.isometry(vector / np.linalg.norm(vector), list(range(nb)), None) # If state preparation is probabilistic the number of qubit flags should increase nf = 1 # Hamiltonian simulation circuit - default is Trotterization if isinstance(matrix, QuantumCircuit): matrix_circuit = matrix elif isinstance(matrix, (list, np.ndarray)): if isinstance(matrix, list): matrix = np.array(matrix) if matrix.shape[0] != matrix.shape[1]: raise ValueError("Input matrix must be square!") if np.log2(matrix.shape[0]) % 1 != 0: raise ValueError("Input matrix dimension must be 2^n!") if not np.allclose(matrix, matrix.conj().T): raise ValueError("Input matrix must be hermitian!") if matrix.shape[0] != 2**vector_circuit.num_qubits: raise ValueError("Input vector dimension does not match input " "matrix dimension! Vector dimension: " + str(vector_circuit.num_qubits) + ". Matrix dimension: " + str(matrix.shape[0])) matrix_circuit = NumPyMatrix(matrix, evolution_time=2 * np.pi) else: raise ValueError(f'Invalid type for matrix: {type(matrix)}.') # Set the tolerance for the matrix approximation if hasattr(matrix_circuit, "tolerance"): matrix_circuit.tolerance = self._epsilon_a # check if the matrix can calculate the condition number and store the upper bound if hasattr(matrix_circuit, "condition_bounds") and matrix_circuit.condition_bounds() is not\ None: kappa = matrix_circuit.condition_bounds()[1] else: kappa = 1 # Update the number of qubits required to represent the eigenvalues nl = max(nb + 1, int(np.log2(kappa)) + 1) # check if the matrix can calculate bounds for the eigenvalues if hasattr(matrix_circuit, "eigs_bounds") and matrix_circuit.eigs_bounds() is not None: lambda_min, lambda_max = matrix_circuit.eigs_bounds() # Constant so that the minimum eigenvalue is represented exactly, since it contributes # the most to the solution of the system delta = self._get_delta(nl, lambda_min, lambda_max) # Update evolution time matrix_circuit.evolution_time = 2 * np.pi * delta / lambda_min # Update the scaling of the solution self.scaling = lambda_min else: delta = 1 / (2**nl) print("The solution will be calculated up to a scaling factor.") if self._exact_reciprocal: reciprocal_circuit = ExactReciprocal(nl, delta) # Update number of ancilla qubits na = matrix_circuit.num_ancillas else: # Calculate breakpoints for the reciprocal approximation num_values = 2**nl constant = delta a = int(round(num_values**(2 / 3))) # pylint: disable=invalid-name # Calculate the degree of the polynomial and the number of intervals r = 2 * constant / a + np.sqrt(np.abs(1 - (2 * constant / a)**2)) degree = min( nb, int( np.log(1 + (16.23 * np.sqrt(np.log(r)**2 + (np.pi / 2)**2) * kappa * (2 * kappa - self._epsilon_r)) / self._epsilon_r))) num_intervals = int( np.ceil(np.log((num_values - 1) / a) / np.log(5))) # Calculate breakpoints and polynomials breakpoints = [] for i in range(0, num_intervals): # Add the breakpoint to the list breakpoints.append(a * (5**i)) # Define the right breakpoint of the interval if i == num_intervals - 1: breakpoints.append(num_values - 1) reciprocal_circuit = PiecewiseChebyshev( lambda x: np.arcsin(constant / x), degree, breakpoints, nl) na = max(matrix_circuit.num_ancillas, reciprocal_circuit.num_ancillas) # Initialise the quantum registers qb = QuantumRegister(nb) # right hand side and solution ql = QuantumRegister(nl) # eigenvalue evaluation qubits if na > 0: qa = AncillaRegister(na) # ancilla qubits qf = QuantumRegister(nf) # flag qubits if na > 0: qc = QuantumCircuit(qb, ql, qa, qf) else: qc = QuantumCircuit(qb, ql, qf) # State preparation qc.append(vector_circuit, qb[:]) # QPE phase_estimation = PhaseEstimation(nl, matrix_circuit) if na > 0: qc.append(phase_estimation, ql[:] + qb[:] + qa[:matrix_circuit.num_ancillas]) else: qc.append(phase_estimation, ql[:] + qb[:]) # Conditioned rotation if self._exact_reciprocal: qc.append(reciprocal_circuit, ql[::-1] + [qf[0]]) else: qc.append(reciprocal_circuit.to_instruction(), ql[:] + [qf[0]] + qa[:reciprocal_circuit.num_ancillas]) # QPE inverse if na > 0: qc.append(phase_estimation.inverse(), ql[:] + qb[:] + qa[:matrix_circuit.num_ancillas]) else: qc.append(phase_estimation.inverse(), ql[:] + qb[:]) return qc
def __init__(self, num_state_qubits: int, kind: str = "full", name: str = "VBERippleCarryAdder") -> None: """ Args: num_state_qubits: The size of the register. kind: The kind of adder, can be ``'full'`` for a full adder, ``'half'`` for a half adder, or ``'fixed'`` for a fixed-sized adder. A full adder includes both carry-in and carry-out, a half only carry-out, and a fixed-sized adder neither carry-in nor carry-out. name: The name of the circuit. Raises: ValueError: If ``num_state_qubits`` is lower than 1. """ if num_state_qubits < 1: raise ValueError("The number of qubits must be at least 1.") super().__init__(num_state_qubits, name=name) # define the input registers registers = [] if kind == "full": qr_cin = QuantumRegister(1, name="cin") registers.append(qr_cin) else: qr_cin = [] qr_a = QuantumRegister(num_state_qubits, name="a") qr_b = QuantumRegister(num_state_qubits, name="b") registers += [qr_a, qr_b] if kind in ["half", "full"]: qr_cout = QuantumRegister(1, name="cout") registers.append(qr_cout) else: qr_cout = [] self.add_register(*registers) if num_state_qubits > 1: qr_help = AncillaRegister(num_state_qubits - 1, name="helper") self.add_register(qr_help) else: qr_help = [] # the code is simplified a lot if we create a list of all carries and helpers carries = qr_cin[:] + qr_help[:] + qr_cout[:] # corresponds to Carry gate in [1] qc_carry = QuantumCircuit(4, name="Carry") qc_carry.ccx(1, 2, 3) qc_carry.cx(1, 2) qc_carry.ccx(0, 2, 3) carry_gate = qc_carry.to_gate() carry_gate_dg = carry_gate.inverse() # corresponds to Sum gate in [1] qc_sum = QuantumCircuit(3, name="Sum") qc_sum.cx(1, 2) qc_sum.cx(0, 2) sum_gate = qc_sum.to_gate() circuit = QuantumCircuit(*self.qregs, name=name) # handle all cases for the first qubits, depending on whether cin is available i = 0 if kind == "half": i += 1 circuit.ccx(qr_a[0], qr_b[0], carries[0]) elif kind == "fixed": i += 1 if num_state_qubits == 1: circuit.cx(qr_a[0], qr_b[0]) else: circuit.ccx(qr_a[0], qr_b[0], carries[0]) for inp, out in zip(carries[:-1], carries[1:]): circuit.append(carry_gate, [inp, qr_a[i], qr_b[i], out]) i += 1 if kind in ["full", "half"]: # final CX (cancels for the 'fixed' case) circuit.cx(qr_a[-1], qr_b[-1]) if len(carries) > 1: circuit.append(sum_gate, [carries[-2], qr_a[-1], qr_b[-1]]) i -= 2 for j, (inp, out) in enumerate( zip(reversed(carries[:-1]), reversed(carries[1:]))): if j == 0: if kind == "fixed": i += 1 else: continue circuit.append(carry_gate_dg, [inp, qr_a[i], qr_b[i], out]) circuit.append(sum_gate, [inp, qr_a[i], qr_b[i]]) i -= 1 if kind in ["half", "fixed"] and num_state_qubits > 1: circuit.ccx(qr_a[0], qr_b[0], carries[0]) circuit.cx(qr_a[0], qr_b[0]) self.append(circuit.to_gate(), self.qubits)
def __init__(self, num_state_qubits: int, kind: str = "full", name: str = "CDKMRippleCarryAdder") -> None: r""" Args: num_state_qubits: The number of qubits in either input register for state :math:`|a\rangle` or :math:`|b\rangle`. The two input registers must have the same number of qubits. kind: The kind of adder, can be ``'full'`` for a full adder, ``'half'`` for a half adder, or ``'fixed'`` for a fixed-sized adder. A full adder includes both carry-in and carry-out, a half only carry-out, and a fixed-sized adder neither carry-in nor carry-out. name: The name of the circuit object. Raises: ValueError: If ``num_state_qubits`` is lower than 1. """ if num_state_qubits < 1: raise ValueError("The number of qubits must be at least 1.") super().__init__(num_state_qubits, name=name) if kind == "full": qr_c = QuantumRegister(1, name="cin") self.add_register(qr_c) else: qr_c = AncillaRegister(1, name="help") qr_a = QuantumRegister(num_state_qubits, name="a") qr_b = QuantumRegister(num_state_qubits, name="b") self.add_register(qr_a, qr_b) if kind in ["full", "half"]: qr_z = QuantumRegister(1, name="cout") self.add_register(qr_z) if kind != "full": self.add_register(qr_c) # build carry circuit for majority of 3 bits in-place # corresponds to MAJ gate in [1] qc_maj = QuantumCircuit(3, name="MAJ") qc_maj.cx(0, 1) qc_maj.cx(0, 2) qc_maj.ccx(2, 1, 0) maj_gate = qc_maj.to_gate() # build circuit for reversing carry operation # corresponds to UMA gate in [1] qc_uma = QuantumCircuit(3, name="UMA") qc_uma.ccx(2, 1, 0) qc_uma.cx(0, 2) qc_uma.cx(2, 1) uma_gate = qc_uma.to_gate() circuit = QuantumCircuit(*self.qregs, name=name) # build ripple-carry adder circuit circuit.append(maj_gate, [qr_a[0], qr_b[0], qr_c[0]]) for i in range(num_state_qubits - 1): circuit.append(maj_gate, [qr_a[i + 1], qr_b[i + 1], qr_a[i]]) if kind in ["full", "half"]: circuit.cx(qr_a[-1], qr_z[0]) for i in reversed(range(num_state_qubits - 1)): circuit.append(uma_gate, [qr_a[i + 1], qr_b[i + 1], qr_a[i]]) circuit.append(uma_gate, [qr_a[0], qr_b[0], qr_c[0]]) self.append(circuit.to_gate(), self.qubits)