예제 #1
0
 def _compute_gradients(self, circuit: QuantumCircuit) -> List[Tuple[complex, complex]]:
     kwargs = {'statevector_mode': self.quantum_instance.is_statevector}
     logger.info('Constructing evaluation circuits...')
     total_evaluation_circuits = list(parallel_map(
         _circ_eval,
         self.commutators,
         task_kwargs={**kwargs, 'wave_function': circuit},
         num_processes=aqua_globals.num_processes
     ))
     total_evaluation_circuits = [item for sublist in total_evaluation_circuits for item in sublist]
     logger.info('Removing duplicate circuits')
     final_circs = []
     for circ in total_evaluation_circuits:
         if not fast_circuit_inclusion(circ, final_circs):
             final_circs.append(circ)
     logger.info('Finished removing duplicate circuits')
     logger.debug('Executing {} circuits for gradient evaluation...'.format(len(final_circs)))
     result = self.quantum_instance.execute(final_circs)
     logger.debug('Computing {} gradients...'.format(len(self.commutators)))
     grads = list(parallel_map(
         _compute_grad,
         self.commutators,
         task_kwargs={**kwargs, 'result': result},
         num_processes=aqua_globals.num_processes
     ))
     self.adapt_step_history['Total num evals'] += len(final_circs)
     logger.debug('Computed gradients: {}'.format(grads))
     return [abs(tup[0]) for tup in grads]
예제 #2
0
def to_weighted_pauli_operator(operator):
    """
    Converting a given operator to `WeightedPauliOperator`

    Args:
        operator (WeightedPauliOperator | TPBGroupedWeightedPauliOperator | MatrixOperator | Operator):
            one of supported operator type
    Returns:
        WeightedPauliOperator: the converted weighted pauli operator
    """
    if operator.__class__ == WeightedPauliOperator:
        return operator
    elif operator.__class__ == TPBGroupedWeightedPauliOperator:
        # destroy the grouping but keep z2 symmetries info
        return WeightedPauliOperator(paulis=operator.paulis,
                                     z2_symmetries=operator.z2_symmetries,
                                     name=operator.name)
    elif operator.__class__ == MatrixOperator:
        if operator.is_empty():
            return WeightedPauliOperator(paulis=[])
        logger.warning(
            "Converting time from a MatrixOperator to a Pauli-type Operator grows exponentially. "
            "If you are converting a system with large number of qubits, it will take time. "
            "You can turn on DEBUG logging to check the progress.")
        num_qubits = operator.num_qubits
        coeff = 2**(-num_qubits)

        paulis = []
        possible_basis = 'IXYZ'
        if operator.dia_matrix is not None:
            possible_basis = 'IZ'

        if logger.isEnabledFor(logging.DEBUG):
            logger.debug(
                "Converting a MatrixOperator to a Pauli-type Operator:")
            TextProgressBar(sys.stderr)
        results = parallel_map(_conversion, [
            basis
            for basis in itertools.product(possible_basis, repeat=num_qubits)
        ],
                               task_kwargs={"matrix": operator._matrix},
                               num_processes=aqua_globals.num_processes)
        for trace_value, pauli in results:
            weight = trace_value * coeff
            if weight != 0.0 and np.abs(weight) > operator.atol:
                paulis.append([weight, pauli])

        return WeightedPauliOperator(paulis,
                                     z2_symmetries=operator.z2_symmetries,
                                     name=operator.name)
    elif operator.__class__ == Operator:
        warnings.warn(
            "The `Operator` class is deprecated. Please use `WeightedPauliOperator` or "
            "`TPBGroupedWeightedPauliOperator` or `MatrixOperator` instead",
            DeprecationWarning)
        return operator.to_weighted_pauli_operator()
    else:
        raise AquaError(
            "Unsupported type to convert to WeightedPauliOperator: {}".format(
                operator.__class__))
예제 #3
0
 def commutators(self) -> List[BaseOperator]:
     if self._coms is not None:
         return self._coms
     logger.info('Computing commutators...')
     self._coms = list(parallel_map(
         _commutator,
         self.operator_pool.pool,
         task_kwargs={'hamiltonian': self.hamiltonian, 'gradient_tolerance': self.grad_tol},
         num_processes=aqua_globals.num_processes
     ))  # type: List[BaseOperator]
     logger.info('Computed {} commutators'.format(len(self._coms)))
     if all(isinstance(op, WeightedPauliOperator) for op in self._coms):
         new_coms = []
         new_pool = []
         for com, op in zip(self._coms, self.operator_pool.pool):
             if len(com.paulis) > 0:
                 new_coms.append(com)
                 new_pool.append(op)
         self._coms = new_coms
         self.operator_pool._pool = new_pool
         logger.info('Dropped commuting terms, new pool has size {}'.format(len(self._coms)))
     else:
         logger.info(
             'Dropping commuting terms currently only supported for WeightedPauliOperator class')
     if len(self._coms) == 0:
         raise ValueError('List of commutators is empty.')
     return self._coms
예제 #4
0
def to_weighted_pauli_operator(
        operator: Union[WeightedPauliOperator, TPBGroupedWeightedPauliOperator, MatrixOperator]) \
        -> WeightedPauliOperator:
    """
    Converting a given operator to `WeightedPauliOperator`

    Args:
        operator: one of supported operator type
    Returns:
        The converted weighted pauli operator
    Raises:
        OpflowError: Unsupported type to convert

    Warnings:
        Converting time from a MatrixOperator to a Pauli-type Operator grows exponentially.
        If you are converting a system with large number of qubits, it will take time.
        You can turn on DEBUG logging to check the progress.
    """
    if operator.__class__ == WeightedPauliOperator:
        return cast(WeightedPauliOperator, operator)
    elif operator.__class__ == TPBGroupedWeightedPauliOperator:
        # destroy the grouping but keep z2 symmetries info
        op_tpb = cast(TPBGroupedWeightedPauliOperator, operator)
        return WeightedPauliOperator(paulis=op_tpb.paulis, z2_symmetries=op_tpb.z2_symmetries,
                                     name=op_tpb.name)
    elif operator.__class__ == MatrixOperator:
        op_m = cast(MatrixOperator, operator)
        if op_m.is_empty():
            return WeightedPauliOperator(paulis=[])
        if op_m.num_qubits > 10:
            logger.warning("Converting time from a MatrixOperator to a Pauli-type Operator grows "
                           "exponentially. If you are converting a system with large number of "
                           "qubits, it will take time. And now you are converting a %s-qubit "
                           "Hamiltonian. You can turn on DEBUG logging to check the progress."
                           "", op_m.num_qubits)
        num_qubits = op_m.num_qubits
        coeff = 2 ** (-num_qubits)

        paulis = []
        possible_basis = 'IXYZ'
        if op_m.dia_matrix is not None:
            possible_basis = 'IZ'

        if logger.isEnabledFor(logging.DEBUG):
            logger.debug("Converting a MatrixOperator to a Pauli-type Operator:")

        results = parallel_map(_conversion,
                               list(itertools.product(possible_basis, repeat=num_qubits)),
                               task_kwargs={"matrix": op_m._matrix},
                               num_processes=aqua_globals.num_processes)
        for trace_value, pauli in results:
            weight = trace_value * coeff
            if weight != 0.0 and np.abs(weight) > op_m.atol:
                paulis.append([weight, pauli])

        return WeightedPauliOperator(paulis, z2_symmetries=operator.z2_symmetries,
                                     name=operator.name)
    else:
        raise OpflowError("Unsupported type to convert to WeightedPauliOperator: "
                          "{}".format(operator.__class__))
