Пример #1
0
    def __init__(self, data, input_dims=None, output_dims=None):
        """Initialize a quantum channel Choi matrix operator.

        Args:
            data (QuantumCircuit or
                  Instruction or
                  BaseOperator or
                  matrix): data to initialize superoperator.
            input_dims (tuple): the input subsystem dimensions.
                                [Default: None]
            output_dims (tuple): the output subsystem dimensions.
                                 [Default: None]

        Raises:
            QiskitError: if input data cannot be initialized as a
            Choi matrix.

        Additional Information:
            If the input or output dimensions are None, they will be
            automatically determined from the input data. If the input data is
            a Numpy array of shape (4**N, 4**N) qubit systems will be used. If
            the input operator is not an N-qubit operator, it will assign a
            single subsystem with dimension specified by the shape of the input.
        """
        # If the input is a raw list or matrix we assume that it is
        # already a Choi matrix.
        if isinstance(data, (list, np.ndarray)):
            # Initialize from raw numpy or list matrix.
            choi_mat = np.asarray(data, dtype=complex)
            # Determine input and output dimensions
            dim_l, dim_r = choi_mat.shape
            if dim_l != dim_r:
                raise QiskitError('Invalid Choi-matrix input.')
            if input_dims:
                input_dim = np.product(input_dims)
            if output_dims:
                output_dim = np.product(output_dims)
            if output_dims is None and input_dims is None:
                output_dim = int(np.sqrt(dim_l))
                input_dim = dim_l // output_dim
            elif input_dims is None:
                input_dim = dim_l // output_dim
            elif output_dims is None:
                output_dim = dim_l // input_dim
            # Check dimensions
            if input_dim * output_dim != dim_l:
                raise QiskitError("Invalid shape for input Choi-matrix.")
        else:
            # Otherwise we initialize by conversion from another Qiskit
            # object into the QuantumChannel.
            if isinstance(data, (QuantumCircuit, Instruction)):
                # If the input is a Terra QuantumCircuit or Instruction we
                # convert it to a SuperOp
                data = SuperOp._init_instruction(data)
            else:
                # We use the QuantumChannel init transform to initialize
                # other objects into a QuantumChannel or Operator object.
                data = self._init_transformer(data)
            input_dim, output_dim = data.dim
            # Now that the input is an operator we convert it to a Choi object
            rep = getattr(data, '_channel_rep', 'Operator')
            choi_mat = _to_choi(rep, data._data, input_dim, output_dim)
            if input_dims is None:
                input_dims = data.input_dims()
            if output_dims is None:
                output_dims = data.output_dims()
        # Check and format input and output dimensions
        input_dims = self._automatic_dims(input_dims, input_dim)
        output_dims = self._automatic_dims(output_dims, output_dim)
        super().__init__(choi_mat, input_dims, output_dims, 'Choi')
Пример #2
0
    def __init__(self, data, input_dims=None, output_dims=None):
        """Initialize a PTM quantum channel operator.

        Args:
            data (QuantumCircuit or
                  Instruction or
                  BaseOperator or
                  matrix): data to initialize superoperator.
            input_dims (tuple): the input subsystem dimensions.
                                [Default: None]
            output_dims (tuple): the output subsystem dimensions.
                                 [Default: None]

        Raises:
            QiskitError: if input data is not an N-qubit channel or
                         cannot be initialized as a PTM.

        Additional Information:
            If the input or output dimensions are None, they will be
            automatically determined from the input data. The PTM
            representation is only valid for N-qubit channels.
        """
        # If the input is a raw list or matrix we assume that it is
        # already a Chi matrix.
        if isinstance(data, (list, np.ndarray)):
            # Should we force this to be real?
            ptm = np.asarray(data, dtype=complex)
            # Determine input and output dimensions
            dout, din = ptm.shape
            if input_dims:
                input_dim = np.product(input_dims)
            else:
                input_dim = int(np.sqrt(din))
            if output_dims:
                output_dim = np.product(input_dims)
            else:
                output_dim = int(np.sqrt(dout))
            if output_dim**2 != dout or input_dim**2 != din or input_dim != output_dim:
                raise QiskitError("Invalid shape for PTM matrix.")
        else:
            # Otherwise we initialize by conversion from another Qiskit
            # object into the QuantumChannel.
            if isinstance(data, (QuantumCircuit, Instruction)):
                # If the input is a Terra QuantumCircuit or Instruction we
                # convert it to a SuperOp
                data = SuperOp._init_instruction(data)
            else:
                # We use the QuantumChannel init transform to initialize
                # other objects into a QuantumChannel or Operator object.
                data = self._init_transformer(data)
            input_dim, output_dim = data.dim
            # Now that the input is an operator we convert it to a PTM object
            rep = getattr(data, "_channel_rep", "Operator")
            ptm = _to_ptm(rep, data._data, input_dim, output_dim)
            if input_dims is None:
                input_dims = data.input_dims()
            if output_dims is None:
                output_dims = data.output_dims()
        # Check input is N-qubit channel
        num_qubits = int(np.log2(input_dim))
        if 2**num_qubits != input_dim or input_dim != output_dim:
            raise QiskitError("Input is not an n-qubit Pauli transfer matrix.")
        super().__init__(ptm, num_qubits=num_qubits)
Пример #3
0
def execute(
        experiments,
        backend,
        basis_gates=None,
        coupling_map=None,  # circuit transpile options
        backend_properties=None,
        initial_layout=None,
        seed_transpiler=None,
        optimization_level=None,
        pass_manager=None,
        qobj_id=None,
        qobj_header=None,
        shots=1024,  # common run options
        memory=False,
        max_credits=10,
        seed_simulator=None,
        default_qubit_los=None,
        default_meas_los=None,  # schedule run options
        schedule_los=None,
        meas_level=MeasLevel.CLASSIFIED,
        meas_return=MeasReturnType.AVERAGE,
        memory_slots=None,
        memory_slot_size=100,
        rep_time=None,
        rep_delay=None,
        parameter_binds=None,
        schedule_circuit=False,
        inst_map=None,
        meas_map=None,
        scheduling_method=None,
        init_qubits=None,
        **run_config):
    """Execute a list of :class:`qiskit.circuit.QuantumCircuit` or
    :class:`qiskit.pulse.Schedule` on a backend.

    The execution is asynchronous, and a handle to a job instance is returned.

    Args:
        experiments (QuantumCircuit or list[QuantumCircuit] or Schedule or list[Schedule]):
            Circuit(s) or pulse schedule(s) to execute

        backend (BaseBackend or Backend):
            Backend to execute circuits on.
            Transpiler options are automatically grabbed from
            backend.configuration() and backend.properties().
            If any other option is explicitly set (e.g. coupling_map), it
            will override the backend's.

        basis_gates (list[str]):
            List of basis gate names to unroll to.
            e.g: ``['u1', 'u2', 'u3', 'cx']``
            If ``None``, do not unroll.

        coupling_map (CouplingMap or list): Coupling map (perhaps custom) to
            target in mapping. Multiple formats are supported:

            #. CouplingMap instance
            #. list
               Must be given as an adjacency matrix, where each entry
               specifies all two-qubit interactions supported by backend
               e.g:
               ``[[0, 1], [0, 3], [1, 2], [1, 5], [2, 5], [4, 1], [5, 3]]``

        backend_properties (BackendProperties):
            Properties returned by a backend, including information on gate
            errors, readout errors, qubit coherence times, etc. Find a backend
            that provides this information with:
            ``backend.properties()``

        initial_layout (Layout or dict or list):
            Initial position of virtual qubits on physical qubits.
            If this layout makes the circuit compatible with the coupling_map
            constraints, it will be used.
            The final layout is not guaranteed to be the same, as the transpiler
            may permute qubits through swaps or other means.

            Multiple formats are supported:

            #. :class:`qiskit.transpiler.Layout` instance
            #. ``dict``:
               virtual to physical::

                    {qr[0]: 0,
                     qr[1]: 3,
                     qr[2]: 5}

               physical to virtual::
                    {0: qr[0],
                     3: qr[1],
                     5: qr[2]}

            #. ``list``
               virtual to physical::

                    [0, 3, 5]  # virtual qubits are ordered (in addition to named)

               physical to virtual::

                    [qr[0], None, None, qr[1], None, qr[2]]

        seed_transpiler (int): Sets random seed for the stochastic parts of the transpiler

        optimization_level (int): How much optimization to perform on the circuits.
            Higher levels generate more optimized circuits,
            at the expense of longer transpilation time.
            #. No optimization
            #. Light optimization
            #. Heavy optimization
            #. Highest optimization
            If None, level 1 will be chosen as default.

        pass_manager (PassManager): The pass manager to use during transpilation. If this
            arg is present, auto-selection of pass manager based on the transpile options
            will be turned off and this pass manager will be used directly.

        qobj_id (str): String identifier to annotate the Qobj

        qobj_header (QobjHeader or dict): User input that will be inserted in Qobj header,
            and will also be copied to the corresponding :class:`qiskit.result.Result`
            header. Headers do not affect the run.

        shots (int): Number of repetitions of each circuit, for sampling. Default: 1024

        memory (bool): If True, per-shot measurement bitstrings are returned as well
            (provided the backend supports it). For OpenPulse jobs, only
            measurement level 2 supports this option. Default: False

        max_credits (int): Maximum credits to spend on job. Default: 10

        seed_simulator (int): Random seed to control sampling, for when backend is a simulator

        default_qubit_los (list): List of default qubit LO frequencies in Hz

        default_meas_los (list): List of default meas LO frequencies in Hz

        schedule_los (None or list or dict or LoConfig): Experiment LO
            configurations, if specified the list is in the format::

                list[Union[Dict[PulseChannel, float], LoConfig]] or
                     Union[Dict[PulseChannel, float], LoConfig]

        meas_level (int or MeasLevel): Set the appropriate level of the
            measurement output for pulse experiments.

        meas_return (str or MeasReturn): Level of measurement data for the
            backend to return For ``meas_level`` 0 and 1:
            ``"single"`` returns information from every shot.
            ``"avg"`` returns average measurement output (averaged over number
            of shots).

        memory_slots (int): Number of classical memory slots used in this job.

        memory_slot_size (int): Size of each memory slot if the output is Level 0.

        rep_time (int): Time per program execution in seconds. Must be from the list provided
            by the backend (``backend.configuration().rep_times``). Defaults to the first entry.

        rep_delay (float): Delay between programs in seconds. Only supported on certain
            backends (``backend.configuration().dynamic_reprate_enabled`` ). If supported,
            ``rep_delay`` will be used instead of ``rep_time`` and must be from the range supplied
            by the backend (``backend.configuration().rep_delay_range``). Default is given by
            ``backend.configuration().default_rep_delay``.

        parameter_binds (list[dict]): List of Parameter bindings over which the set of
            experiments will be executed. Each list element (bind) should be of the form
            ``{Parameter1: value1, Parameter2: value2, ...}``. All binds will be
            executed across all experiments, e.g. if parameter_binds is a
            length-n list, and there are m experiments, a total of :math:`m x n`
            experiments will be run (one for each experiment/bind pair).

        schedule_circuit (bool): If ``True``, ``experiments`` will be converted to
            :class:`qiskit.pulse.Schedule` objects prior to execution.

        inst_map (InstructionScheduleMap):
            Mapping of circuit operations to pulse schedules. If None, defaults to the
            ``instruction_schedule_map`` of ``backend``.

        meas_map (list(list(int))):
            List of sets of qubits that must be measured together. If None, defaults to
            the ``meas_map`` of ``backend``.

        scheduling_method (str or list(str)):
            Optionally specify a particular scheduling method.

        init_qubits (bool): Whether to reset the qubits to the ground state for each shot.
                            Default: ``True``.

        run_config (dict):
            Extra arguments used to configure the run (e.g. for Aer configurable backends).
            Refer to the backend documentation for details on these arguments.
            Note: for now, these keyword arguments will both be copied to the
            Qobj config, and passed to backend.run()

    Returns:
        BaseJob: returns job instance derived from BaseJob

    Raises:
        QiskitError: if the execution cannot be interpreted as either circuits or schedules

    Example:
        Construct a 5-qubit GHZ circuit and execute 4321 shots on a backend.

        .. jupyter-execute::

            from qiskit import QuantumCircuit, execute, BasicAer

            backend = BasicAer.get_backend('qasm_simulator')

            qc = QuantumCircuit(5, 5)
            qc.h(0)
            qc.cx(0, range(1, 5))
            qc.measure_all()

            job = execute(qc, backend, shots=4321)
    """
    if isinstance(experiments,
                  Schedule) or (isinstance(experiments, list)
                                and isinstance(experiments[0], Schedule)):
        # do not transpile a schedule circuit
        if schedule_circuit:
            raise QiskitError(
                "Must supply QuantumCircuit to schedule circuit.")
    elif pass_manager is not None:
        # transpiling using pass_manager
        _check_conflicting_argument(optimization_level=optimization_level,
                                    basis_gates=basis_gates,
                                    coupling_map=coupling_map,
                                    seed_transpiler=seed_transpiler,
                                    backend_properties=backend_properties,
                                    initial_layout=initial_layout)
        experiments = pass_manager.run(experiments)
    else:
        # transpiling the circuits using given transpile options
        experiments = transpile(experiments,
                                basis_gates=basis_gates,
                                coupling_map=coupling_map,
                                backend_properties=backend_properties,
                                initial_layout=initial_layout,
                                seed_transpiler=seed_transpiler,
                                optimization_level=optimization_level,
                                backend=backend)

    if schedule_circuit:
        experiments = schedule(circuits=experiments,
                               backend=backend,
                               inst_map=inst_map,
                               meas_map=meas_map,
                               method=scheduling_method)

    if isinstance(backend, BaseBackend):
        # assembling the circuits into a qobj to be run on the backend
        qobj = assemble(experiments,
                        qobj_id=qobj_id,
                        qobj_header=qobj_header,
                        shots=shots,
                        memory=memory,
                        max_credits=max_credits,
                        seed_simulator=seed_simulator,
                        default_qubit_los=default_qubit_los,
                        default_meas_los=default_meas_los,
                        schedule_los=schedule_los,
                        meas_level=meas_level,
                        meas_return=meas_return,
                        memory_slots=memory_slots,
                        memory_slot_size=memory_slot_size,
                        rep_time=rep_time,
                        rep_delay=rep_delay,
                        parameter_binds=parameter_binds,
                        backend=backend,
                        init_qubits=init_qubits,
                        **run_config)

        # executing the circuits on the backend and returning the job
        start_time = time()
        job = backend.run(qobj, **run_config)
        end_time = time()
        _log_submission_time(start_time, end_time)
    elif isinstance(backend, Backend):
        start_time = time()
        job = backend.run(experiments,
                          shots=shots,
                          memory=memory,
                          seed_simulator=seed_simulator,
                          default_qubit_los=default_qubit_los,
                          default_meas_los=default_meas_los,
                          schedule_los=schedule_los,
                          meas_level=meas_level,
                          meas_return=meas_return,
                          memory_slots=memory_slots,
                          memory_slot_size=memory_slot_size,
                          rep_time=rep_time,
                          rep_delay=rep_delay,
                          parameter_binds=parameter_binds,
                          init_qubits=init_qubits,
                          **run_config)
        end_time = time()
        _log_submission_time(start_time, end_time)
    else:
        raise QiskitError("Invalid backend type %s" % type(backend))
    return job
