示例#1
0
    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 = []
示例#2
0
    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)
示例#3
0
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
示例#4
0
    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
示例#5
0
    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)
示例#6
0
 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)
示例#7
0
    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])
示例#8
0
        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
示例#9
0
    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 = []
示例#10
0
    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 = []
示例#13
0
    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)
示例#17
0
        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
示例#18
0
    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 = []
示例#20
0
    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 = []
示例#21
0
    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)
示例#22
0
    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)
示例#23
0
    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)
示例#24
0
    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
示例#25
0
    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)
示例#27
0
    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)