예제 #5
0
def assemble_circuits(circuits, run_config, qobj_id, qobj_header):
    """Assembles a list of circuits into a qobj that can be run on the backend.

    Args:
        circuits (list[QuantumCircuit]): circuit(s) to assemble
        qobj_id (int): identifier for the generated qobj
        qobj_header (QobjHeader): header to pass to the results
        run_config (RunConfig): configuration of the runtime environment

    Returns:
        QasmQobj: the qobj to be run on the backends
    """
    qobj_config = QasmQobjConfig()
    if run_config:
        qobj_config = QasmQobjConfig(**run_config.to_dict())
    qubit_sizes = []
    memory_slot_sizes = []
    for circ in circuits:
        num_qubits = 0
        memory_slots = 0
        for qreg in circ.qregs:
            num_qubits += qreg.size
        for creg in circ.cregs:
            memory_slots += creg.size
        qubit_sizes.append(num_qubits)
        memory_slot_sizes.append(memory_slots)
    qobj_config.memory_slots = max(memory_slot_sizes)
    qobj_config.n_qubits = max(qubit_sizes)

    experiments = parallel_map(_assemble_circuit, circuits)

    return QasmQobj(qobj_id=qobj_id,
                    config=qobj_config,
                    experiments=experiments,
                    header=qobj_header)
예제 #6
0
def transpile(circuits, backend=None, basis_gates=None, coupling_map=None,
              initial_layout=None, seed_mapper=None, pass_manager=None):
    """transpile one or more circuits.

    Args:
        circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile
        backend (BaseBackend): a backend to compile for
        basis_gates (list[str]): list of basis gate names supported by the
            target. Default: ['u1','u2','u3','cx','id']
        coupling_map (list): coupling map (perhaps custom) to target in mapping
        initial_layout (list): initial layout of qubits in mapping
        seed_mapper (int): random seed for the swap_mapper
        pass_manager (PassManager): a pass_manager for the transpiler stages

    Returns:
        QuantumCircuit or list[QuantumCircuit]: transpiled circuit(s).

    Raises:
        TranspilerError: if args are not complete for the transpiler to function
    """
    return_form_is_single = False
    if isinstance(circuits, QuantumCircuit):
        circuits = [circuits]
        return_form_is_single = True

    # Check for valid parameters for the experiments.
    basis_gates = basis_gates or backend.configuration().basis_gates
    if coupling_map:
        coupling_map = coupling_map
    elif backend:
        # This needs to be removed once Aer 0.2 is out
        coupling_map = getattr(backend.configuration(), 'coupling_map', None)
    else:
        coupling_map = None

    if not basis_gates:
        raise TranspilerError('no basis_gates or backend to compile to')

    # Convert integer list format to Layout
    if isinstance(initial_layout, list) and \
            all(isinstance(elem, int) for elem in initial_layout):
        if isinstance(circuits, list):
            circ = circuits[0]
        else:
            circ = circuits
        initial_layout = Layout.generate_from_intlist(initial_layout, *circ.qregs)

    if initial_layout is not None and not isinstance(initial_layout, Layout):
        initial_layout = Layout(initial_layout)

    circuits = parallel_map(_transpilation, circuits,
                            task_kwargs={'basis_gates': basis_gates,
                                         'coupling_map': coupling_map,
                                         'initial_layout': initial_layout,
                                         'seed_mapper': seed_mapper,
                                         'pass_manager': pass_manager})
    if return_form_is_single:
        return circuits[0]
    return circuits
예제 #7
0
def run_monte_carlo_experiments(op_system):
    """ Runs monte carlo experiments for a given op_system

    Parameters:
        op_system (PulseSimDescription): container for simulation information

    Returns:
        tuple: two lists with experiment results

    Raises:
        Exception: if initial state is of incorrect format
    """

    if not op_system.initial_state.isket:
        raise Exception("Initial state must be a state vector.")

    # set num_cpus to the value given in settings if none in Options
    if not op_system.ode_options.num_cpus:
        op_system.ode_options.num_cpus = CPU_COUNT

    # setup seeds array
    seed = op_system.global_data.get(
        'seed', np.random.randint(np.iinfo(np.int32).max - 1))
    prng = np.random.RandomState(seed)
    for exp in op_system.experiments:
        exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1)

    map_kwargs = {'num_processes': op_system.ode_options.num_cpus}

    exp_results = []
    exp_times = []
    for exp in op_system.experiments:
        start = time.time()
        rng = np.random.RandomState(exp['seed'])
        seeds = rng.randint(np.iinfo(np.int32).max - 1,
                            size=op_system.global_data['shots'])
        exp_res = parallel_map(monte_carlo_evolution,
                               seeds,
                               task_args=(
                                   exp,
                                   op_system,
                               ),
                               **map_kwargs)

        # exp_results is a list for each shot
        # so transform back to an array of shots
        exp_res2 = []
        for exp_shot in exp_res:
            exp_res2.append(exp_shot[0].tolist())

        end = time.time()
        exp_times.append(end - start)
        exp_results.append(np.array(exp_res2))

    return exp_results, exp_times
예제 #8
0
    def _run_several_circuits(self, circuits):
        """Run all the passes on each of the circuits in the circuits list

        Args:
            circuits (list[QuantumCircuit]): circuit to transform via all the registered passes

        Returns:
            list[QuantumCircuit]: Transformed circuits.
        """
        return parallel_map(PassManager._in_parallel, circuits,
                            task_kwargs={'pm_dill': dill.dumps(self)})
예제 #9
0
    def _run_several_circuits(self, circuits, output_name=None, callback=None):
        """Run all the passes on each of the circuits in the circuits list
        Returns:
            list[QuantumCircuit]: Transformed circuits.
        """
        # TODO support for List(output_name) and List(callback)
        del output_name
        del callback

        return parallel_map(PassManager._in_parallel,
                            circuits,
                            task_kwargs={'pm_dill': dill.dumps(self)})
예제 #10
0
def run_unitary_experiments(pulse_sim_desc,
                            pulse_de_model,
                            solver_options=None):
    """ Runs unitary experiments for a given op_system

    Parameters:
        pulse_sim_desc (PulseSimDescription): description of pulse simulation
        pulse_de_model (PulseInternalDEModel): description of de model
        solver_options (PulseSimOptions): options

    Returns:
        tuple: two lists with experiment results

    Raises:
        Exception: if initial state is of incorrect format
    """

    solver_options = PulseSimOptions(
    ) if solver_options is None else solver_options

    if not pulse_sim_desc.initial_state.isket:
        raise Exception("Initial state must be a state vector.")

    y0 = pulse_sim_desc.initial_state.full().ravel()

    # set num_cpus to the value given in settings if none in Options
    if not solver_options.num_cpus:
        solver_options.num_cpus = CPU_COUNT

    # setup seeds array
    seed = pulse_sim_desc.seed or np.random.randint(np.iinfo(np.int32).max - 1)
    prng = np.random.RandomState(seed)
    for exp in pulse_sim_desc.experiments:
        exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1)

    map_kwargs = {'num_processes': solver_options.num_cpus}

    # run simulation on each experiment in parallel
    start = time.time()
    exp_results = parallel_map(_full_simulation,
                               pulse_sim_desc.experiments,
                               task_args=(
                                   y0,
                                   pulse_sim_desc,
                                   pulse_de_model,
                                   solver_options,
                               ),
                               **map_kwargs)
    end = time.time()
    exp_times = (np.ones(len(pulse_sim_desc.experiments)) * (end - start) /
                 len(pulse_sim_desc.experiments))

    return exp_results, exp_times