Пример #4
0
    def __init__(self, data, input_dims=None, output_dims=None):
        """Initialize a quantum channel Superoperator operator.

        Args:
            data (QuantumCircuit or
                  Instruction or
                  BaseOperator or
                  matrix): data to initialize superoperator.
            input_dims (tuple): the input subsystem dimensions.
                                [Default: None]
            output_dims (tuple): the output subsystem dimensions.
                                 [Default: None]

        Raises:
            QiskitError: if input data cannot be initialized as a
                         superoperator.

        Additional Information:
            If the input or output dimensions are None, they will be
            automatically determined from the input data. If the input data is
            a Numpy array of shape (4**N, 4**N) qubit systems will be used. If
            the input operator is not an N-qubit operator, it will assign a
            single subsystem with dimension specified by the shape of the input.
        """
        # If the input is a raw list or matrix we assume that it is
        # already a superoperator.
        if isinstance(data, (list, np.ndarray)):
            # We initialize directly from superoperator matrix
            super_mat = np.asarray(data, dtype=complex)
            # Determine total input and output dimensions
            dout, din = super_mat.shape
            input_dim = int(np.sqrt(din))
            output_dim = int(np.sqrt(dout))
            if output_dim**2 != dout or input_dim**2 != din:
                raise QiskitError("Invalid shape for SuperOp matrix.")
            op_shape = OpShape.auto(dims_l=output_dims,
                                    dims_r=input_dims,
                                    shape=(output_dim, input_dim))
        else:
            # Otherwise we initialize by conversion from another Qiskit
            # object into the QuantumChannel.
            if isinstance(data, (QuantumCircuit, Instruction)):
                # If the input is a Terra QuantumCircuit or Instruction we
                # perform a simulation to construct the circuit superoperator.
                # This will only work if the circuit or instruction can be
                # defined in terms of instructions which have no classical
                # register components. The instructions can be gates, reset,
                # or Kraus instructions. Any conditional gates or measure
                # will cause an exception to be raised.
                data = self._init_instruction(data)
            else:
                # We use the QuantumChannel init transform to initialize
                # other objects into a QuantumChannel or Operator object.
                data = self._init_transformer(data)
            # Now that the input is an operator we convert it to a
            # SuperOp object
            op_shape = data._op_shape
            input_dim, output_dim = data.dim
            rep = getattr(data, '_channel_rep', 'Operator')
            super_mat = _to_superop(rep, data._data, input_dim, output_dim)
        # Initialize QuantumChannel
        super().__init__(super_mat, op_shape=op_shape)
Пример #5
0
    def normalize(single_inpt):
        if abs(single_inpt) < 1e-14:
            return '0'
        val = single_inpt / np.pi
        if output == 'text':
            pi = 'pi'
        elif output == 'latex':
            pi = '\\pi'
        elif output == 'mpl':
            pi = '$\\pi$'
        else:
            raise QiskitError(
                'pi_check parameter output should be text, latex, or mpl')
        if abs(val) >= 1 - eps:
            if abs(abs(val) - abs(round(val))) < eps:
                val = int(round(val))
                if val == 1:
                    str_out = '{}'.format(pi)
                elif val == -1:
                    str_out = '-{}'.format(pi)
                else:
                    str_out = '{}{}'.format(val, pi)
                return str_out

        val = np.pi / single_inpt
        if abs(abs(val) - abs(round(val))) < eps:
            val = int(round(val))
            if val > 0:
                if output == 'latex':
                    str_out = '\\frac{%s}{%s}' % (pi, abs(val))
                else:
                    str_out = '{}/{}'.format(pi, val)
            else:
                if output == 'latex':
                    str_out = '\\frac{-%s}{%s}' % (pi, abs(val))
                else:
                    str_out = '-{}/{}'.format(pi, abs(val))
            return str_out

        # Look for all fracs in 8
        abs_val = abs(single_inpt)
        frac = np.where(np.abs(abs_val - FRAC_MESH) < 1e-8)
        if frac[0].shape[0]:
            numer = int(frac[1][0]) + 1
            denom = int(frac[0][0]) + 1
            if single_inpt < 0:
                numer *= -1

            if numer == 1 and denom == 1:
                str_out = '{}'.format(pi)
            elif numer == -1 and denom == 1:
                str_out = '-{}'.format(pi)
            elif numer == 1:
                if output == 'latex':
                    str_out = '\\frac{%s}{%s}' % (pi, denom)
                else:
                    str_out = '{}/{}'.format(pi, denom)
            elif numer == -1:
                if output == 'latex':
                    str_out = '\\frac{-%s}{%s}' % (pi, denom)
                else:
                    str_out = '-{}/{}'.format(pi, denom)
            elif denom == 1:
                if output == 'latex':
                    str_out = '\\frac{%s}{%s}' % (numer, pi)
                else:
                    str_out = '{}/{}'.format(numer, pi)
            else:
                if output == 'latex':
                    str_out = '\\frac{%s%s}{%s}' % (numer, pi, denom)
                else:
                    str_out = '{}{}/{}'.format(numer, pi, denom)

            return str_out
        # nothing found
        str_out = '%.{}g'.format(ndigits) % single_inpt
        return str_out
