Quellcode fΓΌr qiskit.circuit.library.arithmetic.multipliers.hrs_cumulative_multiplier

# This code is part of Qiskit.
# (C) Copyright IBM 2017, 2021.
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Compute the product of two qubit registers using classical multiplication approach."""

from typing import Optional
from qiskit.circuit import QuantumRegister, AncillaRegister, QuantumCircuit

from .multiplier import Multiplier

[Doku]class HRSCumulativeMultiplier(Multiplier): r"""A multiplication circuit to store product of two input registers out-of-place. Circuit uses the approach from [1]. As an example, a multiplier circuit that performs a non-modular multiplication on two 3-qubit sized registers with the default adder is as follows (where ``Adder`` denotes the ``CDKMRippleCarryAdder``): .. parsed-literal:: a_0: ────■───────────────────────── β”‚ a_1: ────┼─────────■─────────────── β”‚ β”‚ a_2: ────┼─────────┼─────────■───── β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β” b_0: ─0 β”œβ”€0 β”œβ”€0 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ b_1: ─1 β”œβ”€1 β”œβ”€1 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ b_2: ─2 β”œβ”€2 β”œβ”€2 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ out_0: ─3 β”œβ”€ β”œβ”€ β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ out_1: ─4 β”œβ”€3 β”œβ”€ β”œ β”‚ Adder β”‚β”‚ Adder β”‚β”‚ Adder β”‚ out_2: ─5 β”œβ”€4 β”œβ”€3 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ out_3: ─6 β”œβ”€5 β”œβ”€4 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ out_4: ─ β”œβ”€6 β”œβ”€5 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ out_5: ─ β”œβ”€ β”œβ”€6 β”œ β”‚ β”‚β”‚ β”‚β”‚ β”‚ aux_0: ─7 β”œβ”€7 β”œβ”€7 β”œ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Multiplication in this circuit is implemented in a classical approach by performing a series of shifted additions using one of the input registers while the qubits from the other input register act as control qubits for the adders. **References:** [1] HΓ€ner et al., Optimizing Quantum Circuits for Arithmetic, 2018. `arXiv:1805.12445 <https://arxiv.org/pdf/1805.12445.pdf>`_ """ 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 circuit = QuantumCircuit(*self.qregs, name=name) 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[:]) circuit.append(controlled_adder, qr_list) self.append(circuit.to_gate(), self.qubits)