예제 #11
0
def assemble_circuits(circuits: List[QuantumCircuit], run_config: RunConfig,
                      qobj_id: int, qobj_header: QobjHeader) -> QasmQobj:
    """Assembles a list of circuits into a qobj that can be run on the backend.

    Args:
        circuits: circuit(s) to assemble
        run_config: configuration of the runtime environment
        qobj_id: identifier for the generated qobj
        qobj_header: header to pass to the results

    Returns:
        The qobj to be run on the backends
    """
    qobj_config = QasmQobjConfig()
    if run_config:
        qobj_config = QasmQobjConfig(**run_config.to_dict())
    qubit_sizes = []
    memory_slot_sizes = []
    for circ in circuits:
        num_qubits = 0
        memory_slots = 0
        for qreg in circ.qregs:
            num_qubits += qreg.size
        for creg in circ.cregs:
            memory_slots += creg.size
        qubit_sizes.append(num_qubits)
        memory_slot_sizes.append(memory_slots)
    qobj_config.memory_slots = max(memory_slot_sizes)
    qobj_config.n_qubits = max(qubit_sizes)

    experiments_and_pulse_libs = parallel_map(_assemble_circuit, circuits,
                                              [run_config])
    experiments = []
    pulse_library = {}
    for exp, lib in experiments_and_pulse_libs:
        experiments.append(exp)
        if lib:
            pulse_library.update(lib)
    if pulse_library:
        qobj_config.pulse_library = [
            PulseLibraryItem(name=name, samples=samples)
            for name, samples in pulse_library.items()
        ]
    experiments, calibrations = _extract_common_calibrations(experiments)
    if calibrations and calibrations.gates:
        qobj_config.calibrations = calibrations

    return QasmQobj(qobj_id=qobj_id,
                    config=qobj_config,
                    experiments=experiments,
                    header=qobj_header)
예제 #12
0
def transpile(circuits,
              backend=None,
              basis_gates=None,
              coupling_map=None,
              initial_layout=None,
              seed_mapper=None,
              pass_manager=None):
    """transpile one or more circuits.

    Args:
        circuits (QuantumCircuit or list[QuantumCircuit]): circuits to compile
        backend (BaseBackend): a backend to compile for
        basis_gates (list[str]): list of basis gate names supported by the
            target. Default: ['u1','u2','u3','cx','id']
        coupling_map (list): coupling map (perhaps custom) to target in mapping
        initial_layout (list): initial layout of qubits in mapping
        seed_mapper (int): random seed for the swap_mapper
        pass_manager (PassManager): a pass_manager for the transpiler stages

    Returns:
        QuantumCircuit or list[QuantumCircuit]: transpiled circuit(s).

    Raises:
        TranspilerError: if args are not complete for the transpiler to function
    """
    return_form_is_single = False
    if isinstance(circuits, QuantumCircuit):
        circuits = [circuits]
        return_form_is_single = True

    # Check for valid parameters for the experiments.
    basis_gates = basis_gates or backend.configuration().basis_gates
    coupling_map = coupling_map or getattr(backend.configuration(),
                                           'coupling_map', None)

    if not basis_gates:
        raise TranspilerError('no basis_gates or backend to compile to')

    circuits = parallel_map(_transpilation,
                            circuits,
                            task_kwargs={
                                'basis_gates': basis_gates,
                                'coupling_map': coupling_map,
                                'initial_layout': initial_layout,
                                'seed_mapper': seed_mapper,
                                'pass_manager': pass_manager
                            })
    if return_form_is_single:
        return circuits[0]
    return circuits
예제 #13
0
    def _run_several_circuits(
        self, circuits: List[QuantumCircuit], output_name: str = None, callback: Callable = None
    ) -> List[QuantumCircuit]:
        """Run all the passes on the specified ``circuits``.

        Args:
            circuits: Circuits to transform via all the registered passes.
            output_name: The output circuit name. If ``None``, it will be set to the same as the
                input circuit name.
            callback: A callback function that will be called after each pass execution.

        Returns:
            The transformed circuits.
        """
        # TODO support for List(output_name) and List(callback)
        del output_name
        del callback

        return parallel_map(
            PassManager._in_parallel, circuits, task_kwargs={"pm_dill": dill.dumps(self)}
        )
예제 #14
0
def run_unitary_experiments(op_system):
    """ Runs unitary experiments for a given op_system

    Parameters:
        op_system (PulseSimDescription): container for simulation information

    Returns:
        tuple: two lists with experiment results

    Raises:
        Exception: if initial state is of incorrect format
    """

    if not op_system.initial_state.isket:
        raise Exception("Initial state must be a state vector.")

    # set num_cpus to the value given in settings if none in Options
    if not op_system.ode_options.num_cpus:
        op_system.ode_options.num_cpus = CPU_COUNT

    # setup seeds array
    seed = op_system.global_data.get('seed', np.random.randint(np.iinfo(np.int32).max - 1))
    prng = np.random.RandomState(seed)
    for exp in op_system.experiments:
        exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1)

    map_kwargs = {'num_processes': op_system.ode_options.num_cpus}

    # run simulation on each experiment in parallel
    start = time.time()
    exp_results = parallel_map(_full_simulation,
                               op_system.experiments,
                               task_args=(op_system, ),
                               **map_kwargs
                               )
    end = time.time()
    exp_times = (np.ones(len(op_system.experiments)) *
                 (end - start) / len(op_system.experiments))

    return exp_results, exp_times
예제 #15
0
def assemble_circuits(circuits: List[QuantumCircuit], run_config: RunConfig,
                      qobj_id: int, qobj_header: QobjHeader) -> QasmQobj:
    """Assembles a list of circuits into a qobj that can be run on the backend.

    Args:
        circuits: circuit(s) to assemble
        run_config: configuration of the runtime environment
        qobj_id: identifier for the generated qobj
        qobj_header: header to pass to the results

    Returns:
        The qobj to be run on the backends
    """
    # assemble the circuit experiments
    experiments_and_pulse_libs = parallel_map(_assemble_circuit, circuits,
                                              [run_config])
    experiments = []
    pulse_library = {}
    for exp, lib in experiments_and_pulse_libs:
        experiments.append(exp)
        if lib:
            pulse_library.update(lib)

    # extract common calibrations
    experiments, calibrations = _extract_common_calibrations(experiments)

    # configure LO freqs per circuit
    lo_converter = converters.LoConfigConverter(QasmQobjExperimentConfig,
                                                **run_config.to_dict())
    experiments = _configure_experiment_los(experiments, lo_converter,
                                            run_config)

    qobj_config = QasmQobjConfig()
    if run_config:
        qobj_config_dict = run_config.to_dict()

        # remove LO ranges, not needed in qobj
        qobj_config_dict.pop("qubit_lo_range", None)
        qobj_config_dict.pop("meas_lo_range", None)

        # convert LO frequencies to GHz, if they exist
        if "qubit_lo_freq" in qobj_config_dict:
            qobj_config_dict["qubit_lo_freq"] = [
                freq / 1e9 for freq in qobj_config_dict["qubit_lo_freq"]
            ]
        if "meas_lo_freq" in qobj_config_dict:
            qobj_config_dict["meas_lo_freq"] = [
                freq / 1e9 for freq in qobj_config_dict["meas_lo_freq"]
            ]

        # override default los if single ``schedule_los`` entry set
        schedule_los = qobj_config_dict.pop("schedule_los", [])
        if len(schedule_los) == 1:
            lo_dict = schedule_los[0]
            q_los = lo_converter.get_qubit_los(lo_dict)
            # Hz -> GHz
            if q_los:
                qobj_config_dict["qubit_lo_freq"] = [
                    freq / 1e9 for freq in q_los
                ]
            m_los = lo_converter.get_meas_los(lo_dict)
            if m_los:
                qobj_config_dict["meas_lo_freq"] = [
                    freq / 1e9 for freq in m_los
                ]

        qobj_config = QasmQobjConfig(**qobj_config_dict)

    qubit_sizes = []
    memory_slot_sizes = []
    for circ in circuits:
        num_qubits = 0
        memory_slots = 0
        for qreg in circ.qregs:
            num_qubits += qreg.size
        for creg in circ.cregs:
            memory_slots += creg.size
        qubit_sizes.append(num_qubits)
        memory_slot_sizes.append(memory_slots)
    qobj_config.memory_slots = max(memory_slot_sizes)
    qobj_config.n_qubits = max(qubit_sizes)

    if pulse_library:
        qobj_config.pulse_library = [
            PulseLibraryItem(name=name, samples=samples)
            for name, samples in pulse_library.items()
        ]

    if calibrations and calibrations.gates:
        qobj_config.calibrations = calibrations

    return QasmQobj(qobj_id=qobj_id,
                    config=qobj_config,
                    experiments=experiments,
                    header=qobj_header)