Пример #6
0
def weyl_coordinates(U):
    """Computes the Weyl coordinates for
    a given two-qubit unitary matrix.

    Args:
        U (ndarray): Input two-qubit unitary.

    Returns:
        ndarray: Array of Weyl coordinates.

    Raises:
        QiskitError: Computed coordinates not in Weyl chamber.
    """
    pi2 = np.pi / 2
    pi4 = np.pi / 4

    U = U / la.det(U)**(0.25)
    Up = _Bd.dot(U).dot(_B)
    M2 = Up.T.dot(Up)

    # M2 is a symmetric complex matrix. We need to decompose it as M2 = P D P^T where
    # P ∈ SO(4), D is diagonal with unit-magnitude elements.
    # D, P = la.eig(M2)  # this can fail for certain kinds of degeneracy
    for _ in range(3):  # FIXME: this randomized algorithm is horrendous
        M2real = np.random.normal() * M2.real + np.random.normal() * M2.imag
        _, P = la.eigh(M2real)
        D = P.T.dot(M2).dot(P).diagonal()
        if np.allclose(P.dot(np.diag(D)).dot(P.T),
                       M2,
                       rtol=1.0e-10,
                       atol=1.0e-10):
            break
    else:
        raise QiskitError(
            "TwoQubitWeylDecomposition: failed to diagonalize M2. "
            "Please submit this output to "
            "https://github.com/Qiskit/qiskit-terra/issues/4159 "
            "Input %s" % U.tolist())

    d = -np.angle(D) / 2
    d[3] = -d[0] - d[1] - d[2]
    cs = np.mod((d[:3] + d[3]) / 2, 2 * np.pi)

    # Reorder the eigenvalues to get in the Weyl chamber
    cstemp = np.mod(cs, pi2)
    np.minimum(cstemp, pi2 - cstemp, cstemp)
    order = np.argsort(cstemp)[[1, 2, 0]]
    cs = cs[order]
    d[:3] = d[order]

    # Flip into Weyl chamber
    if cs[0] > pi2:
        cs[0] -= 3 * pi2
    if cs[1] > pi2:
        cs[1] -= 3 * pi2
    conjs = 0
    if cs[0] > pi4:
        cs[0] = pi2 - cs[0]
        conjs += 1
    if cs[1] > pi4:
        cs[1] = pi2 - cs[1]
        conjs += 1
    if cs[2] > pi2:
        cs[2] -= 3 * pi2
    if conjs == 1:
        cs[2] = pi2 - cs[2]
    if cs[2] > pi4:
        cs[2] -= pi2

    return cs[[1, 0, 2]]
Пример #7
0
 def add(self, gate):
     """Add instruction to set."""
     if not isinstance(gate, Instruction):
         raise QiskitError("attempt to add non-Instruction" +
                           " to InstructionSet")
     self.instructions.append(gate)
Пример #8
0
    def __init__(
        self,
        name: str,
        instructions: Optional[Sequence[Instruction]] = None,
        default_states: Optional[Sequence[Union[Statevector, DensityMatrix]]] = None,
        qubit_states: Optional[Dict[int, Sequence[Union[Statevector, DensityMatrix]]]] = None,
    ):
        """Initialize a fitter preparation basis.

        Args:
            name: a name to identity the basis.
            instructions: list of 1-qubit instructions for preparing states
                          from the :math:`|0^{\\otimes n}\\rangle` state.
            default_states: Optional, default density matrices prepared by the
                            input instructions. If None these will be determined by
                            ideal simulation of the preparation instructions.
            qubit_states: Optional, a dict with physical qubit keys and a list of
                          density matrices prepared by the list of basis instructions
                          for a specific qubit. The default states will be used for any
                          qubits not specified in this dict.

        Raises:
            QiskitError: if input states or instructions are not valid, or no
                         instructions or states are provided.
        """
        if instructions is None and default_states is None and qubit_states is None:
            raise QiskitError(
                "LocalPreparationBasis must define at least one of instructions, "
                "default_states, or qubit_states."
            )
        super().__init__(name)

        # Internal variables
        self._instructions = tuple()
        self._size = None
        self._default_states = None
        self._default_dim = None
        self._qubit_states = {}
        self._qubit_dim = {}
        self._qubits = set()
        self._custom_defaults = True

        # Format instructions so compatible types can be converted to
        # Instruction instances.
        if instructions is not None:
            self._instructions = _format_instructions(instructions)
            self._size = len(instructions)
            if default_states is None:
                default_states = self._instructions
                self._custom_defaults = False

        # Construct default states
        if default_states is not None:
            self._default_states = tuple(DensityMatrix(i).data for i in default_states)
            self._default_dim = self._default_states[0].shape[0]
            if self._size is None:
                self._size = len(self._default_states)
            elif len(self._default_states) != self._size:
                raise QiskitError(
                    "Number of instructions and number of default states must be equal."
                )

        # Construct states of specific qubits if provided
        qubit_states = qubit_states or {}
        for qubit, states in qubit_states.items():
            if self._size is None:
                self._size = len(states)
            elif len(states) != self._size:
                raise QiskitError("Number of instructions and number of states must be equal.")

            qstates = tuple(DensityMatrix(i).data for i in states)
            self._qubit_states[qubit] = qstates
            self._qubit_dim[qubit] = qstates[0].shape[0]
            self._qubits.add(qubit)

        # Pseudo hash value to make basis hashable for LRU cached functions
        self._hash = hash(
            (
                type(self),
                self._name,
                self._size,
                self._default_dim,
                self._custom_defaults,
                tuple(self._qubits),
                tuple(self._qubit_dim.values()),
                (type(i) for i in self._instructions),
            )
        )
Пример #9
0
def process_fidelity(channel, target=None, require_cp=True, require_tp=False):
    r"""Return the process fidelity of a noisy quantum channel.


    The process fidelity :math:`F_{\text{pro}}(\mathcal{E}, \methcal{F})`
    between two quantum channels :math:`\mathcal{E}, \mathcal{F}` is given by

    .. math:
        F_{\text{pro}}(\mathcal{E}, \mathcal{F})
            = F(\rho_{\mathcal{E}}, \rho_{\mathcal{F}})

    where :math:`F` is the :func:`~qiskit.quantum_info.state_fidelity`,
    :math:`\rho_{\mathcal{E}} = \Lambda_{\mathcal{E}} / d` is the
    normalized :class:`~qiskit.quantum_info.Choi` matrix for the channel
    :math:`\mathcal{E}`, and :math:`d` is the input dimension of
    :math:`\mathcal{E}`.

    When the target channel is unitary this is equivalent to

    .. math::
        F_{\text{pro}}(\mathcal{E}, U)
            = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2}

    where :math:`S_{\mathcal{E}}, S_{U}` are the
    :class:`~qiskit.quantum_info.SuperOp` matrices for the *input* quantum
    channel :math:`\mathcal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the input dimension of the channel.

    Args:
        channel (Operator or QuantumChannel): input quantum channel.
        target (Operator or QuantumChannel or None): target quantum channel.
            If `None` target is the identity operator [Default: None].
        require_cp (bool): require channel to be completely-positive
            [Default: True].
        require_tp (bool): require channel to be trace-preserving
            [Default: False].

    Returns:
        float: The process fidelity :math:`F_{\text{pro}}`.

    Raises:
        QiskitError: if the channel and target do not have the same dimensions.
        QiskitError: if the channel and target are not completely-positive
                     (with ``require_cp=True``) or not trace-preserving
                     (with ``require_tp=True``).
    """
    # Format inputs
    channel = _input_formatter(channel, SuperOp, 'process_fidelity', 'channel')
    target = _input_formatter(target, Operator, 'process_fidelity', 'target')

    if target:
        # Validate dimensions
        if channel.dim != target.dim:
            raise QiskitError(
                'Input quantum channel and target unitary must have the same '
                'dimensions ({} != {}).'.format(channel.dim, target.dim))

    # Validate complete-positivity and trace-preserving
    for label, chan in [('Input', channel), ('Target', target)]:
        if isinstance(chan, Operator) and (require_cp or require_tp):
            is_unitary = chan.is_unitary()
            # Validate as unitary
            if require_cp and not is_unitary:
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not is_unitary:
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))
        elif chan is not None:
            # Validate as QuantumChannel
            if require_cp and not chan.is_cp():
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not chan.is_tp():
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))

    if isinstance(target, Operator):
        # Compute fidelity with unitary target by applying the inverse
        # to channel and computing fidelity with the identity
        channel = channel @ target.adjoint()
        target = None

    input_dim, _ = channel.dim
    if target is None:
        # Compute process fidelity with identity channel
        if isinstance(channel, Operator):
            # |Tr[U]/dim| ** 2
            fid = np.abs(np.trace(channel.data) / input_dim)**2
        else:
            # Tr[S] / (dim ** 2)
            fid = np.trace(SuperOp(channel).data) / (input_dim**2)
        return float(np.real(fid))

    # For comparing two non-unitary channels we compute the state fidelity of
    # the normalized Choi-matrices. This is equivalent to the previous definition
    # when the target is a unitary channel.
    state1 = DensityMatrix(Choi(channel).data / input_dim)
    state2 = DensityMatrix(Choi(target).data / input_dim)
    return state_fidelity(state1, state2, validate=False)
Пример #10
0
 def op(self):
     """Returns the Instruction object corresponding to the op for the node else None"""
     if 'type' not in self.data_dict or self.data_dict['type'] != 'op':
         raise QiskitError("The node %s is not an op node" % (str(self)))
     return self.data_dict.get('op')
Пример #11
0
    def __init__(
        self,
        name: str,
        instructions: Optional[Sequence[Instruction]] = None,
        default_povms: Optional[Sequence[POVM]] = None,
        qubit_povms: Optional[Dict[int, Sequence[POVM]]] = None,
    ):
        """Initialize a fitter preparation basis.

        Args:
            name: a name to identity the basis.
            instructions: list of instructions for rotating a desired
                          measurement basis to the standard :math:`Z^{\\otimes n}`
                          computational basis measurement.
            default_povms: Optional, list if positive operators valued measures (POVM)
                           for of the measurement basis instructions. A POVM can be
                           input as a list of effects (Statevector or DensityMatrix)
                           for each possible measurement outcome of that basis, or as
                           a single QuantumChannel. For the channel case the effects
                           will be calculated by evolving the computation basis states
                           by the adjoint of the channel. If None the input instructions
                           will be used as the POVM channel.
            qubit_povms: Optional, a dict with physical qubit keys and a list of POVMs
                         corresponding to each basis measurement instruction for the
                         specific qubit. The default POVMs will be used for any qubits
                         not specified in this dict.

        Raises:
            QiskitError: if the input instructions or POVMs are not valid, or if no
                         instructions or POVMs are provided.
        """
        if instructions is None and default_povms is None and qubit_povms is None:
            raise QiskitError(
                "LocalMeasurementBasis must define at least one of instructions, "
                "default_povms, or qubit_povms."
            )
        super().__init__(name)

        # Internal variables
        self._instructions = tuple()
        self._size = None
        self._default_povms = None
        self._default_num_outcomes = None
        self._default_dim = None
        self._qubit_povms = {}
        self._qubit_num_outcomes = {}
        self._qubit_dim = {}
        self._qubits = set()
        self._custom_defaults = True

        # Format instructions so compatible types can be converted to
        # Instruction instances.
        if instructions is not None:
            self._instructions = _format_instructions(instructions)
            self._size = len(self._instructions)
            if default_povms is None:
                default_povms = instructions
                self._custom_defaults = False

        # Format default POVMs
        if default_povms is not None:
            self._default_povms = _format_povms(default_povms)
            self._default_num_outcomes = len(self._default_povms[0])
            self._default_dim = self._default_povms[0][0].shape[0]
            if self._size is None:
                self._size = len(self._default_povms)
            elif len(self._default_povms) != self._size:
                raise QiskitError("Number of instructions and number of states must be equal.")
            if any(len(povm) != self._default_num_outcomes for povm in self._default_povms):
                raise QiskitError(
                    "LocalMeasurementBasis default POVM elements must all have "
                    "the same number of outcomes."
                )

        # Format qubit POVMS
        qubit_povms = qubit_povms or {}
        for qubit, povms in qubit_povms.items():
            f_povms = _format_povms(povms)
            num_outcomes = len(f_povms[0])
            if any(len(povm) != num_outcomes for povm in f_povms):
                raise QiskitError(
                    "LocalMeasurementBasis POVM elements must all have the "
                    "same number of outcomes."
                )
            self._qubit_povms[qubit] = f_povms
            self._qubit_num_outcomes[qubit] = num_outcomes
            self._qubit_dim[qubit] = f_povms[0][0].shape[0]
            self._qubits.add(qubit)

        # Pseudo hash value to make basis hashable for LRU cached functions
        self._hash = hash(
            (
                type(self),
                self._name,
                self._size,
                self._default_dim,
                self._default_num_outcomes,
                self._custom_defaults,
                tuple(self._qubits),
                tuple(self._qubit_dim.values()),
                tuple(self._qubit_num_outcomes.values()),
                (type(i) for i in self._instructions),
            )
        )
