Example #1
0
    def _setup(self):
        self._ret['translation'] = sum(
            [abs(p[0]) for p in self._operator.reorder_paulis()])
        self._ret['stretch'] = 0.5 / self._ret['translation']

        # translate the operator
        self._operator.simplify()
        translation_op = WeightedPauliOperator([[
            self._ret['translation'],
            Pauli(np.zeros(self._operator.num_qubits),
                  np.zeros(self._operator.num_qubits))
        ]])
        translation_op.simplify()
        self._operator += translation_op

        self._pauli_list = self._operator.reorder_paulis()

        # stretch the operator
        for p in self._pauli_list:
            p[0] = p[0] * self._ret['stretch']

        if len(self._pauli_list) == 1:
            slice_pauli_list = self._pauli_list
        else:
            if self._expansion_mode == 'trotter':
                slice_pauli_list = self._pauli_list
            else:
                slice_pauli_list = suzuki_expansion_slice_pauli_list(
                    self._pauli_list, 1, self._expansion_order)
        self._slice_pauli_list = slice_pauli_list
Example #2
0
    def _setup(
            self, operator: Optional[Union[OperatorBase,
                                           LegacyBaseOperator]]) -> None:
        self._operator = None
        self._ret = {}
        self._pauli_list = None
        self._phase_estimation_circuit = None
        self._slice_pauli_list = None
        if operator:
            # Convert to Legacy Operator if Operator flow passed in
            if isinstance(operator, OperatorBase):
                operator = operator.to_legacy_op()
            self._operator = op_converter.to_weighted_pauli_operator(
                operator.copy())
            self._ret['translation'] = sum(
                [abs(p[0]) for p in self._operator.reorder_paulis()])
            self._ret['stretch'] = 0.5 / self._ret['translation']

            # translate the operator
            self._operator.simplify()
            translation_op = WeightedPauliOperator([[
                self._ret['translation'],
                Pauli(np.zeros(self._operator.num_qubits),
                      np.zeros(self._operator.num_qubits))
            ]])
            translation_op.simplify()
            self._operator += translation_op
            self._pauli_list = self._operator.reorder_paulis()

            # stretch the operator
            for p in self._pauli_list:
                p[0] = p[0] * self._ret['stretch']

            if len(self._pauli_list) == 1:
                slice_pauli_list = self._pauli_list
            else:
                if self._expansion_mode == 'trotter':
                    slice_pauli_list = self._pauli_list
                else:
                    slice_pauli_list = suzuki_expansion_slice_pauli_list(
                        self._pauli_list, 1, self._expansion_order)
            self._slice_pauli_list = slice_pauli_list