def run_monte_carlo_experiments(pulse_sim_desc,
                                pulse_de_model,
                                solver_options=None):
    """ Runs monte carlo experiments for a given op_system

    Parameters:
        pulse_sim_desc (PulseSimDescription): description of pulse simulation
        pulse_de_model (PulseInternalDEModel): description of de model
        solver_options (PulseSimOptions): options

    Returns:
        tuple: two lists with experiment results

    Raises:
        Exception: if initial state is of incorrect format
    """

    solver_options = PulseSimOptions(
    ) if solver_options is None else solver_options

    if not pulse_sim_desc.initial_state.data.ndim != 1:
        raise Exception("Initial state must be a state vector.")

    y0 = pulse_sim_desc.initial_state.data.ravel()

    # set num_cpus to the value given in settings if none in Options
    if not solver_options.num_cpus:
        solver_options.num_cpus = CPU_COUNT

    # setup seeds array
    seed = pulse_sim_desc.seed or np.random.randint(np.iinfo(np.int32).max - 1)
    prng = np.random.RandomState(seed)
    for exp in pulse_sim_desc.experiments:
        exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1)

    map_kwargs = {'num_processes': solver_options.num_cpus}

    exp_results = []
    exp_times = []

    # needs to be configured ahead of time
    pulse_de_model._config_internal_data()

    for exp in pulse_sim_desc.experiments:
        start = time.time()
        rng = np.random.RandomState(exp['seed'])
        seeds = rng.randint(np.iinfo(np.int32).max - 1,
                            size=pulse_sim_desc.shots)
        exp_res = parallel_map(monte_carlo_evolution,
                               seeds,
                               task_args=(
                                   exp,
                                   y0,
                                   pulse_sim_desc,
                                   pulse_de_model,
                                   solver_options,
                               ),
                               **map_kwargs)

        # exp_results is a list for each shot
        # so transform back to an array of shots
        exp_res2 = []
        for exp_shot in exp_res:
            exp_res2.append(exp_shot[0].tolist())

        end = time.time()
        exp_times.append(end - start)
        exp_results.append(np.array(exp_res2))

    return exp_results, exp_times
예제 #17
0
 def test_parallel_schedule_names(self):
     """Verify unique schedule names in parallel"""
     out_schedules = parallel_map(_build_simple_schedule, list(range(10)))
     names = [schedule.name for schedule in out_schedules]
     self.assertEqual(len(names), len(set(names)))
예제 #18
0
 def test_parallel_circuit_names(self):
     """Verify unique circuit names in parallel"""
     out_circs = parallel_map(_build_simple_circuit, list(range(10)))
     names = [circ.name for circ in out_circs]
     self.assertEqual(len(names), len(set(names)))
예제 #19
0
 def test_parallel(self):
     """Test parallel_map"""
     ans = parallel_map(_parfunc, list(range(10)))
     self.assertEqual(ans, list(range(10)))
예제 #20
0
def schedule(
    circuits: Union[QuantumCircuit, List[QuantumCircuit]],
    backend: Optional[Backend] = None,
    inst_map: Optional[InstructionScheduleMap] = None,
    meas_map: Optional[List[List[int]]] = None,
    dt: Optional[float] = None,
    method: Optional[Union[str, List[str]]] = None,
) -> Union[Schedule, List[Schedule]]:
    """
    Schedule a circuit to a pulse ``Schedule``, using the backend, according to any specified
    methods. Supported methods are documented in :py:mod:`qiskit.scheduler.schedule_circuit`.

    Args:
        circuits: The quantum circuit or circuits to translate
        backend: A backend instance, which contains hardware-specific data required for scheduling
        inst_map: Mapping of circuit operations to pulse schedules. If ``None``, defaults to the
                  ``backend``\'s ``instruction_schedule_map``
        meas_map: List of sets of qubits that must be measured together. If ``None``, defaults to
                  the ``backend``\'s ``meas_map``
        dt: The output sample rate of backend control electronics. For scheduled circuits
            which contain time information, dt is required. If not provided, it will be
            obtained from the backend configuration
        method: Optionally specify a particular scheduling method

    Returns:
        A pulse ``Schedule`` that implements the input circuit

    Raises:
        QiskitError: If ``inst_map`` and ``meas_map`` are not passed and ``backend`` is not passed
    """
    arg_circuits_list = isinstance(circuits, list)
    start_time = time()
    if backend and getattr(backend, "version", 0) > 1:
        if inst_map is None:
            inst_map = backend.instruction_schedule_map
        if meas_map is None:
            meas_map = backend.meas_map
        if dt is None:
            dt = backend.dt
    else:
        if inst_map is None:
            if backend is None:
                raise QiskitError(
                    "Must supply either a backend or InstructionScheduleMap for scheduling passes."
                )
            defaults = backend.defaults()
            if defaults is None:
                raise QiskitError(
                    "The backend defaults are unavailable. The backend may not support pulse."
                )
            inst_map = defaults.instruction_schedule_map
        if meas_map is None:
            if backend is None:
                raise QiskitError(
                    "Must supply either a backend or a meas_map for scheduling passes."
                )
            meas_map = backend.configuration().meas_map
        if dt is None:
            if backend is not None:
                dt = backend.configuration().dt

    schedule_config = ScheduleConfig(inst_map=inst_map,
                                     meas_map=meas_map,
                                     dt=dt)
    circuits = circuits if isinstance(circuits, list) else [circuits]
    schedules = parallel_map(schedule_circuit, circuits,
                             (schedule_config, method))
    end_time = time()
    _log_schedule_time(start_time, end_time)
    if arg_circuits_list:
        return schedules
    else:
        return schedules[0]
예제 #21
0
    def run(self):
        """Runs the solver.
        """
        map_kwargs = {'num_processes': self.op_system.ode_options.num_cpus}

        # exp_results from the solvers return the values of the measurement
        # operators

        # If no collapse terms, and only measurements at end
        # can do a single shot.

        # exp_results is a list of '0' and '1'
        # where '0' occurs with probability 1-<M>
        # and '1' occurs with probability <M>
        # M is the measurement operator, which is a projector
        # into one of the qubit states (usually |1>)
        if self.op_system.can_sample:
            start = time.time()
            exp_results = parallel_map(unitary_evolution,
                                       self.op_system.experiments,
                                       task_args=(self.op_system, ),
                                       **map_kwargs)
            end = time.time()
            exp_times = (np.ones(len(self.op_system.experiments)) *
                         (end - start) / len(self.op_system.experiments))

        # need to simulate each trajectory, so shots*len(experiments) times
        # Do a for-loop over experiments, and do shots in parallel_map
        else:
            exp_results = []
            exp_times = []
            for exp in self.op_system.experiments:
                start = time.time()
                rng = np.random.RandomState(exp['seed'])
                seeds = rng.randint(np.iinfo(np.int32).max - 1,
                                    size=self.op_system.global_data['shots'])
                exp_res = parallel_map(monte_carlo,
                                       seeds,
                                       task_args=(
                                           exp,
                                           self.op_system,
                                       ),
                                       **map_kwargs)

                # exp_results is a list for each shot
                # so transform back to an array of shots
                exp_res2 = []
                for exp_shot in exp_res:
                    exp_res2.append(exp_shot[0].tolist())

                end = time.time()
                exp_times.append(end - start)
                exp_results.append(np.array(exp_res2))

        # format the data into the proper output
        all_results = []
        for idx_exp, exp in enumerate(self.op_system.experiments):

            m_lev = self.op_system.global_data['meas_level']
            m_ret = self.op_system.global_data['meas_return']

            # populate the results dictionary
            results = {
                'seed_simulator': exp['seed'],
                'shots': self.op_system.global_data['shots'],
                'status': 'DONE',
                'success': True,
                'time_taken': exp_times[idx_exp],
                'header': exp['header'],
                'meas_level': m_lev,
                'meas_return': m_ret,
                'data': {}
            }

            if self.op_system.can_sample:
                memory = exp_results[idx_exp][0]
                results['data']['statevector'] = []
                for coef in exp_results[idx_exp][1]:
                    results['data']['statevector'].append(
                        [np.real(coef), np.imag(coef)])
                results['header']['ode_t'] = exp_results[idx_exp][2]
            else:
                memory = exp_results[idx_exp]

            # meas_level 2 return the shots
            if m_lev == 2:

                # convert the memory **array** into a n
                # integer
                # e.g. [1,0] -> 2
                int_mem = memory.dot(np.power(2.0, np.arange(
                    memory.shape[1]))).astype(int)

                # if the memory flag is set return each shot
                if self.op_system.global_data['memory']:
                    hex_mem = [hex(val) for val in int_mem]
                    results['data']['memory'] = hex_mem

                # Get hex counts dict
                unique = np.unique(int_mem, return_counts=True)
                hex_dict = {}
                for kk in range(unique[0].shape[0]):
                    key = hex(unique[0][kk])
                    hex_dict[key] = unique[1][kk]

                results['data']['counts'] = hex_dict

            # meas_level 1 returns the <n>
            elif m_lev == 1:

                if m_ret == 'avg':

                    memory = [np.mean(memory, 0)]

                # convert into the right [real, complex] pair form for json
                # this should be cython?
                results['data']['memory'] = []

                for mem_shot in memory:
                    results['data']['memory'].append([])
                    for mem_slot in mem_shot:
                        results['data']['memory'][-1].append(
                            [np.real(mem_slot),
                             np.imag(mem_slot)])

                if m_ret == 'avg':
                    results['data']['memory'] = results['data']['memory'][0]

            all_results.append(results)

        if not self.op_system.use_cpp_ode_func:
            _cython_build_cleanup(self.op_system.global_data['rhs_file_name'])

        return all_results