Пример #12
0
    def from_labels(cls, labels):
        r"""Construct a StabilizerTable from a list of Pauli stabilizer strings.

        Pauli Stabilizer string labels are Pauli strings with an optional
        ``"+"`` or ``"-"`` character. If there is no +/-sign a + phase is
        used by default.

        .. list-table:: Stabilizer Representations
            :header-rows: 1

            * - Label
              - Phase
              - Symplectic
              - Matrix
              - Pauli
            * - ``"+I"``
              - 0
              - :math:`[0, 0]`
              - :math:`\begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}`
              - :math:`I`
            * - ``"-I"``
              - 1
              - :math:`[0, 0]`
              - :math:`\begin{bmatrix} -1 & 0 \\ 0 & -1 \end{bmatrix}`
              - :math:`-I`
            * - ``"X"``
              - 0
              - :math:`[1, 0]`
              - :math:`\begin{bmatrix} 0 & 1 \\ 1 & 0  \end{bmatrix}`
              - :math:`X`
            * - ``"-X"``
              - 1
              - :math:`[1, 0]`
              - :math:`\begin{bmatrix} 0 & -1 \\ -1 & 0  \end{bmatrix}`
              - :math:`-X`
            * - ``"Y"``
              - 0
              - :math:`[1, 1]`
              - :math:`\begin{bmatrix} 0 & 1 \\ -1 & 0  \end{bmatrix}`
              - :math:`iY`
            * - ``"-Y"``
              - 1
              - :math:`[1, 1]`
              - :math:`\begin{bmatrix} 0 & -1 \\ 1 & 0  \end{bmatrix}`
              - :math:`-iY`
            * - ``"Z"``
              - 0
              - :math:`[0, 1]`
              - :math:`\begin{bmatrix} 1 & 0 \\ 0 & -1  \end{bmatrix}`
              - :math:`Z`
            * - ``"-Z"``
              - 1
              - :math:`[0, 1]`
              - :math:`\begin{bmatrix} -1 & 0 \\ 0 & 1  \end{bmatrix}`
              - :math:`-Z`

        Args:
            labels (list): Pauli stabilizer string label(es).

        Returns:
            StabilizerTable: the constructed StabilizerTable.

        Raises:
            QiskitError: If the input list is empty or contains invalid
                         Pauli stabilizer strings.
        """
        if isinstance(labels, str):
            labels = [labels]
        n_paulis = len(labels)
        if n_paulis == 0:
            raise QiskitError("Input Pauli list is empty.")
        # Get size from first Pauli
        pauli, phase = cls._from_label(labels[0])
        table = np.zeros((n_paulis, len(pauli)), dtype=bool)
        phases = np.zeros(n_paulis, dtype=bool)
        table[0], phases[0] = pauli, phase
        for i in range(1, n_paulis):
            table[i], phases[i] = cls._from_label(labels[i])
        return cls(table, phases)
Пример #13
0
    def compose(self, other, qargs=None, front=False):
        """Return the compose output product of two tables.

        This returns the combination of the compose product of all
        stabilizers in the current table with all stabilizers in the
        other table.

        The individual stabilizer compose product is given by

        +----------------------+----+----+----+----+
        | :code:`A.compose(B)` |  I |  X |  Y |  Z |
        +======================+====+====+====+====+
        | **I**                |  I |  X |  Y |  Z |
        +----------------------+----+----+----+----+
        | **X**                |  X |  I |  Z | -Y |
        +----------------------+----+----+----+----+
        | **Y**                |  Y | -Z | -I |  X |
        +----------------------+----+----+----+----+
        | **Z**                |  Z |  Y | -X |  I |
        +----------------------+----+----+----+----+

        If `front=True` the composition will be given by the
        :meth:`dot` method.

        **Example**

        .. jupyter-execute::

            from qiskit.quantum_info.operators import StabilizerTable

            current = StabilizerTable.from_labels(['+I', '-X'])
            other =  StabilizerTable.from_labels(['+X', '-Z'])
            print(current.compose(other))

        Args:
            other (StabilizerTable): another StabilizerTable.
            qargs (None or list): qubits to apply compose product on
                                  (Default: None).
            front (bool): If True use `dot` composition method
                          (default: False).

        Returns:
            StabilizerTable: the compose outer product table.

        Raises:
            QiskitError: if other cannot be converted to a StabilizerTable.
        """
        if qargs is None:
            qargs = getattr(other, 'qargs', None)
        if not isinstance(other, StabilizerTable):
            other = StabilizerTable(other)
        if qargs is None and other.num_qubits != self.num_qubits:
            raise QiskitError(
                "other StabilizerTable must be on the same number of qubits.")
        if qargs and other.num_qubits != len(qargs):
            raise QiskitError(
                "Number of qubits in the other StabilizerTable does not match qargs."
            )

        # Stack X and Z blocks for output size
        x1, x2 = self._block_stack(self.X, other.X)
        z1, z2 = self._block_stack(self.Z, other.Z)
        phase1, phase2 = self._block_stack(self.phase, other.phase)

        if qargs is not None:
            ret_x, ret_z = x1.copy(), z1.copy()
            x1 = x1[:, qargs]
            z1 = z1[:, qargs]
            ret_x[:, qargs] = x1 ^ x2
            ret_z[:, qargs] = z1 ^ z2
            pauli = np.hstack([ret_x, ret_z])
        else:
            pauli = np.hstack((x1 ^ x2, z1 ^ z2))

        # We pick up a minus sign for products:
        # Y.Y = -I, X.Y = -Z, Y.Z = -X, Z.X = -Y
        if front:
            minus = (x1 & z2 & (x2 | z1)) | (~x1 & x2 & z1 & ~z2)
        else:
            minus = (x2 & z1 & (x1 | z2)) | (~x2 & x1 & z2 & ~z1)
        phase_shift = np.array(np.sum(minus, axis=1) % 2, dtype=bool)
        phase = phase_shift ^ phase1 ^ phase2
        return StabilizerTable(pauli, phase)
Пример #14
0
    def run(self, dag):
        """Run the Unroller pass on `dag`.

        Args:
            dag (DAGCircuit): input dag

        Raises:
            QiskitError: if unable to unroll given the basis due to undefined
            decomposition rules (such as a bad basis) or excessive recursion.

        Returns:
            DAGCircuit: output unrolled dag
        """
        if self.basis is None:
            return dag
        # Walk through the DAG and expand each non-basis node
        basic_insts = ['measure', 'reset', 'barrier', 'snapshot', 'delay']
        for node in dag.op_nodes():
            if node.op._directive:
                continue

            if node.name in basic_insts:
                # TODO: this is legacy behavior.Basis_insts should be removed that these
                #  instructions should be part of the device-reported basis. Currently, no
                #  backend reports "measure", for example.
                continue

            if node.name in self.basis:  # If already a base, ignore.
                if isinstance(node.op, ControlledGate) and node.op._open_ctrl:
                    pass
                else:
                    continue

            # TODO: allow choosing other possible decompositions
            try:
                phase = node.op.definition.global_phase
                rule = node.op.definition.data
            except (TypeError, AttributeError) as err:
                raise QiskitError(f'Error decomposing node of instruction \'{node.name}\': '
                                  f'{err}. Unable to define instruction \'{node.name}\' in the'
                                  f' given basis.') from err

            # Isometry gates definitions can have widths smaller than that of the
            # original gate, in which case substitute_node will raise. Fall back
            # to substitute_node_with_dag if an the width of the definition is
            # different that the width of the node.
            while rule and len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1:
                if rule[0][0].name in self.basis:
                    dag.global_phase += phase
                    dag.substitute_node(node, rule[0][0], inplace=True)
                    break
                try:
                    phase += rule[0][0].definition.global_phase
                    rule = rule[0][0].definition.data
                except (TypeError, AttributeError) as err:
                    raise QiskitError(f'Error decomposing node of instruction \'{node.name}\': '
                                      f'{err}. Unable to define instruction \'{rule[0][0].name}\''
                                      f' in the given basis.') from err

            else:
                if not rule:
                    if rule == []:  # empty node
                        dag.remove_op_node(node)
                        dag.global_phase += phase
                        continue
                    # opaque node
                    raise QiskitError("Cannot unroll the circuit to the given basis, %s. "
                                      "No rule to expand instruction %s." %
                                      (str(self.basis), node.op.name))
                decomposition = circuit_to_dag(node.op.definition)
                unrolled_dag = self.run(decomposition)  # recursively unroll ops
                dag.substitute_node_with_dag(node, unrolled_dag)
        return dag
Пример #15
0
 def op(self):
     """Returns the Instruction object corresponding to the op for the node, else None"""
     if not self.type or self.type != 'op':
         raise QiskitError("The node %s is not an op node" % (str(self)))
     return self._op