Example #3
0
    def construct_circuit(
        self,
        state_register=None,
        ancillary_register=None,
        auxiliary_register=None,
        measurement=False,
    ):
        """Construct the Phase Estimation circuit

        Args:
            state_register (QuantumRegister): the optional register to use for the quantum state
            ancillary_register (QuantumRegister): the optional register to use for
            the ancillary measurement qubits
            auxiliary_register (QuantumRegister): an optional auxiliary quantum register
            measurement (bool): Boolean flag to indicate if measurement should be included
            in the circuit.

        Returns:
            QuantumCircuit: the QuantumCircuit object for the constructed circuit

        Raises:
            RuntimeError: Multiple identity pauli terms are present
            ValueError: invalid mode
        """
        # pylint: disable=invalid-name
        if self._circuit is None:
            if ancillary_register is None:
                a = QuantumRegister(self._num_ancillae, name='a')
            else:
                a = ancillary_register
            self._ancillary_register = a

            if state_register is None:
                if self._operator is not None:
                    q = QuantumRegister(self._operator.num_qubits, name='q')
                elif self._unitary_circuit_factory is not None:
                    q = QuantumRegister(
                        self._unitary_circuit_factory.num_target_qubits,
                        name='q')
                else:
                    raise RuntimeError('Missing operator specification.')
            else:
                q = state_register
            self._state_register = q

            qc = QuantumCircuit(a, q)

            if auxiliary_register is None:
                num_aux_qubits, aux = 0, None
                if self._state_in_circuit_factory is not None:
                    num_aux_qubits = self._state_in_circuit_factory.required_ancillas(
                    )
                if self._unitary_circuit_factory is not None:
                    num_aux_qubits = \
                        max(num_aux_qubits,
                            self._unitary_circuit_factory.required_ancillas_controlled())

                if num_aux_qubits > 0:
                    aux = QuantumRegister(num_aux_qubits, name='aux')
                    qc.add_register(aux)
            else:
                aux = auxiliary_register
                qc.add_register(aux)

            # initialize state_in
            if self._state_in is not None:
                qc.data += self._state_in.construct_circuit('circuit', q).data
            elif self._state_in_circuit_factory is not None:
                self._state_in_circuit_factory.build(qc, q, aux)

            # Put all ancillae in uniform superposition
            qc.u2(0, np.pi, a)

            # phase kickbacks via dynamics
            if self._operator is not None:
                # check for identify paulis to get its coef for applying
                # global phase shift on ancillae later
                num_identities = 0
                for p in self._pauli_list:
                    if np.all(np.logical_not(p[1].z)) and np.all(
                            np.logical_not(p[1].x)):
                        num_identities += 1
                        if num_identities > 1:
                            raise RuntimeError(
                                'Multiple identity pauli terms are present.')
                        self._ancilla_phase_coef = p[0].real if isinstance(
                            p[0], complex) else p[0]

                if len(self._pauli_list) == 1:
                    slice_pauli_list = self._pauli_list
                else:
                    if self._expansion_mode == 'trotter':
                        slice_pauli_list = self._pauli_list
                    elif self._expansion_mode == 'suzuki':
                        slice_pauli_list = suzuki_expansion_slice_pauli_list(
                            self._pauli_list, 1, self._expansion_order)
                    else:
                        raise ValueError(
                            'Unrecognized expansion mode {}.'.format(
                                self._expansion_mode))
                for i in range(self._num_ancillae):

                    qc_evolutions_inst = evolution_instruction(
                        slice_pauli_list,
                        -self._evo_time,
                        self._num_time_slices,
                        controlled=True,
                        power=(2**i),
                        shallow_slicing=self._shallow_circuit_concat)
                    if self._shallow_circuit_concat:
                        qc_evolutions = QuantumCircuit(q, a)
                        qc_evolutions.append(qc_evolutions_inst,
                                             qargs=list(q) + [a[i]])
                        qc.data += qc_evolutions.data
                    else:
                        qc.append(qc_evolutions_inst, qargs=list(q) + [a[i]])
                    # global phase shift for the ancilla due to the identity pauli term
                    qc.u1(self._evo_time * self._ancilla_phase_coef * (2**i),
                          a[i])

            elif self._unitary_circuit_factory is not None:
                for i in range(self._num_ancillae):
                    self._unitary_circuit_factory.build_controlled_power(
                        qc, q, a[i], 2**i, aux)

            # inverse qft on ancillae
            if self._iqft.num_qubits != len(
                    a):  # check if QFT has the right size
                try:  # try resizing
                    self._iqft.num_qubits = len(a)
                except AttributeError:
                    raise ValueError(
                        'The IQFT cannot be resized and does not have the '
                        'required size of {}'.format(len(a)))

            if hasattr(self._iqft, 'do_swaps'):
                self._iqft.do_swaps = False
            qc.append(self._iqft.to_instruction(), a)

            if measurement:
                c_ancilla = ClassicalRegister(self._num_ancillae, name='ca')
                qc.add_register(c_ancilla)
                # real hardware can currently not handle operations after measurements, which might
                # happen if the circuit gets transpiled, hence we're adding a safeguard-barrier
                qc.barrier()
                qc.measure(a, c_ancilla)

            self._circuit = qc
        return self._circuit
    def construct_circuit(
        self,
        state_register=None,
        ancillary_register=None,
        auxiliary_register=None,
        measurement=False,
    ):
        """
        Construct the Phase Estimation circuit

        Args:
            state_register (QuantumRegister): the optional register to use for the quantum state
            ancillary_register (QuantumRegister): the optional register to use for the ancillary measurement qubits
            auxiliary_register (QuantumRegister): an optional auxiliary quantum register
            measurement (bool): Boolean flag to indicate if measurement should be included in the circuit.

        Returns:
            the QuantumCircuit object for the constructed circuit
        """

        if self._circuit is None:
            if ancillary_register is None:
                a = QuantumRegister(self._num_ancillae, name='a')
            else:
                a = ancillary_register
            self._ancillary_register = a

            if state_register is None:
                if self._operator is not None:
                    q = QuantumRegister(self._operator.num_qubits, name='q')
                elif self._unitary_circuit_factory is not None:
                    q = QuantumRegister(
                        self._unitary_circuit_factory.num_target_qubits,
                        name='q')
                else:
                    raise RuntimeError('Missing operator specification.')
            else:
                q = state_register
            self._state_register = q

            qc = QuantumCircuit(a, q)

            if auxiliary_register is None:
                num_aux_qubits, aux = 0, None
                if self._state_in_circuit_factory is not None:
                    num_aux_qubits = self._state_in_circuit_factory.required_ancillas(
                    )
                if self._unitary_circuit_factory is not None:
                    num_aux_qubits = max(
                        num_aux_qubits,
                        self._unitary_circuit_factory.
                        required_ancillas_controlled())

                if num_aux_qubits > 0:
                    aux = QuantumRegister(num_aux_qubits, name='aux')
                    qc.add_register(aux)
            else:
                aux = auxiliary_register
                qc.add_register(aux)

            # initialize state_in
            if self._state_in is not None:
                qc.data += self._state_in.construct_circuit('circuit', q).data
            elif self._state_in_circuit_factory is not None:
                self._state_in_circuit_factory.build(qc, q, aux)

            # Put all ancillae in uniform superposition
            qc.u2(0, np.pi, a)

            # phase kickbacks via dynamics
            if self._operator is not None:
                # check for identify paulis to get its coef for applying global phase shift on ancillae later
                num_identities = 0
                for p in self._pauli_list:
                    if np.all(np.logical_not(p[1].z)) and np.all(
                            np.logical_not(p[1].x)):
                        num_identities += 1
                        if num_identities > 1:
                            raise RuntimeError(
                                'Multiple identity pauli terms are present.')
                        self._ancilla_phase_coef = p[0].real if isinstance(
                            p[0], complex) else p[0]

                if len(self._pauli_list) == 1:
                    slice_pauli_list = self._pauli_list
                else:
                    if self._expansion_mode == 'trotter':
                        slice_pauli_list = self._pauli_list
                    elif self._expansion_mode == 'suzuki':
                        slice_pauli_list = suzuki_expansion_slice_pauli_list(
                            self._pauli_list, 1, self._expansion_order)
                    else:
                        raise ValueError(
                            'Unrecognized expansion mode {}.'.format(
                                self._expansion_mode))
                for i in range(self._num_ancillae):

                    qc_evolutions_inst = evolution_instruction(
                        slice_pauli_list,
                        -self._evo_time,
                        self._num_time_slices,
                        controlled=True,
                        power=(2**i),
                        shallow_slicing=self._shallow_circuit_concat)
                    if self._shallow_circuit_concat:
                        qc_evolutions = QuantumCircuit(q, a)
                        qc_evolutions.append(qc_evolutions_inst,
                                             qargs=[x for x in q] + [a[i]])
                        qc.data += qc_evolutions.data
                    else:
                        qc.append(qc_evolutions_inst,
                                  qargs=[x for x in q] + [a[i]])
                    # global phase shift for the ancilla due to the identity pauli term
                    qc.u1(self._evo_time * self._ancilla_phase_coef * (2**i),
                          a[i])

            elif self._unitary_circuit_factory is not None:
                for i in range(self._num_ancillae):
                    self._unitary_circuit_factory.build_controlled_power(
                        qc, q, a[i], 2**i, aux)

            # inverse qft on ancillae
            self._iqft.construct_circuit(mode='circuit',
                                         qubits=a,
                                         circuit=qc,
                                         do_swaps=False)

            if measurement:
                c_ancilla = ClassicalRegister(self._num_ancillae, name='ca')
                qc.add_register(c_ancilla)
                # qc.barrier(a)
                qc.measure(a, c_ancilla)

            self._circuit = qc
        return self._circuit