예제 #22
0
    def find_optim_param_energy(self, preferred_op = None, preferred_op_mode = False,  previous_circuit = None) -> dict:
        """method: find_optim_param_energy
               finds the optimum operator+parameter pair for the next iteration of the ansatz
        args: 
           preferred_op - an operator (weightedpaulioperator) predetermined to be the next operator in the ansatz 
                           (essentially converts this method to rotosolve instead of rotoselect)
           preferred_op_mode - a flag (boolean) to choose whether or not preferred op should be used
        
        returns:
           dictionary with: optimal operator, name of optimal operator (for output purposes), optimal parameter,
                            optimal energy, A, B, and C for Asin(theta + B) + C
        """
        A = np.empty(0)
        C = np.empty(0)
        final_circs = []
        E_list = []
        #measure energies (theta = 0, theta = pi/4, theta = -pi/4)

        if(self.adapt_step_history['Total number energy iterations'] == 0):
            wavefunc = self.initial_state.construct_circuit()
            Energy_0_circ = self.hamiltonian.construct_evaluation_circuit(wavefunc, True)
            result = self.quantum_instance.execute(Energy_0_circ)
            Energy_0 = np.real(self.hamiltonian.evaluate_with_result(result, True)[0])
            self.adapt_step_history['Total num evals'] += 1
        else:
            op_list = self._current_operator_list
            bounds=[(-np.pi, +np.pi)]*len(op_list)
            vf = ADAPTVariationalForm(op_list, bounds, self.initial_state)
            wavefunc = vf.construct_circuit(self.adapt_step_history['optimal_parameters'][-1])
            Energy_0 = self.adapt_step_history['energy_history'][-1]

        if preferred_op_mode:
            pool = preferred_op
        else:
            pool = self.operator_pool.pool

        args = []
        kwargs = {'ham': self.hamiltonian, 'energy_step_tol': self.energy_step_tol, 'parameter': np.pi/4}
        op_list_pi4 = list(parallel_map(
            Generate_op,
            pool,
            args,
            kwargs
            ))
        kwargs['parameter'] = -np.pi/4
        op_list_negpi4 = list(parallel_map(
            Generate_op,
            self.operator_pool.pool,
            args,
            kwargs
            ))

        op_list = op_list_pi4 + op_list_negpi4

        kwargs = {'statevector_mode': self.quantum_instance.is_statevector}
        total_evaluation_circuits = list(parallel_map(
            _circ_eval,
            op_list,
            task_kwargs={**kwargs, 'wave_function': wavefunc},
            num_processes=aqua_globals.num_processes
        ))

        total_evaluation_circuits = [item for sublist in total_evaluation_circuits for item in sublist]
        logger.info('Removing duplicate circuits')

        for circ in total_evaluation_circuits:
            if not fast_circuit_inclusion(circ, final_circs):
                final_circs.append(circ)
        result = self.quantum_instance.execute(final_circs)

        Energies = list(parallel_map(
            _compute_energy,
            op_list,
            task_kwargs={**kwargs, 'result': result},
            num_processes=aqua_globals.num_processes
            ))

        for entry in Energies:
            E_list.append(np.real(entry[0]))

        cutoff = int(len(E_list)/2)
        Energy_pi4 = np.array(E_list[0:cutoff])
        Energy_negpi4 = np.array(E_list[cutoff:])
        #calculate minimum energy + A,B, and C from measured energies
        B = np.arctan2(( -Energy_negpi4 - Energy_pi4 + 2*Energy_0),(Energy_pi4 - Energy_negpi4))
        Optim_param_array = (-B - np.pi/2)/2
        X = np.sin(B)
        Y = np.sin(B + np.pi/2)
        Z = np.sin(B - np.pi/2)
        for i in range(0,(len(Energy_negpi4)-1)):
            if Y[i] != 0:
                C = np.append(C, (Energy_0-Energy_pi4[i]*(X[i]/Y[i]))/(1-X[i]/Y[i]))
                A = np.append(A, (Energy_pi4[i] - C[-1])/Y[i])
            else:
                C = np.append(C, Energy_pi4[i])
                A = np.append(A, (Energy_0 - C[-1])/X[i])
        Optim_energy_array = C - A
        #find minimum energy index
        Optim_param_pos = np.argmin(Optim_energy_array)
        min_energy = Optim_energy_array[Optim_param_pos]
        Optim_param = Optim_param_array[Optim_param_pos]

        #CPU has limit on smallest number to be calculated - looks like its somewhere around 1e-16
        #manually set this to zero as it should be zero.
        if min_energy > Energy_0 and abs(Optim_param) < 2e-16:
            Optim_param = 0
            min_energy = Energy_0

        #find optimum operator
        Optim_operator = self.operator_pool.pool[Optim_param_pos]
        Optim_operator_name = self.operator_pool.pool[Optim_param_pos].print_details()

        #keep track of number of quantum evaluations
        self.adapt_step_history['Total num evals'] += len(final_circs)

        return {'Newly Minimized Energy': min_energy, 'Next Parameter value': Optim_param, 
         'Next Operator identity': Optim_operator, 'Next Operator Name': Optim_operator_name, 'A': A[Optim_param_pos], 'B': B[Optim_param_pos], 'C': C[Optim_param_pos]}