Пример #16
0
def plot_circuit_layout(circuit, backend, view='virtual'):
    """Plot the layout of a circuit transpiled for a given
    target backend.

    Args:
        circuit (QuantumCircuit): Input quantum circuit.
        backend (BaseBackend): Target backend.
        view (str): Layout view: either 'virtual' or 'physical'.

    Returns:
        Figure: A matplotlib figure showing layout.

    Raises:
        QiskitError: Invalid view type given.
        VisualizationError: Circuit has no layout attribute.

    Example:
        .. jupyter-execute::
            :hide-code:
            :hide-output:

            from qiskit.test.ibmq_mock import mock_get_backend
            mock_get_backend('FakeVigo')

        .. jupyter-execute::

            import numpy as np
            from qiskit import QuantumCircuit, IBMQ, transpile
            from qiskit.visualization import plot_histogram, plot_gate_map, plot_circuit_layout
            from qiskit.tools.monitor import job_monitor
            import matplotlib.pyplot as plt
            %matplotlib inline

            IBMQ.load_account()

            ghz = QuantumCircuit(3, 3)
            ghz.h(0)
            for idx in range(1,3):
                ghz.cx(0,idx)
            ghz.measure(range(3), range(3))

            provider = IBMQ.get_provider(hub='ibm-q')
            backend = provider.get_backend('ibmq_vigo')
            new_circ_lv3 = transpile(ghz, backend=backend, optimization_level=3)
            plot_circuit_layout(new_circ_lv3, backend)
    """
    if circuit._layout is None:
        raise QiskitError('Circuit has no layout. '
                          'Perhaps it has not been transpiled.')

    n_qubits = backend.configuration().n_qubits

    qubits = []
    qubit_labels = [None] * n_qubits

    if view == 'virtual':
        for key, val in circuit._layout.get_virtual_bits().items():
            if key.register.name != 'ancilla':
                qubits.append(val)
                qubit_labels[val] = key.index

    elif view == 'physical':
        for key, val in circuit._layout.get_physical_bits().items():
            if val.register.name != 'ancilla':
                qubits.append(key)
                qubit_labels[key] = key

    else:
        raise VisualizationError("Layout view must be 'virtual' or 'physical'.")

    qcolors = ['#648fff'] * n_qubits
    for k in qubits:
        qcolors[k] = 'k'

    cmap = backend.configuration().coupling_map

    lcolors = ['#648fff'] * len(cmap)

    for idx, edge in enumerate(cmap):
        if edge[0] in qubits and edge[1] in qubits:
            lcolors[idx] = 'k'

    fig = plot_gate_map(backend,
                        qubit_color=qcolors,
                        qubit_labels=qubit_labels,
                        line_color=lcolors)
    return fig
def _assemble_circuit(
    circuit: QuantumCircuit, run_config: RunConfig
) -> Tuple[QasmQobjExperiment, Optional[PulseLibrary]]:
    """Assemble one circuit.

    Args:
        circuit: circuit to assemble
        run_config: configuration of the runtime environment

    Returns:
        One experiment for the QasmQobj, and pulse library for pulse gates (which could be None)

    Raises:
        QiskitError: when the circuit has unit other than 'dt'.
    """
    if circuit.unit != "dt":
        raise QiskitError(
            f"Unable to assemble circuit with unit '{circuit.unit}', which must be 'dt'."
        )

    # header data
    num_qubits = 0
    memory_slots = 0
    qubit_labels = []
    clbit_labels = []

    qreg_sizes = []
    creg_sizes = []
    for qreg in circuit.qregs:
        qreg_sizes.append([qreg.name, qreg.size])
        for j in range(qreg.size):
            qubit_labels.append([qreg.name, j])
        num_qubits += qreg.size
    for creg in circuit.cregs:
        creg_sizes.append([creg.name, creg.size])
        for j in range(creg.size):
            clbit_labels.append([creg.name, j])
        memory_slots += creg.size

    qubit_indices = {qubit: idx for idx, qubit in enumerate(circuit.qubits)}
    clbit_indices = {clbit: idx for idx, clbit in enumerate(circuit.clbits)}

    # TODO: why do we need creq_sizes and qreg_sizes in header
    # TODO: we need to rethink memory_slots as they are tied to classical bit
    metadata = circuit.metadata
    if metadata is None:
        metadata = {}
    header = QobjExperimentHeader(
        qubit_labels=qubit_labels,
        n_qubits=num_qubits,
        qreg_sizes=qreg_sizes,
        clbit_labels=clbit_labels,
        memory_slots=memory_slots,
        creg_sizes=creg_sizes,
        name=circuit.name,
        global_phase=float(circuit.global_phase),
        metadata=metadata,
    )

    # TODO: why do we need n_qubits and memory_slots in both the header and the config
    config = QasmQobjExperimentConfig(n_qubits=num_qubits, memory_slots=memory_slots)
    calibrations, pulse_library = _assemble_pulse_gates(circuit, run_config)
    if calibrations:
        config.calibrations = calibrations

    # Convert conditionals from QASM-style (creg ?= int) to qobj-style
    # (register_bit ?= 1), by assuming device has unlimited register slots
    # (supported only for simulators). Map all measures to a register matching
    # their clbit_index, create a new register slot for every conditional gate
    # and add a bfunc to map the creg=val mask onto the gating register bit.

    is_conditional_experiment = any(
        getattr(instruction.operation, "condition", None) for instruction in circuit.data
    )
    max_conditional_idx = 0

    instructions = []
    for op_context in circuit.data:
        instruction = op_context.operation.assemble()

        # Add register attributes to the instruction
        qargs = op_context.qubits
        cargs = op_context.clbits
        if qargs:
            instruction.qubits = [qubit_indices[qubit] for qubit in qargs]
        if cargs:
            instruction.memory = [clbit_indices[clbit] for clbit in cargs]
            # If the experiment has conditional instructions, assume every
            # measurement result may be needed for a conditional gate.
            if instruction.name == "measure" and is_conditional_experiment:
                instruction.register = [clbit_indices[clbit] for clbit in cargs]

        # To convert to a qobj-style conditional, insert a bfunc prior
        # to the conditional instruction to map the creg ?= val condition
        # onto a gating register bit.
        if hasattr(instruction, "_condition"):
            ctrl_reg, ctrl_val = instruction._condition
            mask = 0
            val = 0
            if isinstance(ctrl_reg, Clbit):
                mask = 1 << clbit_indices[ctrl_reg]
                val = (ctrl_val & 1) << clbit_indices[ctrl_reg]
            else:
                for clbit in clbit_indices:
                    if clbit in ctrl_reg:
                        mask |= 1 << clbit_indices[clbit]
                        val |= ((ctrl_val >> list(ctrl_reg).index(clbit)) & 1) << clbit_indices[
                            clbit
                        ]

            conditional_reg_idx = memory_slots + max_conditional_idx
            conversion_bfunc = QasmQobjInstruction(
                name="bfunc",
                mask="0x%X" % mask,
                relation="==",
                val="0x%X" % val,
                register=conditional_reg_idx,
            )
            instructions.append(conversion_bfunc)
            instruction.conditional = conditional_reg_idx
            max_conditional_idx += 1
            # Delete condition attribute now that we have replaced it with
            # the conditional and bfunc
            del instruction._condition

        instructions.append(instruction)
    return (
        QasmQobjExperiment(instructions=instructions, header=header, config=config),
        pulse_library,
    )
Пример #18
0
def plot_gate_map(backend, figsize=None,
                  plot_directed=False,
                  label_qubits=True,
                  qubit_size=24,
                  line_width=4,
                  font_size=12,
                  qubit_color=None,
                  qubit_labels=None,
                  line_color=None,
                  font_color='w',
                  ax=None):
    """Plots the gate map of a device.

    Args:
        backend (BaseBackend): A backend instance,
        figsize (tuple): Output figure size (wxh) in inches.
        plot_directed (bool): Plot directed coupling map.
        label_qubits (bool): Label the qubits.
        qubit_size (float): Size of qubit marker.
        line_width (float): Width of lines.
        font_size (int): Font size of qubit labels.
        qubit_color (list): A list of colors for the qubits
        qubit_labels (list): A list of qubit labels
        line_color (list): A list of colors for each line from coupling_map.
        font_color (str): The font color for the qubit labels.
        ax (Axes): A Matplotlib axes instance.

    Returns:
        Figure: A Matplotlib figure instance.

    Raises:
        QiskitError: if tried to pass a simulator.
        ImportError: if matplotlib not installed.

    Example:
        .. jupyter-execute::
            :hide-code:
            :hide-output:

            from qiskit.test.ibmq_mock import mock_get_backend
            mock_get_backend('FakeVigo')

        .. jupyter-execute::

           from qiskit import QuantumCircuit, execute, IBMQ
           from qiskit.visualization import plot_gate_map
           %matplotlib inline

           provider = IBMQ.load_account()
           accountProvider = IBMQ.get_provider(hub='ibm-q')
           backend = accountProvider.get_backend('ibmq_vigo')
           plot_gate_map(backend)
    """
    if not HAS_MATPLOTLIB:
        raise ImportError('Must have Matplotlib installed.')

    if backend.configuration().simulator:
        raise QiskitError('Requires a device backend, not simulator.')

    input_axes = False
    if ax:
        input_axes = True

    mpl_data = {}

    mpl_data[1] = [[0, 0]]

    mpl_data[20] = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4],
                    [1, 0], [1, 1], [1, 2], [1, 3], [1, 4],
                    [2, 0], [2, 1], [2, 2], [2, 3], [2, 4],
                    [3, 0], [3, 1], [3, 2], [3, 3], [3, 4]]

    mpl_data[15] = [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4],
                    [0, 5], [0, 6], [1, 7], [1, 6], [1, 5],
                    [1, 4], [1, 3], [1, 2], [1, 1], [1, 0]]

    mpl_data[16] = [[1, 0], [0, 0], [0, 1], [0, 2], [0, 3],
                    [0, 4], [0, 5], [0, 6], [0, 7], [1, 7],
                    [1, 6], [1, 5], [1, 4], [1, 3], [1, 2], [1, 1]]

    mpl_data[5] = [[1, 0], [0, 1], [1, 1], [1, 2], [2, 1]]

    mpl_data[28] = [[0, 2], [0, 3], [0, 4], [0, 5], [0, 6],
                    [1, 2], [1, 6],
                    [2, 0], [2, 1], [2, 2], [2, 3], [2, 4],
                    [2, 5], [2, 6], [2, 7], [2, 8],
                    [3, 0], [3, 4], [3, 8],
                    [4, 0], [4, 1], [4, 2], [4, 3], [4, 4],
                    [4, 5], [4, 6], [4, 7], [4, 8]]

    mpl_data[53] = [[0, 2], [0, 3], [0, 4], [0, 5], [0, 6],
                    [1, 2], [1, 6],
                    [2, 0], [2, 1], [2, 2], [2, 3], [2, 4],
                    [2, 5], [2, 6], [2, 7], [2, 8],
                    [3, 0], [3, 4], [3, 8],
                    [4, 0], [4, 1], [4, 2], [4, 3], [4, 4],
                    [4, 5], [4, 6], [4, 7], [4, 8],
                    [5, 2], [5, 6],
                    [6, 0], [6, 1], [6, 2], [6, 3], [6, 4],
                    [6, 5], [6, 6], [6, 7], [6, 8],
                    [7, 0], [7, 4], [7, 8],
                    [8, 0], [8, 1], [8, 2], [8, 3], [8, 4],
                    [8, 5], [8, 6], [8, 7], [8, 8],
                    [9, 2], [9, 6]]

    config = backend.configuration()
    n_qubits = config.n_qubits
    cmap = config.coupling_map

    if qubit_labels is None:
        qubit_labels = list(range(n_qubits))
    else:
        if len(qubit_labels) != n_qubits:
            raise QiskitError('Length of qubit labels '
                              'does not equal number '
                              'of qubits.')

    if n_qubits in mpl_data.keys():
        grid_data = mpl_data[n_qubits]
    else:
        if not input_axes:
            fig, ax = plt.subplots(figsize=(5, 5))  # pylint: disable=invalid-name
            ax.axis('off')
            return fig

    x_max = max([d[1] for d in grid_data])
    y_max = max([d[0] for d in grid_data])
    max_dim = max(x_max, y_max)

    if figsize is None:
        if n_qubits == 1 or (x_max / max_dim > 0.33 and y_max / max_dim > 0.33):
            figsize = (5, 5)
        else:
            figsize = (9, 3)

    if ax is None:
        fig, ax = plt.subplots(figsize=figsize)  # pylint: disable=invalid-name
        ax.axis('off')

    # set coloring
    if qubit_color is None:
        qubit_color = ['#648fff'] * config.n_qubits
    if line_color is None:
        line_color = ['#648fff'] * len(cmap) if cmap else []

    # Add lines for couplings
    if n_qubits != 1:
        for ind, edge in enumerate(cmap):
            is_symmetric = False
            if edge[::-1] in cmap:
                is_symmetric = True
            y_start = grid_data[edge[0]][0]
            x_start = grid_data[edge[0]][1]
            y_end = grid_data[edge[1]][0]
            x_end = grid_data[edge[1]][1]

            if is_symmetric:
                if y_start == y_end:
                    x_end = (x_end - x_start) / 2 + x_start

                elif x_start == x_end:
                    y_end = (y_end - y_start) / 2 + y_start

                else:
                    x_end = (x_end - x_start) / 2 + x_start
                    y_end = (y_end - y_start) / 2 + y_start
            ax.add_artist(plt.Line2D([x_start, x_end], [-y_start, -y_end],
                                     color=line_color[ind], linewidth=line_width,
                                     zorder=0))
            if plot_directed:
                dx = x_end - x_start  # pylint: disable=invalid-name
                dy = y_end - y_start  # pylint: disable=invalid-name
                if is_symmetric:
                    x_arrow = x_start + dx * 0.95
                    y_arrow = -y_start - dy * 0.95
                    dx_arrow = dx * 0.01
                    dy_arrow = -dy * 0.01
                    head_width = 0.15
                else:
                    x_arrow = x_start + dx * 0.5
                    y_arrow = -y_start - dy * 0.5
                    dx_arrow = dx * 0.2
                    dy_arrow = -dy * 0.2
                    head_width = 0.2
                ax.add_patch(mpatches.FancyArrow(x_arrow,
                                                 y_arrow,
                                                 dx_arrow,
                                                 dy_arrow,
                                                 head_width=head_width,
                                                 length_includes_head=True,
                                                 edgecolor=None,
                                                 linewidth=0,
                                                 facecolor=line_color[ind],
                                                 zorder=1))

    # Add circles for qubits
    for var, idx in enumerate(grid_data):
        _idx = [idx[1], -idx[0]]
        width = _GraphDist(qubit_size, ax, True)
        height = _GraphDist(qubit_size, ax, False)
        ax.add_artist(mpatches.Ellipse(
            _idx, width, height, color=qubit_color[var], zorder=1))
        if label_qubits:
            ax.text(*_idx, s=qubit_labels[var],
                    horizontalalignment='center',
                    verticalalignment='center',
                    color=font_color, size=font_size, weight='bold')
    ax.set_xlim([-1, x_max + 1])
    ax.set_ylim([-(y_max + 1), 1])
    if not input_axes:
        if get_backend() in ['module://ipykernel.pylab.backend_inline',
                             'nbAgg']:
            plt.close(fig)
        return fig
    return None
Пример #19
0
    def from_label(cls, label):
        """Return a tensor product of Pauli X,Y,Z eigenstates.

        .. list-table:: Single-qubit state labels
           :header-rows: 1

           * - Label
             - Statevector
           * - ``"0"``
             - :math:`[1, 0]`
           * - ``"1"``
             - :math:`[0, 1]`
           * - ``"+"``
             - :math:`[1 / \\sqrt{2},  1 / \\sqrt{2}]`
           * - ``"-"``
             - :math:`[1 / \\sqrt{2},  -1 / \\sqrt{2}]`
           * - ``"r"``
             - :math:`[1 / \\sqrt{2},  i / \\sqrt{2}]`
           * - ``"l"``
             - :math:`[1 / \\sqrt{2},  -i / \\sqrt{2}]`

        Args:
            label (string): a eigenstate string ket label (see table for
                            allowed values).

        Returns:
            Statevector: The N-qubit basis state density matrix.

        Raises:
            QiskitError: if the label contains invalid characters, or the
                         length of the label is larger than an explicitly
                         specified num_qubits.
        """
        # Check label is valid
        if re.match(r'^[01rl\-+]+$', label) is None:
            raise QiskitError('Label contains invalid characters.')
        # We can prepare Z-eigenstates by converting the computational
        # basis bit-string to an integer and preparing that unit vector
        # However, for X-basis states, we will prepare a Z-eigenstate first
        # then apply Hadamard gates to rotate 0 and 1s to + and -.
        z_label = label
        xy_states = False
        if re.match('^[01]+$', label) is None:
            # We have X or Y eigenstates so replace +,r with 0 and
            # -,l with 1 and prepare the corresponding Z state
            xy_states = True
            z_label = z_label.replace('+', '0')
            z_label = z_label.replace('r', '0')
            z_label = z_label.replace('-', '1')
            z_label = z_label.replace('l', '1')
        # Initialize Z eigenstate vector
        num_qubits = len(label)
        data = np.zeros(1 << num_qubits, dtype=complex)
        pos = int(z_label, 2)
        data[pos] = 1
        state = Statevector(data)
        if xy_states:
            # Apply hadamards to all qubits in X eigenstates
            x_mat = np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2)
            # Apply S.H to qubits in Y eigenstates
            y_mat = np.dot(np.diag([1, 1j]), x_mat)
            for qubit, char in enumerate(reversed(label)):
                if char in ['+', '-']:
                    state = state.evolve(x_mat, qargs=[qubit])
                elif char in ['r', 'l']:
                    state = state.evolve(y_mat, qargs=[qubit])
        return state
Пример #20
0
def _assemble_experiments(
        schedules: List[pulse.Schedule],
        lo_converter: converters.LoConfigConverter,
        run_config: RunConfig
) -> Tuple[List[qobj.PulseQobjExperiment], Dict[str, Any]]:
    """Assembles a list of schedules into PulseQobjExperiments, and returns related metadata that
    will be assembled into the Qobj configuration.

    Args:
        schedules: Schedules to assemble.
        lo_converter: The configured frequency converter and validator.
        run_config: Configuration of the runtime environment.

    Returns:
        The list of assembled experiments, and the dictionary of related experiment config.

    Raises:
        QiskitError: when frequency settings are not compatible with the experiments.
    """
    freq_configs = [lo_converter(lo_dict) for lo_dict in getattr(run_config, 'schedule_los', [])]

    if len(schedules) > 1 and len(freq_configs) not in [0, 1, len(schedules)]:
        raise QiskitError('Invalid frequency setting is specified. If the frequency is specified, '
                          'it should be configured the same for all schedules, configured for each '
                          'schedule, or a list of frequencies should be provided for a single '
                          'frequency sweep schedule.')

    instruction_converter = getattr(run_config,
                                    'instruction_converter',
                                    converters.InstructionToQobjConverter)
    instruction_converter = instruction_converter(qobj.PulseQobjInstruction,
                                                  **run_config.to_dict())

    schedules = [
        sched if isinstance(sched, pulse.Schedule) else pulse.Schedule(sched) for sched in schedules
    ]
    compressed_schedules = transforms.compress_pulses(schedules)

    user_pulselib = {}
    experiments = []
    for idx, schedule in enumerate(compressed_schedules):
        qobj_instructions, max_memory_slot = _assemble_instructions(
            schedule,
            instruction_converter,
            run_config,
            user_pulselib)

        # TODO: add other experimental header items (see circuit assembler)
        qobj_experiment_header = qobj.QobjExperimentHeader(
            memory_slots=max_memory_slot + 1,  # Memory slots are 0 indexed
            name=schedule.name or 'Experiment-%d' % idx)

        experiment = qobj.PulseQobjExperiment(
            header=qobj_experiment_header,
            instructions=qobj_instructions)
        if freq_configs:
            # This handles the cases where one frequency setting applies to all experiments and
            # where each experiment has a different frequency
            freq_idx = idx if len(freq_configs) != 1 else 0
            experiment.config = freq_configs[freq_idx]

        experiments.append(experiment)

    # Frequency sweep
    if freq_configs and len(experiments) == 1:
        experiment = experiments[0]
        experiments = []
        for freq_config in freq_configs:
            experiments.append(qobj.PulseQobjExperiment(
                header=experiment.header,
                instructions=experiment.instructions,
                config=freq_config))

    # Top level Qobj configuration
    experiment_config = {
        'pulse_library': [qobj.PulseLibraryItem(name=name, samples=samples)
                          for name, samples in user_pulselib.items()],
        'memory_slots': max([exp.header.memory_slots for exp in experiments])
    }

    return experiments, experiment_config