예제 #23
0
def run_unitary_experiments(op_system):
    """ Runs unitary experiments for a given op_system

    Parameters:
        op_system (PulseSimDescription): container for simulation information

    Returns:
        tuple: two lists with experiment results

    Raises:
        Exception: if initial state is of incorrect format
    """

    if not op_system.initial_state.isket:
        raise Exception("Initial state must be a state vector.")

    # set num_cpus to the value given in settings if none in Options
    if not op_system.ode_options.num_cpus:
        op_system.ode_options.num_cpus = CPU_COUNT

    # setup seeds array
    seed = op_system.global_data.get('seed', np.random.randint(np.iinfo(np.int32).max - 1))
    prng = np.random.RandomState(seed)
    for exp in op_system.experiments:
        exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1)

    map_kwargs = {'num_processes': op_system.ode_options.num_cpus}

    # set up full simulation, i.e. combining different (ideally modular) computational
    # resources into one function
    def full_simulation(exp, op_system):

        psi, ode_t = unitary_evolution(exp, op_system)

        # ###############
        # do measurement
        # ###############
        rng = np.random.RandomState(exp['seed'])

        shots = op_system.global_data['shots']
        # Init memory
        memory = np.zeros((shots, op_system.global_data['memory_slots']),
                          dtype=np.uint8)

        qubits = []
        memory_slots = []
        tlist = exp['tlist']
        for acq in exp['acquire']:
            if acq[0] == tlist[-1]:
                qubits += list(acq[1])
                memory_slots += list(acq[2])
        qubits = np.array(qubits, dtype='uint32')
        memory_slots = np.array(memory_slots, dtype='uint32')

        probs = occ_probabilities(qubits, psi, op_system.global_data['measurement_ops'])
        rand_vals = rng.rand(memory_slots.shape[0] * shots)
        write_shots_memory(memory, memory_slots, probs, rand_vals)

        return [memory, psi, ode_t]

    # run simulation on each experiment in parallel
    start = time.time()
    exp_results = parallel_map(full_simulation,
                               op_system.experiments,
                               task_args=(op_system,),
                               **map_kwargs
                               )
    end = time.time()
    exp_times = (np.ones(len(op_system.experiments)) *
                 (end - start) / len(op_system.experiments))

    return exp_results, exp_times
예제 #24
0
def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]],
              backend: Optional[Union[Backend, BaseBackend]] = None,
              basis_gates: Optional[List[str]] = None,
              coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None,
              backend_properties: Optional[BackendProperties] = None,
              initial_layout: Optional[Union[Layout, Dict, List]] = None,
              layout_method: Optional[str] = None,
              routing_method: Optional[str] = None,
              translation_method: Optional[str] = None,
              scheduling_method: Optional[str] = None,
              instruction_durations: Optional[InstructionDurationsType] = None,
              dt: Optional[float] = None,
              seed_transpiler: Optional[int] = None,
              optimization_level: Optional[int] = None,
              pass_manager: Optional[PassManager] = None,
              callback: Optional[Callable[[BasePass, DAGCircuit, float,
                                           PropertySet, int], Any]] = None,
              output_name: Optional[Union[str, List[str]]] = None) -> Union[QuantumCircuit,
                                                                            List[QuantumCircuit]]:
    """Transpile one or more circuits, according to some desired transpilation targets.

    All arguments may be given as either a singleton or list. In case of a list,
    the length must be equal to the number of circuits being transpiled.

    Transpilation is done in parallel using multiprocessing.

    Args:
        circuits: Circuit(s) to transpile
        backend: If set, 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.

            .. note::

                The backend arg is purely for convenience. The resulting
                circuit may be run on any backend as long as it is compatible.
        basis_gates: List of basis gate names to unroll to
            (e.g: ``['u1', 'u2', 'u3', 'cx']``). If ``None``, do not unroll.
        coupling_map: 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: 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: 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:

            #. ``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]]

        layout_method: Name of layout selection pass ('trivial', 'dense', 'noise_adaptive', 'sabre')
        routing_method: Name of routing pass ('basic', 'lookahead', 'stochastic', 'sabre', 'none')
        translation_method: Name of translation pass ('unroller', 'translator', 'synthesis')
        scheduling_method: Name of scheduling pass.
            * ``'as_soon_as_possible'``: Schedule instructions greedily, as early as possible
            on a qubit resource. alias: ``'asap'``)
            * ``'as_late_as_possible'``: Schedule instructions late, i.e. keeping qubits
            in the ground state when possible. (alias: ``'alap'``)
            If ``None``, no scheduling will be done.
        instruction_durations: Durations of instructions.
            The gate lengths defined in ``backend.properties`` are used as default.
            They are overwritten if this ``instruction_durations`` is specified.
            The format of ``instruction_durations`` must be as follows.
            The `instruction_durations` must be given as a list of tuples
            [(instruction_name, qubits, duration, unit), ...].
            | [('cx', [0, 1], 12.3, 'ns'), ('u3', [0], 4.56, 'ns')]
            | [('cx', [0, 1], 1000), ('u3', [0], 300)]
            If unit is omitted, the default is 'dt', which is a sample time depending on backend.
            If the time unit is 'dt', the duration must be an integer.
        dt: Backend sample time (resolution) in seconds.
            If ``None`` (default), ``backend.configuration().dt`` is used.
        seed_transpiler: Sets random seed for the stochastic parts of the transpiler
        optimization_level: How much optimization to perform on the circuits.
            Higher levels generate more optimized circuits,
            at the expense of longer transpilation time.
            * 0: no optimization
            * 1: light optimization
            * 2: heavy optimization
            * 3: even heavier optimization
            If ``None``, level 1 will be chosen as default.
        pass_manager: The pass manager to use for a custom pipeline of transpiler passes.
            If this arg is present, all other args will be ignored and the
            pass manager will be used directly (Qiskit will not attempt to
            auto-select a pass manager based on transpile options).
        callback: A callback function that will be called after each
            pass execution. The function will be called with 5 keyword
            arguments,
            | ``pass_``: the pass being run.
            | ``dag``: the dag output of the pass.
            | ``time``: the time to execute the pass.
            | ``property_set``: the property set.
            | ``count``: the index for the pass execution.
            The exact arguments passed expose the internals of the pass manager,
            and are subject to change as the pass manager internals change. If
            you intend to reuse a callback function over multiple releases, be
            sure to check that the arguments being passed are the same.
            To use the callback feature, define a function that will
            take in kwargs dict and access the variables. For example::

                def callback_func(**kwargs):
                    pass_ = kwargs['pass_']
                    dag = kwargs['dag']
                    time = kwargs['time']
                    property_set = kwargs['property_set']
                    count = kwargs['count']
                    ...
                transpile(circ, callback=callback_func)

        output_name: A list with strings to identify the output circuits. The length of
            the list should be exactly the length of the ``circuits`` parameter.

    Returns:
        The transpiled circuit(s).

    Raises:
        TranspilerError: in case of bad inputs to transpiler (like conflicting parameters)
            or errors in passes
    """
    arg_circuits_list = isinstance(circuits, list)
    circuits = circuits if arg_circuits_list else [circuits]

    # transpiling schedules is not supported yet.
    start_time = time()
    if all(isinstance(c, Schedule) for c in circuits):
        warnings.warn("Transpiling schedules is not supported yet.", UserWarning)
        end_time = time()
        _log_transpile_time(start_time, end_time)
        if arg_circuits_list:
            return circuits
        else:
            return circuits[0]

    if pass_manager is not None:
        _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, layout_method=layout_method,
                                    routing_method=routing_method,
                                    translation_method=translation_method,
                                    backend=backend)

        warnings.warn("The parameter pass_manager in transpile is being deprecated. "
                      "The preferred way to tranpile a circuit using a custom pass manager is"
                      " pass_manager.run(circuit)", DeprecationWarning, stacklevel=2)
        return pass_manager.run(circuits, output_name=output_name, callback=callback)

    if optimization_level is None:
        # Take optimization level from the configuration or 1 as default.
        config = user_config.get_config()
        optimization_level = config.get('transpile_optimization_level', 1)

    if scheduling_method is not None and backend is None and not instruction_durations:
        warnings.warn("When scheduling circuits without backend,"
                      " 'instruction_durations' should be usually provided.",
                      UserWarning)

    # Get transpile_args to configure the circuit transpilation job(s)
    transpile_args = _parse_transpile_args(circuits, backend, basis_gates, coupling_map,
                                           backend_properties, initial_layout,
                                           layout_method, routing_method, translation_method,
                                           scheduling_method, instruction_durations, dt,
                                           seed_transpiler, optimization_level,
                                           callback, output_name)

    _check_circuits_coupling_map(circuits, transpile_args, backend)

    # Transpile circuits in parallel
    circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_args)))

    end_time = time()
    _log_transpile_time(start_time, end_time)

    if arg_circuits_list:
        return circuits
    else:
        return circuits[0]