Пример #21
0
def circuit_to_gate(circuit, parameter_map=None):
    """Build a ``Gate`` object from a ``QuantumCircuit``.

    The gate is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The gate will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the gate.
           If None, existing circuit parameters will also parameterize the
           Gate.

    Raises:
        QiskitError: if circuit is non-unitary or if
            parameter_map is not compatible with circuit

    Return:
        Gate: a Gate equivalent to the action of the
        input circuit. Upon decomposition, this gate will
        yield the components comprising the original circuit.
    """
    if circuit.clbits:
        raise QiskitError('Circuit with classical bits cannot be converted '
                          'to gate.')

    for inst, _, _ in circuit.data:
        if not isinstance(inst, Gate):
            raise QiskitError('One or more instructions in this instruction '
                              'cannot be converted to a gate')

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(('parameter_map should map all circuit parameters. '
                           'Circuit parameters: {}, parameter_map: {}').format(
                               circuit.parameters, parameter_dict))

    gate = Gate(name=circuit.name,
                num_qubits=sum([qreg.size for qreg in circuit.qregs]),
                params=sorted(parameter_dict.values(), key=lambda p: p.name))
    gate.condition = None

    def find_bit_position(bit):
        """find the index of a given bit (Register, int) within
        a flat ordered list of bits of the circuit
        """
        if isinstance(bit, Qubit):
            ordered_regs = circuit.qregs
        else:
            ordered_regs = circuit.cregs
        reg_index = ordered_regs.index(bit.register)
        return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index

    target = circuit.copy()
    target._substitute_parameters(parameter_dict)

    definition = target.data

    if gate.num_qubits > 0:
        q = QuantumRegister(gate.num_qubits, 'q')

    # The 3rd parameter in the output tuple) is hard coded to [] because
    # Gate objects do not have cregs set and we've verified that all
    # instructions are gates
    definition = list(
        map(
            lambda x:
            (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])), []),
            definition))
    gate.definition = definition

    return gate
Пример #22
0
    def __init__(self, data, dims=None):
        """Initialize a density matrix object.

        Args:
            data (np.ndarray or list or matrix_like or QuantumCircuit or
                  qiskit.circuit.Instruction):
                A statevector, quantum instruction or an object with a ``to_operator`` or
                ``to_matrix`` method from which the density matrix can be constructed.
                If a vector the density matrix is constructed as the projector of that vector.
                If a quantum instruction, the density matrix is constructed by assuming all
                qubits are initialized in the zero state.
            dims (int or tuple or list): Optional. The subsystem dimension
                    of the state (See additional information).

        Raises:
            QiskitError: if input data is not valid.

        Additional Information:
            The ``dims`` kwarg can be None, an integer, or an iterable of
            integers.

            * ``Iterable`` -- the subsystem dimensions are the values in the list
              with the total number of subsystems given by the length of the list.

            * ``Int`` or ``None`` -- the leading dimension of the input matrix
              specifies the total dimension of the density matrix. If it is a
              power of two the state will be initialized as an N-qubit state.
              If it is not a power of two the state will have a single
              d-dimensional subsystem.
        """
        if isinstance(data, (list, np.ndarray)):
            # Finally we check if the input is a raw matrix in either a
            # python list or numpy array format.
            self._data = np.asarray(data, dtype=complex)
        elif isinstance(data, (QuantumCircuit, Instruction)):
            # If the data is a circuit or an instruction use the classmethod
            # to construct the DensityMatrix object
            self._data = DensityMatrix.from_instruction(data)._data
        elif hasattr(data, 'to_operator'):
            # If the data object has a 'to_operator' attribute this is given
            # higher preference than the 'to_matrix' method for initializing
            # an Operator object.
            op = data.to_operator()
            self._data = op.data
            if dims is None:
                dims = op.output_dims()
        elif hasattr(data, 'to_matrix'):
            # If no 'to_operator' attribute exists we next look for a
            # 'to_matrix' attribute to a matrix that will be cast into
            # a complex numpy matrix.
            self._data = np.asarray(data.to_matrix(), dtype=complex)
        else:
            raise QiskitError("Invalid input data format for DensityMatrix")
        # Convert statevector into a density matrix
        ndim = self._data.ndim
        shape = self._data.shape
        if ndim == 2 and shape[0] == shape[1]:
            pass  # We good
        elif ndim == 1:
            self._data = np.outer(self._data, np.conj(self._data))
        elif ndim == 2 and shape[1] == 1:
            self._data = np.reshape(self._data, shape[0])
        else:
            raise QiskitError(
                "Invalid DensityMatrix input: not a square matrix.")
        super().__init__(op_shape=OpShape.auto(
            shape=self._data.shape, dims_l=dims, dims_r=dims))
Пример #23
0
def circuit_to_gate(circuit,
                    parameter_map=None,
                    equivalence_library=None,
                    label=None):
    """Build a :class:`.Gate` object from a :class:`.QuantumCircuit`.

    The gate is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The gate will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the gate.
           If None, existing circuit parameters will also parameterize the
           Gate.
        equivalence_library (EquivalenceLibrary): Optional equivalence library
           where the converted gate will be registered.
        label (str): Optional gate label.

    Raises:
        QiskitError: if circuit is non-unitary or if
            parameter_map is not compatible with circuit

    Return:
        Gate: a Gate equivalent to the action of the
        input circuit. Upon decomposition, this gate will
        yield the components comprising the original circuit.
    """
    # pylint: disable=cyclic-import
    from qiskit.circuit.quantumcircuit import QuantumCircuit

    if circuit.clbits:
        raise QiskitError(
            "Circuit with classical bits cannot be converted to gate.")

    for inst, _, _ in circuit.data:
        if not isinstance(inst, Gate):
            raise QiskitError(
                ("One or more instructions cannot be converted to"
                 ' a gate. "{}" is not a gate instruction').format(inst.name))

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(("parameter_map should map all circuit parameters. "
                           "Circuit parameters: {}, parameter_map: {}").format(
                               circuit.parameters, parameter_dict))

    gate = Gate(
        name=circuit.name,
        num_qubits=circuit.num_qubits,
        params=[*parameter_dict.values()],
        label=label,
    )
    gate.condition = None

    target = circuit.assign_parameters(parameter_dict, inplace=False)

    if equivalence_library is not None:
        equivalence_library.add_equivalence(gate, target)

    rules = target.data

    if gate.num_qubits > 0:
        q = QuantumRegister(gate.num_qubits, "q")

    qubit_map = {bit: q[idx] for idx, bit in enumerate(circuit.qubits)}

    # The 3rd parameter in the output tuple) is hard coded to [] because
    # Gate objects do not have cregs set and we've verified that all
    # instructions are gates
    rules = [(inst, [qubit_map[y] for y in qargs], [])
             for inst, qargs, _ in rules]
    qc = QuantumCircuit(q, name=gate.name, global_phase=target.global_phase)
    for instr, qargs, cargs in rules:
        qc._append(instr, qargs, cargs)
    gate.definition = qc
    return gate
Пример #24
0
    def _append_circuit(self, circuit, qargs=None):
        """Update BasePauli inplace by applying a Clifford circuit.

        Args:
            circuit (QuantumCircuit or Instruction): the gate or composite gate to apply.
            qargs (list or None): The qubits to apply gate to.

        Returns:
            BasePauli: the updated Pauli.

        Raises:
            QiskitError: if input gate cannot be decomposed into Clifford gates.
        """
        if isinstance(circuit, Barrier):
            return self

        if qargs is None:
            qargs = list(range(self.num_qubits))

        if isinstance(circuit, QuantumCircuit):
            gate = circuit.to_instruction()
        else:
            gate = circuit

        # Basis Clifford Gates
        basis_1q = {
            'i': _evolve_i,
            'id': _evolve_i,
            'iden': _evolve_i,
            'x': _evolve_x,
            'y': _evolve_y,
            'z': _evolve_z,
            'h': _evolve_h,
            's': _evolve_s,
            'sdg': _evolve_sdg,
            'sinv': _evolve_sdg
        }
        basis_2q = {
            'cx': _evolve_cx,
            'cz': _evolve_cz,
            'cy': _evolve_cy,
            'swap': _evolve_swap
        }

        # Non-Clifford gates
        non_clifford = ['t', 'tdg', 'ccx', 'ccz']

        if isinstance(gate, str):
            # Check if gate is a valid Clifford basis gate string
            if gate not in basis_1q and gate not in basis_2q:
                raise QiskitError(
                    "Invalid Clifford gate name string {}".format(gate))
            name = gate
        else:
            # Assume gate is an Instruction
            name = gate.name

        # Apply gate if it is a Clifford basis gate
        if name in non_clifford:
            raise QiskitError(
                "Cannot update Pauli with non-Clifford gate {}".format(name))
        if name in basis_1q:
            if len(qargs) != 1:
                raise QiskitError("Invalid qubits for 1-qubit gate.")
            return basis_1q[name](self, qargs[0])
        if name in basis_2q:
            if len(qargs) != 2:
                raise QiskitError("Invalid qubits for 2-qubit gate.")
            return basis_2q[name](self, qargs[0], qargs[1])

        # If not a Clifford basis gate we try to unroll the gate and
        # raise an exception if unrolling reaches a non-Clifford gate.
        if gate.definition is None:
            raise QiskitError('Cannot apply Instruction: {}'.format(gate.name))
        if not isinstance(gate.definition, QuantumCircuit):
            raise QiskitError(
                '{} instruction definition is {}; expected QuantumCircuit'.
                format(gate.name, type(gate.definition)))

        flat_instr = gate.definition
        bit_indices = {
            bit: index
            for bits in [flat_instr.qubits, flat_instr.clbits]
            for index, bit in enumerate(bits)
        }

        for instr, qregs, cregs in flat_instr:
            if cregs:
                raise QiskitError(
                    'Cannot apply Instruction with classical registers: {}'.
                    format(instr.name))
            # Get the integer position of the flat register
            new_qubits = [qargs[bit_indices[tup]] for tup in qregs]
            self._append_circuit(instr, new_qubits)

        # Since the individual gate evolution functions don't take mod
        # of phase we update it at the end
        self._phase %= 4
        return self
Пример #25
0
 def _check_dups(self, qubits):
     """Raise exception if list of qubits contains duplicates."""
     squbits = set(qubits)
     if len(squbits) != len(qubits):
         raise QiskitError("duplicate qubit arguments")
Пример #26
0
    def compose(self, other, qargs=None, front=False, inplace=False):
        """Return the composition of Paulis.

        Args:
            a ({cls}): an operator object.
            b ({cls}): an operator object.
            qargs (list or None): Optional, qubits to apply dot product
                                  on (default: None).
            inplace (bool): If True update in-place (default: False).

        Returns:
            {cls}: The operator a.compose(b)

        Raises:
            QiskitError: if number of qubits of other does not match qargs.
        """.format(cls=type(self).__name__)
        # Validation
        if qargs is None and other.num_qubits != self.num_qubits:
            raise QiskitError(
                "other {} must be on the same number of qubits.".format(
                    type(self).__name__))

        if qargs and other.num_qubits != len(qargs):
            raise QiskitError(
                "Number of qubits of the other {} does not match qargs.".
                format(type(self).__name__))

        if other._num_paulis not in [1, self._num_paulis]:
            raise QiskitError("Incompatible BasePaulis. Second list must "
                              "either have 1 or the same number of Paulis.")

        # Compute phase shift
        if qargs is not None:
            x1, z1 = self._x[:, qargs], self._z[:, qargs]
        else:
            x1, z1 = self._x, self._z
        x2, z2 = other._x, other._z

        # Get phase shift
        phase = self._phase + other._phase
        if front:
            phase += 2 * np.sum(np.logical_and(x1, z2), axis=1)
        else:
            phase += 2 * np.sum(np.logical_and(z1, x2), axis=1)

        # Update Pauli
        x = np.logical_xor(x1, x2)
        z = np.logical_xor(z1, z2)

        if qargs is None:
            if not inplace:
                return BasePauli(z, x, phase)
            # Inplace update
            self._x = x
            self._z = z
            self._phase = phase
            return self

        # Qargs update
        ret = self if inplace else self.copy()
        ret._x[:, qargs] = x
        ret._z[:, qargs] = z
        ret._phase = np.mod(phase, 4)
        return ret
Пример #27
0
def _check_conflicting_argument(**kargs):
    conflicting_args = [arg for arg, value in kargs.items() if value]
    if conflicting_args:
        raise QiskitError(
            "The parameters pass_manager conflicts with the following "
            "parameter(s): {}.".format(', '.join(conflicting_args)))
Пример #28
0
    def __init__(self, data=None, num_qubits=None, validate=True):
        """Initialize a CNOTDihedral operator object.

        Args:
            data (CNOTDihedral or QuantumCircuit or ~qiskit.circuit.Instruction):
                Optional, operator to initialize.
            num_qubits (int): Optional, initialize an empty CNOTDihedral operator.
            validate (bool): if True, validates the CNOTDihedral element.

        Raises:
            QiskitError: if the type is invalid.
            QiskitError: if validate=True and the CNOTDihedral element is invalid.
        """

        if num_qubits:
            # initialize n-qubit identity
            self._num_qubits = num_qubits
            # phase polynomial
            self.poly = SpecialPolynomial(self._num_qubits)
            # n x n invertible matrix over Z_2
            self.linear = np.eye(self._num_qubits, dtype=np.int8)
            # binary shift, n coefficients in Z_2
            self.shift = np.zeros(self._num_qubits, dtype=np.int8)

        # Initialize from another CNOTDihedral by sharing the underlying
        # poly, linear and shift
        elif isinstance(data, CNOTDihedral):
            self.linear = data.linear
            self.shift = data.shift
            self.poly = data.poly

        # Initialize from ScalarOp as N-qubit identity discarding any global phase
        elif isinstance(data, ScalarOp):
            if not data.is_unitary() or set(
                    data._input_dims) != {2} or data.num_qubits is None:
                raise QiskitError(
                    "Can only initialize from N-qubit identity ScalarOp.")
            self._num_qubits = data.num_qubits
            # phase polynomial
            self.poly = SpecialPolynomial(self._num_qubits)
            # n x n invertible matrix over Z_2
            self.linear = np.eye(self._num_qubits, dtype=np.int8)
            # binary shift, n coefficients in Z_2
            self.shift = np.zeros(self._num_qubits, dtype=np.int8)

        # Initialize from a QuantumCircuit or Instruction object
        elif isinstance(data, (QuantumCircuit, Instruction)):
            self._num_qubits = data.num_qubits
            elem = self._from_circuit(data)
            self.poly = elem.poly
            self.linear = elem.linear
            self.shift = elem.shift

        elif isinstance(data, Pauli):
            self._num_qubits = data.num_qubits
            elem = self._from_circuit(data.to_instruction())
            self.poly = elem.poly
            self.linear = elem.linear
            self.shift = elem.shift

        else:
            raise QiskitError("Invalid input type for CNOTDihedral class.")

        # Initialize BaseOperator
        super().__init__(num_qubits=self._num_qubits)

        # Validate the CNOTDihedral element
        if validate and not self._is_valid():
            raise QiskitError("Invalid CNOTDihedral element.")
Пример #29
0
def pulse_drawer(samples, duration, dt=None, interp_method='None',
                 filename=None, interactive=False,
                 dpi=150, nop=1000, size=(6, 5)):
    """Plot the interpolated envelope of pulse

    Args:
        samples (ndarray): Data points of complex pulse envelope.
        duration (int): Pulse length (number of points).
        dt (float): Time interval of samples.
        interp_method (str): Method of interpolation
            (set `None` for turn off the interpolation).
        filename (str): Name required to save pulse image.
        interactive (bool): When set true show the circuit in a new window
            (this depends on the matplotlib backend being used supporting this).
        dpi (int): Resolution of saved image.
        nop (int): Data points for interpolation.
        size (tuple): Size of figure.
    Returns:
        matplotlib.figure: A matplotlib figure object for the pulse envelope.
    Raises:
        ImportError: when the output methods requieres non-installed libraries.
        QiskitError: when invalid interpolation method is specified.
    """

    try:
        from matplotlib import pyplot as plt
    except ImportError:
        raise ImportError('pulse_drawer need matplotlib. '
                          'Run "pip install matplotlib" before.')

    if dt:
        _dt = dt
    else:
        _dt = 1

    re_y = np.real(samples)
    im_y = np.imag(samples)

    image = plt.figure(figsize=size)
    ax0 = image.add_subplot(111)

    if interp_method == 'CubicSpline':
        # spline interpolation, use mid-point of dt
        time = np.arange(0, duration + 1) * _dt + 0.5 * _dt
        cs_ry = CubicSpline(time[:-1], re_y)
        cs_iy = CubicSpline(time[:-1], im_y)

        _time = np.linspace(0, duration * _dt, nop)
        _re_y = cs_ry(_time)
        _im_y = cs_iy(_time)
    elif interp_method == 'None':
        # pseudo-DAC output
        time = np.arange(0, duration + 1) * _dt

        _time = np.r_[time[0], np.repeat(time[1:-1], 2), time[-1]]
        _re_y = np.repeat(re_y, 2)
        _im_y = np.repeat(im_y, 2)
    else:
        raise QiskitError('Invalid interpolation method "%s"' % interp_method)

    # plot
    ax0.fill_between(x=_time, y1=_re_y, y2=np.zeros_like(_time),
                     facecolor='red', alpha=0.3,
                     edgecolor='red', linewidth=1.5,
                     label='real part')
    ax0.fill_between(x=_time, y1=_im_y, y2=np.zeros_like(_time),
                     facecolor='blue', alpha=0.3,
                     edgecolor='blue', linewidth=1.5,
                     label='imaginary part')

    ax0.set_xlim(0, duration * _dt)
    ax0.grid(b=True, linestyle='-')
    ax0.legend(bbox_to_anchor=(0.5, 1.00), loc='lower center',
               ncol=2, frameon=False, fontsize=14)

    if filename:
        image.savefig(filename, dpi=dpi, bbox_inches='tight')

    plt.close(image)

    if image and interactive:
        plt.show(image)

    return image
def circuit_to_instruction(circuit,
                           parameter_map=None,
                           equivalence_library=None):
    """Build an ``Instruction`` object from a ``QuantumCircuit``.

    The instruction is anonymous (not tied to a named quantum register),
    and so can be inserted into another circuit. The instruction will
    have the same string name as the circuit.

    Args:
        circuit (QuantumCircuit): the input circuit.
        parameter_map (dict): For parameterized circuits, a mapping from
           parameters in the circuit to parameters to be used in the instruction.
           If None, existing circuit parameters will also parameterize the
           instruction.
        equivalence_library (EquivalenceLibrary): Optional equivalence library
           where the converted instruction will be registered.

    Raises:
        QiskitError: if parameter_map is not compatible with circuit

    Return:
        qiskit.circuit.Instruction: an instruction equivalent to the action of the
        input circuit. Upon decomposition, this instruction will
        yield the components comprising the original circuit.

    Example:
        .. jupyter-execute::

            from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
            from qiskit.converters import circuit_to_instruction
            %matplotlib inline

            q = QuantumRegister(3, 'q')
            c = ClassicalRegister(3, 'c')
            circ = QuantumCircuit(q, c)
            circ.h(q[0])
            circ.cx(q[0], q[1])
            circ.measure(q[0], c[0])
            circ.rz(0.5, q[1]).c_if(c, 2)
            circuit_to_instruction(circ)
    """
    # pylint: disable=cyclic-import
    from qiskit.circuit.quantumcircuit import QuantumCircuit

    if parameter_map is None:
        parameter_dict = {p: p for p in circuit.parameters}
    else:
        parameter_dict = circuit._unroll_param_dict(parameter_map)

    if parameter_dict.keys() != circuit.parameters:
        raise QiskitError(('parameter_map should map all circuit parameters. '
                           'Circuit parameters: {}, parameter_map: {}').format(
                               circuit.parameters, parameter_dict))

    instruction = Instruction(
        name=circuit.name,
        num_qubits=sum([qreg.size for qreg in circuit.qregs]),
        num_clbits=sum([creg.size for creg in circuit.cregs]),
        params=sorted(parameter_dict.values(), key=lambda p: p.name))
    instruction.condition = None

    def find_bit_position(bit):
        """find the index of a given bit (Register, int) within
        a flat ordered list of bits of the circuit
        """
        if isinstance(bit, Qubit):
            ordered_regs = circuit.qregs
        else:
            ordered_regs = circuit.cregs
        reg_index = ordered_regs.index(bit.register)
        return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index

    target = circuit.assign_parameters(parameter_dict, inplace=False)

    if equivalence_library is not None:
        equivalence_library.add_equivalence(instruction, target)

    definition = target.data

    regs = []
    if instruction.num_qubits > 0:
        q = QuantumRegister(instruction.num_qubits, 'q')
        regs.append(q)

    if instruction.num_clbits > 0:
        c = ClassicalRegister(instruction.num_clbits, 'c')
        regs.append(c)

    definition = list(
        map(
            lambda x:
            (x[0], list(map(lambda y: q[find_bit_position(y)], x[1])),
             list(map(lambda y: c[find_bit_position(y)], x[2]))), definition))

    # fix condition
    for rule in definition:
        condition = rule[0].condition
        if condition:
            reg, val = condition
            if reg.size == c.size:
                rule[0].condition = (c, val)
            else:
                raise QiskitError(
                    'Cannot convert condition in circuit with '
                    'multiple classical registers to instruction')

    qc = QuantumCircuit(*regs, name=instruction.name)
    for instr, qargs, cargs in definition:
        qc._append(instr, qargs, cargs)
    if circuit.global_phase:
        qc.global_phase = circuit.global_phase

    instruction.definition = qc

    return instruction