예제 #25
0
def transpile(
    circuits: Union[QuantumCircuit, List[QuantumCircuit]],
    backend: Optional[Union[Backend, BaseBackend]] = None,
    basis_gates: Optional[List[str]] = None,
    inst_map: Optional[List[InstructionScheduleMap]] = None,
    coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None,
    backend_properties: Optional[BackendProperties] = None,
    initial_layout: Optional[Union[Layout, Dict, List]] = None,
    layout_method: Optional[str] = None,
    routing_method: Optional[str] = None,
    translation_method: Optional[str] = None,
    scheduling_method: Optional[str] = None,
    instruction_durations: Optional[InstructionDurationsType] = None,
    dt: Optional[float] = None,
    approximation_degree: Optional[float] = None,
    timing_constraints: Optional[Dict[str, int]] = None,
    seed_transpiler: Optional[int] = None,
    optimization_level: Optional[int] = None,
    callback: Optional[Callable[
        [BasePass, DAGCircuit, float, PropertySet, int], Any]] = None,
    output_name: Optional[Union[str, List[str]]] = None,
    unitary_synthesis_method: str = "default",
    unitary_synthesis_plugin_config: dict = None,
    target: Target = None,
) -> Union[QuantumCircuit, List[QuantumCircuit]]:
    """Transpile one or more circuits, according to some desired transpilation targets.

    All arguments may be given as either a singleton or list. In case of a list,
    the length must be equal to the number of circuits being transpiled.

    Transpilation is done in parallel using multiprocessing.

    Args:
        circuits: Circuit(s) to transpile
        backend: If set, 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.

            .. note::

                The backend arg is purely for convenience. The resulting
                circuit may be run on any backend as long as it is compatible.
        basis_gates: List of basis gate names to unroll to
            (e.g: ``['u1', 'u2', 'u3', 'cx']``). If ``None``, do not unroll.
        inst_map: Mapping of unrolled gates to pulse schedules. If this is not provided,
            transpiler tries to get from the backend. If any user defined calibration
            is found in the map and this is used in a circuit, transpiler attaches
            the custom gate definition to the circuit. This enables one to flexibly
            override the low-level instruction implementation. This feature is available
            iff the backend supports the pulse gate experiment.
        coupling_map: 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: 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: 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:

            #. ``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]]

        layout_method: Name of layout selection pass ('trivial', 'dense', 'noise_adaptive', 'sabre')
        routing_method: Name of routing pass ('basic', 'lookahead', 'stochastic', 'sabre', 'none')
        translation_method: Name of translation pass ('unroller', 'translator', 'synthesis')
        scheduling_method: Name of scheduling pass.
            * ``'as_soon_as_possible'``: Schedule instructions greedily, as early as possible
            on a qubit resource. (alias: ``'asap'``)
            * ``'as_late_as_possible'``: Schedule instructions late, i.e. keeping qubits
            in the ground state when possible. (alias: ``'alap'``)
            If ``None``, no scheduling will be done.
        instruction_durations: Durations of instructions.
            Applicable only if scheduling_method is specified.
            The gate lengths defined in ``backend.properties`` are used as default.
            They are overwritten if this ``instruction_durations`` is specified.
            The format of ``instruction_durations`` must be as follows.
            The `instruction_durations` must be given as a list of tuples
            [(instruction_name, qubits, duration, unit), ...].
            | [('cx', [0, 1], 12.3, 'ns'), ('u3', [0], 4.56, 'ns')]
            | [('cx', [0, 1], 1000), ('u3', [0], 300)]
            If unit is omitted, the default is 'dt', which is a sample time depending on backend.
            If the time unit is 'dt', the duration must be an integer.
        dt: Backend sample time (resolution) in seconds.
            If ``None`` (default), ``backend.configuration().dt`` is used.
        approximation_degree (float): heuristic dial used for circuit approximation
            (1.0=no approximation, 0.0=maximal approximation)
        timing_constraints: An optional control hardware restriction on instruction time resolution.
            A quantum computer backend may report a set of restrictions, namely:

            - granularity: An integer value representing minimum pulse gate
              resolution in units of ``dt``. A user-defined pulse gate should have
              duration of a multiple of this granularity value.
            - min_length: An integer value representing minimum pulse gate
              length in units of ``dt``. A user-defined pulse gate should be longer
              than this length.
            - pulse_alignment: An integer value representing a time resolution of gate
              instruction starting time. Gate instruction should start at time which
              is a multiple of the alignment value.
            - acquire_alignment: An integer value representing a time resolution of measure
              instruction starting time. Measure instruction should start at time which
              is a multiple of the alignment value.

            This information will be provided by the backend configuration.
            If the backend doesn't have any restriction on the instruction time allocation,
            then ``timing_constraints`` is None and no adjustment will be performed.
        seed_transpiler: Sets random seed for the stochastic parts of the transpiler
        optimization_level: How much optimization to perform on the circuits.
            Higher levels generate more optimized circuits,
            at the expense of longer transpilation time.
            * 0: no optimization
            * 1: light optimization
            * 2: heavy optimization
            * 3: even heavier optimization
            If ``None``, level 1 will be chosen as default.
        callback: A callback function that will be called after each
            pass execution. The function will be called with 5 keyword
            arguments,
            | ``pass_``: the pass being run.
            | ``dag``: the dag output of the pass.
            | ``time``: the time to execute the pass.
            | ``property_set``: the property set.
            | ``count``: the index for the pass execution.
            The exact arguments passed expose the internals of the pass manager,
            and are subject to change as the pass manager internals change. If
            you intend to reuse a callback function over multiple releases, be
            sure to check that the arguments being passed are the same.
            To use the callback feature, define a function that will
            take in kwargs dict and access the variables. For example::

                def callback_func(**kwargs):
                    pass_ = kwargs['pass_']
                    dag = kwargs['dag']
                    time = kwargs['time']
                    property_set = kwargs['property_set']
                    count = kwargs['count']
                    ...
                transpile(circ, callback=callback_func)

        output_name: A list with strings to identify the output circuits. The length of
            the list should be exactly the length of the ``circuits`` parameter.
        unitary_synthesis_method (str): The name of the unitary synthesis
            method to use. By default 'default' is used, which is the only
            method included with qiskit. If you have installed any unitary
            synthesis plugins you can use the name exported by the plugin.
        unitary_synthesis_plugin_config: An optional configuration dictionary
            that will be passed directly to the unitary synthesis plugin. By
            default this setting will have no effect as the default unitary
            synthesis method does not take custom configuration. This should
            only be necessary when a unitary synthesis plugin is specified with
            the ``unitary_synthesis`` argument. As this is custom for each
            unitary synthesis plugin refer to the plugin documentation for how
            to use this option.
        target: A backend transpiler target. Normally this is specified as part of
            the ``backend`` argument, but if you have manually constructed a
            :class:`~qiskit.transpiler.Target` object you can specify it manually here.
            This will override the target from ``backend``.
    Returns:
        The transpiled circuit(s).

    Raises:
        TranspilerError: in case of bad inputs to transpiler (like conflicting parameters)
            or errors in passes
    """
    arg_circuits_list = isinstance(circuits, list)
    circuits = circuits if arg_circuits_list else [circuits]

    if not circuits:
        return []

    # transpiling schedules is not supported yet.
    start_time = time()
    if all(isinstance(c, Schedule) for c in circuits):
        warnings.warn("Transpiling schedules is not supported yet.",
                      UserWarning)
        end_time = time()
        _log_transpile_time(start_time, end_time)
        if arg_circuits_list:
            return circuits
        else:
            return circuits[0]

    if optimization_level is None:
        # Take optimization level from the configuration or 1 as default.
        config = user_config.get_config()
        optimization_level = config.get("transpile_optimization_level", 1)

    if (scheduling_method is not None and backend is None and target is None
            and not instruction_durations):
        warnings.warn(
            "When scheduling circuits without backend,"
            " 'instruction_durations' should be usually provided.",
            UserWarning,
        )

    # Get transpile_args to configure the circuit transpilation job(s)
    transpile_args = _parse_transpile_args(
        circuits,
        backend,
        basis_gates,
        inst_map,
        coupling_map,
        backend_properties,
        initial_layout,
        layout_method,
        routing_method,
        translation_method,
        scheduling_method,
        instruction_durations,
        dt,
        approximation_degree,
        seed_transpiler,
        optimization_level,
        callback,
        output_name,
        timing_constraints,
        unitary_synthesis_method,
        unitary_synthesis_plugin_config,
        target,
    )

    _check_circuits_coupling_map(circuits, transpile_args, backend)

    # Transpile circuits in parallel
    circuits = parallel_map(_transpile_circuit,
                            list(zip(circuits, transpile_args)))

    end_time = time()
    _log_transpile_time(start_time, end_time)

    if arg_circuits_list:
        return circuits
    else:
        return circuits[0]
예제 #26
0
def transpile(circuits,
              backend=None,
              basis_gates=None,
              coupling_map=None,
              backend_properties=None,
              initial_layout=None,
              seed_transpiler=None,
              optimization_level=None,
              pass_manager=None):
    """transpile one or more circuits, according to some desired
    transpilation targets.

    All arguments may be given as either singleton or list. In case of list,
    the length must be equal to the number of circuits being transpiled.

    Transpilation is done in parallel using multiprocessing.

    Args:
        circuits (QuantumCircuit or list[QuantumCircuit]):
            Circuit(s) to transpile

        backend (BaseBackend):
            If set, 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.
            Note: the backend arg is purely for convenience. The resulting
                circuit may be run on any backend as long as it is compatible.

        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:
            a. CouplingMap instance

            b. 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. For a backend
            that provides this information, it can be obtained 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:
            a. Layout instance

            b. 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]}

            c. 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.
                0: no optimization
                1: light optimization
                2: heavy optimization
                3: even heavier optimization

        pass_manager (PassManager):
            The pass manager to use for a custom pipeline of transpiler passes.
            If this arg is present, all other args will be ignored and the
            pass manager will be used directly (Qiskit will not attempt to
            auto-select a pass manager based on transpile options).


    Returns:
        QuantumCircuit or list[QuantumCircuit]: transpiled circuit(s).

    Raises:
        TranspilerError: in case of bad inputs to transpiler or errors in passes
    """

    # transpiling schedules is not supported yet.
    if isinstance(circuits, Schedule) or \
       (isinstance(circuits, list) and all(isinstance(c, Schedule) for c in circuits)):
        return circuits

    if optimization_level is None:
        config = user_config.get_config()
        optimization_level = config.get('transpile_optimization_level', None)

    # Get TranspileConfig(s) to configure the circuit transpilation job(s)
    circuits = circuits if isinstance(circuits, list) else [circuits]
    transpile_configs = _parse_transpile_args(circuits, backend, basis_gates,
                                              coupling_map, backend_properties,
                                              initial_layout, seed_transpiler,
                                              optimization_level, pass_manager)
    # Check circuit width against number of qubits in coupling_map(s)
    coupling_maps_list = list(config.coupling_map
                              for config in transpile_configs)
    for circuit, parsed_coupling_map in zip(circuits, coupling_maps_list):
        # If coupling_map is not None
        if isinstance(parsed_coupling_map, CouplingMap):
            n_qubits = len(circuit.qubits)
            max_qubits = parsed_coupling_map.size()
            if n_qubits > max_qubits:
                raise TranspilerError(
                    'Number of qubits ({}) '.format(n_qubits) +
                    'in {} '.format(circuit.name) +
                    'is greater than maximum ({}) '.format(max_qubits) +
                    'in the coupling_map')
    # Transpile circuits in parallel
    circuits = parallel_map(_transpile_circuit,
                            list(zip(circuits, transpile_configs)))

    if len(circuits) == 1:
        return circuits[0]
    return circuits
예제 #27
0
def transpile(circuits,
              backend=None,
              basis_gates=None,
              coupling_map=None,
              backend_properties=None,
              initial_layout=None,
              seed_transpiler=None,
              optimization_level=None,
              pass_manager=None,
              callback=None,
              output_name=None):
    """Transpile one or more circuits, according to some desired transpilation targets.

    All arguments may be given as either singleton or list. In case of list,
    the length must be equal to the number of circuits being transpiled.

    Transpilation is done in parallel using multiprocessing.

    Args:
        circuits (QuantumCircuit or list[QuantumCircuit]):
            Circuit(s) to transpile

        backend (BaseBackend):
            If set, 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.

            Note: the backend arg is purely for convenience. The resulting
            circuit may be run on any backend as long as it is compatible.

        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:

            1. CouplingMap instance
            2. 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. For a backend
            that provides this information, it can be obtained 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:

            1. Layout instance
            2. 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]}

            3. 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.

                * 0: no optimization
                * 1: light optimization
                * 2: heavy optimization
                * 3: even heavier optimization

            If None, level 1 will be chosen as default.

        pass_manager (PassManager):
            The pass manager to use for a custom pipeline of transpiler passes.
            If this arg is present, all other args will be ignored and the
            pass manager will be used directly (Qiskit will not attempt to
            auto-select a pass manager based on transpile options).

        callback (func):
            A callback function that will be called after each
            pass execution. The function will be called with 5 keyword
            arguments:
                pass_ (Pass): the pass being run
                dag (DAGCircuit): the dag output of the pass
                time (float): the time to execute the pass
                property_set (PropertySet): the property set
                count (int): the index for the pass execution

            The exact arguments pass expose the internals of the pass manager
            and are subject to change as the pass manager internals change. If
            you intend to reuse a callback function over multiple releases be
            sure to check that the arguments being passed are the same.

            To use the callback feature you define a function that will
            take in kwargs dict and access the variables. For example::

                def callback_func(**kwargs):
                    pass_ = kwargs['pass_']
                    dag = kwargs['dag']
                    time = kwargs['time']
                    property_set = kwargs['property_set']
                    count = kwargs['count']
                    ...

                transpile(circ, callback=callback_func)

        output_name (str or list[str]) :
            A list with strings to identify the output circuits. The length of
            `list[str]` should be exactly the length of `circuits` parameter.

    Returns:
        QuantumCircuit or list[QuantumCircuit]: transpiled circuit(s).

    Raises:
        TranspilerError: in case of bad inputs to transpiler or errors in passes
    """
    # transpiling schedules is not supported yet.
    if isinstance(circuits, Schedule) or \
            (isinstance(circuits, list) and all(isinstance(c, Schedule) for c in circuits)):
        return circuits

    if optimization_level is None:
        config = user_config.get_config()
        optimization_level = config.get('transpile_optimization_level', None)

    # Get TranspileConfig(s) to configure the circuit transpilation job(s)
    circuits = circuits if isinstance(circuits, list) else [circuits]
    transpile_configs = _parse_transpile_args(circuits, backend, basis_gates,
                                              coupling_map, backend_properties,
                                              initial_layout, seed_transpiler,
                                              optimization_level, pass_manager,
                                              callback, output_name)
    # Check circuit width against number of qubits in coupling_map(s)
    coupling_maps_list = list(config.coupling_map
                              for config in transpile_configs)
    for circuit, parsed_coupling_map in zip(circuits, coupling_maps_list):
        # If coupling_map is not None or n_qubits == 1
        n_qubits = len(circuit.qubits)
        max_qubits = None
        if isinstance(parsed_coupling_map, CouplingMap):
            max_qubits = parsed_coupling_map.size()

        # If coupling_map is None, the limit might be in the backend (like in 1Q devices)
        elif backend is not None and not backend.configuration().simulator:
            max_qubits = backend.configuration().n_qubits

        if max_qubits is not None and (n_qubits > max_qubits):
            raise TranspilerError(
                'Number of qubits ({}) '.format(n_qubits) +
                'in {} '.format(circuit.name) +
                'is greater than maximum ({}) '.format(max_qubits) +
                'in the coupling_map')
    # Transpile circuits in parallel
    circuits = parallel_map(_transpile_circuit,
                            list(zip(circuits, transpile_configs)))

    if len(circuits) == 1:
        return circuits[0]
    return circuits