mirror of https://github.com/Qiskit/qiskit.git
Circuits to qobj (#1629)
* Removing qobj dependencies in qobjconfig * Adding to rebase * Removing unrolls * Linting * Fixing last test * Updating the schema * Linting that makes no sense * Diego updates * Linting * Update qiskit/tools/compiler.py Co-Authored-By: jaygambetta <jay.gambetta@us.ibm.com> * Update qiskit/qobj/run_config.py Co-Authored-By: jaygambetta <jay.gambetta@us.ibm.com> * update warning messages. remove init from RunConfig as all optional * only put optional shots, max_credits, memory in qobj if they are set
This commit is contained in:
parent
95fbde842d
commit
2ea7d176ea
|
@ -19,6 +19,11 @@ The format is based on `Keep a Changelog`_.
|
|||
|
||||
`UNRELEASED`_
|
||||
=============
|
||||
Added
|
||||
-----
|
||||
|
||||
- Added a RunConfig object for configurations for run configurations to be used
|
||||
in compile and circuits_to_qobj. (#1629)
|
||||
|
||||
Changed
|
||||
-------
|
||||
|
@ -30,6 +35,8 @@ Changed
|
|||
- The snapshot instruction now takes ``label`` and ``snap_type`` instead of
|
||||
``slot`` (#1615).
|
||||
- The test folders have been reorganized to match the python modules (#1625)
|
||||
- The circuits_to_qobj no longers uses the unrollers (#1629)
|
||||
|
||||
|
||||
Fixed
|
||||
-----
|
||||
|
@ -46,6 +53,7 @@ Removed
|
|||
- Removed simulator instructions ``save``, ``load``, ``wait``, ``noise``
|
||||
as unsupported in Aer (#1615).
|
||||
- Removed circuit.add as deprecated (#1627)
|
||||
- Removed the unroller (#1629)
|
||||
|
||||
`0.7.0`_ - 2018-12-19
|
||||
=====================
|
||||
|
|
|
@ -5,104 +5,148 @@
|
|||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""Helper function for converting a list of circuits to a qobj"""
|
||||
from copy import deepcopy
|
||||
"""Compile function for converting a list of circuits to the qobj"""
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
from qiskit.qobj import Qobj, QobjConfig, QobjExperiment, QobjItem, QobjHeader
|
||||
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
||||
from qiskit.qobj import Qobj, QobjConfig, QobjExperiment, QobjInstruction, QobjHeader
|
||||
from qiskit.qobj import QobjExperimentConfig, QobjExperimentHeader, QobjConditional
|
||||
from qiskit.qobj.run_config import RunConfig
|
||||
|
||||
|
||||
def circuits_to_qobj(circuits, backend_name, config=None, shots=1024,
|
||||
max_credits=10, qobj_id=None, basis_gates=None, coupling_map=None,
|
||||
seed=None, memory=False):
|
||||
def circuits_to_qobj(circuits, user_qobj_header=None, run_config=None,
|
||||
qobj_id=None, backend_name=None,
|
||||
config=None, shots=None, max_credits=None,
|
||||
basis_gates=None,
|
||||
coupling_map=None, seed=None, memory=None):
|
||||
"""Convert a list of circuits into a qobj.
|
||||
|
||||
Args:
|
||||
circuits (list[QuantumCircuits] or QuantumCircuit): circuits to compile
|
||||
backend_name (str): name of runner backend
|
||||
config (dict): dictionary of parameters (e.g. noise) used by runner
|
||||
shots (int): number of repetitions of each circuit, for sampling
|
||||
max_credits (int): maximum credits to use
|
||||
user_qobj_header (QobjHeader): header to pass to the results
|
||||
run_config (RunConfig): RunConfig object
|
||||
qobj_id (int): identifier for the generated qobj
|
||||
basis_gates (list[str])): basis gates for the experiment
|
||||
coupling_map (list): coupling map (perhaps custom) to target in mapping
|
||||
seed (int): random seed for simulators
|
||||
memory (bool): if True, per-shot measurement bitstrings are returned as well
|
||||
|
||||
backend_name (str): TODO: delete after qiskit-terra 0.8
|
||||
config (dict): TODO: delete after qiskit-terra 0.8
|
||||
shots (int): TODO: delete after qiskit-terra 0.8
|
||||
max_credits (int): TODO: delete after qiskit-terra 0.8
|
||||
basis_gates (str): TODO: delete after qiskit-terra 0.8
|
||||
coupling_map (list): TODO: delete after qiskit-terra 0.8
|
||||
seed (int): TODO: delete after qiskit-terra 0.8
|
||||
memory (bool): TODO: delete after qiskit-terra 0.8
|
||||
|
||||
Returns:
|
||||
Qobj: the Qobj to be run on the backends
|
||||
"""
|
||||
# TODO: the following will be removed from qobj and thus removed here:
|
||||
# `basis_gates`, `coupling_map`
|
||||
|
||||
# Step 1: create the Qobj, with empty experiments.
|
||||
# Copy the configuration: the values in `config` have preference
|
||||
qobj_config = deepcopy(config or {})
|
||||
qobj_config.update({'shots': shots,
|
||||
'max_credits': max_credits,
|
||||
'memory_slots': 0,
|
||||
'memory': memory})
|
||||
|
||||
qobj = Qobj(qobj_id=qobj_id or str(uuid.uuid4()),
|
||||
config=QobjConfig(**qobj_config),
|
||||
experiments=[],
|
||||
header=QobjHeader(backend_name=backend_name))
|
||||
if seed:
|
||||
qobj.config.seed = seed
|
||||
|
||||
user_qobj_header = user_qobj_header or QobjHeader()
|
||||
run_config = run_config or RunConfig()
|
||||
if isinstance(circuits, QuantumCircuit):
|
||||
circuits = [circuits]
|
||||
|
||||
if backend_name:
|
||||
warnings.warn('backend_name is not required anymore', DeprecationWarning)
|
||||
user_qobj_header.backend_name = backend_name
|
||||
if config:
|
||||
warnings.warn('config is not used anymore. Set all configs in '
|
||||
'run_config.', DeprecationWarning)
|
||||
if shots:
|
||||
warnings.warn('shots is not used anymore. Set it via run_config.', DeprecationWarning)
|
||||
run_config.shots = shots
|
||||
if basis_gates:
|
||||
warnings.warn('basis_gates was unused and will be removed.', DeprecationWarning)
|
||||
if coupling_map:
|
||||
warnings.warn('coupling_map was unused and will be removed.', DeprecationWarning)
|
||||
if seed:
|
||||
warnings.warn('seed is not used anymore. Set it via run_config', DeprecationWarning)
|
||||
run_config.seed = seed
|
||||
if memory:
|
||||
warnings.warn('memory is not used anymore. Set it via run_config', DeprecationWarning)
|
||||
run_config.memory = memory
|
||||
if max_credits:
|
||||
warnings.warn('max_credits is not used anymore. Set it via run_config', DeprecationWarning)
|
||||
run_config.max_credits = max_credits
|
||||
|
||||
userconfig = QobjConfig(**run_config.to_dict())
|
||||
experiments = []
|
||||
max_n_qubits = 0
|
||||
max_memory_slots = 0
|
||||
for circuit in circuits:
|
||||
qobj.experiments.append(_circuit_to_experiment(circuit,
|
||||
config,
|
||||
basis_gates,
|
||||
coupling_map))
|
||||
# header stuff
|
||||
n_qubits = 0
|
||||
memory_slots = 0
|
||||
qubit_labels = []
|
||||
clbit_labels = []
|
||||
|
||||
# Update the global `memory_slots` and `n_qubits` values.
|
||||
qobj.config.memory_slots = max(experiment.config.memory_slots for
|
||||
experiment in qobj.experiments)
|
||||
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])
|
||||
n_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
|
||||
|
||||
qobj.config.n_qubits = max(experiment.config.n_qubits for
|
||||
experiment in qobj.experiments)
|
||||
# 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
|
||||
# TODO: when no more backends use the compiled_circuit_qasm lets delete it form header
|
||||
experimentheader = QobjExperimentHeader(qubit_labels=qubit_labels,
|
||||
n_qubits=n_qubits,
|
||||
qreg_sizes=qreg_sizes,
|
||||
clbit_labels=clbit_labels,
|
||||
memory_slots=memory_slots,
|
||||
creg_sizes=creg_sizes,
|
||||
name=circuit.name,
|
||||
compiled_circuit_qasm=circuit.qasm())
|
||||
# TODO: why do we need n_qubits and memory_slots in both the header and the config
|
||||
experimentconfig = QobjExperimentConfig(n_qubits=n_qubits, memory_slots=memory_slots)
|
||||
|
||||
return qobj
|
||||
instructions = []
|
||||
for opt in circuit.data:
|
||||
current_instruction = QobjInstruction(name=opt.name)
|
||||
if opt.qargs:
|
||||
qubit_indices = [qubit_labels.index([qubit[0].name, qubit[1]])
|
||||
for qubit in opt.qargs]
|
||||
current_instruction.qubits = qubit_indices
|
||||
if opt.cargs:
|
||||
clbit_indices = [clbit_labels.index([clbit[0].name, clbit[1]])
|
||||
for clbit in opt.cargs]
|
||||
current_instruction.memory = clbit_indices
|
||||
# TODO: we are not constant with params vs param
|
||||
if opt.param:
|
||||
params = list(map(lambda x: x.evalf(), opt.param))
|
||||
current_instruction.params = params
|
||||
|
||||
# TODO: I really dont like this for snapshot. I also think we should change
|
||||
# type to snap_type
|
||||
if opt.name == "snapshot":
|
||||
current_instruction.label = str(opt.param[0])
|
||||
current_instruction.type = str(opt.param[1])
|
||||
if opt.control:
|
||||
mask = 0
|
||||
for clbit in clbit_labels:
|
||||
if clbit[0] == opt.control[0].name:
|
||||
mask |= (1 << clbit_labels.index(clbit))
|
||||
|
||||
def _circuit_to_experiment(circuit, config=None, basis_gates=None,
|
||||
coupling_map=None):
|
||||
"""Helper function for dags to qobj in parallel (if available).
|
||||
current_instruction.conditional = QobjConditional(mask="0x%X" % mask,
|
||||
type='equals',
|
||||
val="0x%X" % opt.control[1])
|
||||
|
||||
Args:
|
||||
circuit (QuantumCircuit): QuantumCircuit to convert into qobj experiment
|
||||
config (dict): dictionary of parameters (e.g. noise) used by runner
|
||||
basis_gates (list[str])): basis gates for the experiment
|
||||
coupling_map (list): coupling map (perhaps custom) to target in mapping
|
||||
instructions.append(current_instruction)
|
||||
experiments.append(QobjExperiment(instructions=instructions, header=experimentheader,
|
||||
config=experimentconfig))
|
||||
if n_qubits > max_n_qubits:
|
||||
max_n_qubits = n_qubits
|
||||
if memory_slots > max_memory_slots:
|
||||
max_memory_slots = memory_slots
|
||||
|
||||
Returns:
|
||||
Qobj: Qobj to be run on the backends
|
||||
"""
|
||||
# pylint: disable=unused-argument
|
||||
# TODO: if arguments are really unused, consider changing the signature
|
||||
# TODO: removed the DAG from this function
|
||||
from qiskit.converters import circuit_to_dag
|
||||
from qiskit.unroll import DagUnroller, JsonBackend
|
||||
dag = circuit_to_dag(circuit)
|
||||
json_circuit = DagUnroller(dag, JsonBackend(dag.basis)).execute()
|
||||
# Step 3a: create the Experiment based on json_circuit
|
||||
experiment = QobjExperiment.from_dict(json_circuit)
|
||||
# Step 3b: populate the Experiment configuration and header
|
||||
experiment.header.name = circuit.name
|
||||
experiment_config = deepcopy(config or {})
|
||||
experiment_config.update({
|
||||
'memory_slots': sum([creg.size for creg in dag.cregs.values()]),
|
||||
'n_qubits': sum([qreg.size for qreg in dag.qregs.values()])
|
||||
})
|
||||
experiment.config = QobjItem(**experiment_config)
|
||||
userconfig.memory_slots = max_memory_slots
|
||||
userconfig.n_qubits = max_n_qubits
|
||||
|
||||
# set eval_symbols=True to evaluate each symbolic expression
|
||||
# TODO: after transition to qobj, we can drop this
|
||||
experiment.header.compiled_circuit_qasm = circuit.qasm()
|
||||
# Step 3c: add the Experiment to the Qobj
|
||||
return experiment
|
||||
return Qobj(qobj_id=qobj_id or str(uuid.uuid4()), config=userconfig,
|
||||
experiments=experiments, header=user_qobj_header)
|
||||
|
|
|
@ -12,6 +12,7 @@ from qiskit.circuit import quantumcircuit as qc
|
|||
from qiskit.circuit import quantumregister as qr
|
||||
|
||||
|
||||
# TODO: This is broken for conditionals. Will fix after circuits_2_qobj pr
|
||||
def qobj_to_circuits(qobj):
|
||||
"""Return a list of QuantumCircuit object(s) from a qobj
|
||||
|
||||
|
@ -42,19 +43,30 @@ def qobj_to_circuits(qobj):
|
|||
for i in x.instructions:
|
||||
instr_method = getattr(circuit, i.name)
|
||||
qubits = []
|
||||
try:
|
||||
for qubit in i.qubits:
|
||||
qubit_label = x.header.qubit_labels[qubit]
|
||||
qubits.append(
|
||||
qreg_dict[qubit_label[0]][qubit_label[1]])
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
clbits = []
|
||||
try:
|
||||
for clbit in i.memory:
|
||||
clbit_label = x.header.clbit_labels[clbit]
|
||||
clbits.append(
|
||||
creg_dict[clbit_label[0]][clbit_label[1]])
|
||||
if i.name in ['snapshot', 'save', 'load', 'noise']:
|
||||
instr_method(*i.params)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
params = []
|
||||
try:
|
||||
params = i.params
|
||||
except Exception: # pylint: disable=broad-except
|
||||
pass
|
||||
if i.name in ['snapshot']:
|
||||
instr_method(*params)
|
||||
else:
|
||||
instr_method(*i.params, *qubits, *clbits)
|
||||
instr_method(*params, *qubits, *clbits)
|
||||
circuits.append(circuit)
|
||||
return circuits
|
||||
return None
|
||||
|
|
|
@ -396,7 +396,7 @@ class QasmSimulatorPy(BaseBackend):
|
|||
self._validate(qobj)
|
||||
result_list = []
|
||||
self._shots = qobj.config.shots
|
||||
self._memory = qobj.config.memory
|
||||
self._memory = getattr(qobj.config, 'memory', False)
|
||||
self._qobj_config = qobj.config
|
||||
start = time.time()
|
||||
for experiment in qobj.experiments:
|
||||
|
@ -456,7 +456,8 @@ class QasmSimulatorPy(BaseBackend):
|
|||
# For compatibility on Windows force dyte to be int32
|
||||
# and set the maximum value to be (2 ** 31) - 1
|
||||
seed = np.random.randint(2147483647, dtype='int32')
|
||||
self._local_random.seed(seed)
|
||||
|
||||
self._local_random.seed(seed=seed)
|
||||
# Check if measure sampling is supported for current circuit
|
||||
self._validate_measure_sampling(experiment)
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
"""Module for the Qobj structure."""
|
||||
|
||||
from ._qobj import (Qobj, QobjConfig, QobjExperiment, QobjInstruction,
|
||||
QobjItem, QobjHeader, QobjExperimentHeader)
|
||||
from .qobj import (Qobj, QobjConfig, QobjExperiment, QobjInstruction, QobjItem,
|
||||
QobjHeader, QobjExperimentHeader, QobjConditional, QobjExperimentConfig)
|
||||
from ._converter import qobj_to_dict
|
||||
from ._validation import validate_qobj_against_schema
|
||||
from .exceptions import QobjValidationError
|
||||
from .run_config import RunConfig
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import logging
|
||||
|
||||
from qiskit.exceptions import QiskitError
|
||||
from ._qobj import QOBJ_VERSION
|
||||
from ._qobj import QobjItem
|
||||
from .qobj import QOBJ_VERSION
|
||||
from .qobj import QobjItem
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
@ -138,27 +138,6 @@ class Qobj(QobjItem):
|
|||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class QobjConfig(QobjItem):
|
||||
"""Configuration for a Qobj.
|
||||
|
||||
Attributes:
|
||||
shots (int): number of shots.
|
||||
memory_slots (int): number of measurements slots in the classical
|
||||
memory on the backend.
|
||||
|
||||
Attributes defined in the schema but not required:
|
||||
max_credits (int): number of credits.
|
||||
seed (int): random seed.
|
||||
"""
|
||||
REQUIRED_ARGS = ['shots', 'memory_slots']
|
||||
|
||||
def __init__(self, shots, memory_slots, **kwargs):
|
||||
self.shots = shots
|
||||
self.memory_slots = memory_slots
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class QobjHeader(QobjItem):
|
||||
"""Header for a Qobj.
|
||||
|
||||
|
@ -171,6 +150,21 @@ class QobjHeader(QobjItem):
|
|||
pass
|
||||
|
||||
|
||||
class QobjConfig(QobjItem):
|
||||
"""Configuration for a Qobj.
|
||||
|
||||
Attributes:
|
||||
None should be required
|
||||
Attributes defined in the schema but not required:
|
||||
max_credits (int): number of credits.
|
||||
seed (int): random seed.
|
||||
memory_slots (int): number of measurements slots in the classical
|
||||
memory on the backend.
|
||||
shots (int): number of shots.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class QobjExperiment(QobjItem):
|
||||
"""Quantum experiment represented inside a Qobj.
|
||||
|
||||
|
@ -189,7 +183,7 @@ class QobjExperiment(QobjItem):
|
|||
|
||||
|
||||
class QobjExperimentHeader(QobjItem):
|
||||
"""Header for a Qobj.
|
||||
"""Header for a Qobj Experiment .
|
||||
|
||||
Attributes defined in the schema but not required:
|
||||
name (str): experiment name.
|
||||
|
@ -197,12 +191,23 @@ class QobjExperimentHeader(QobjItem):
|
|||
pass
|
||||
|
||||
|
||||
class QobjExperimentConfig(QobjItem):
|
||||
"""Config for a Qobj Experiment.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class QobjInstruction(QobjItem):
|
||||
"""Quantum Instruction.
|
||||
|
||||
Attributes:
|
||||
name(str): name of the gate.
|
||||
qubits(list): list of qubits to apply to the gate.
|
||||
name(str): name of the operation.
|
||||
Optional Attributes:
|
||||
qubits(list): list of qubits to apply to the operation.
|
||||
params(list): list of params for the operation.
|
||||
memory(list): list of memory to apply to the operation.
|
||||
conditional(QobjConditional): conditional Qobj
|
||||
"""
|
||||
REQUIRED_ARGS = ['name']
|
||||
|
||||
|
@ -210,3 +215,22 @@ class QobjInstruction(QobjItem):
|
|||
self.name = name
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class QobjConditional(QobjItem):
|
||||
"""Quantum Conditional.
|
||||
|
||||
Attributes:
|
||||
mask (hex): mask of the conditional
|
||||
type (string): type of the conditional
|
||||
val (hex): value of the conditional
|
||||
"""
|
||||
# pylint: disable=redefined-builtin
|
||||
REQUIRED_ARGS = ['mask', 'type', 'val']
|
||||
|
||||
def __init__(self, mask, type, val):
|
||||
self.mask = mask
|
||||
self.type = type
|
||||
self.val = val
|
||||
|
||||
super().__init__()
|
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2018, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""Models for RunConfig and its related components."""
|
||||
from marshmallow.validate import Range
|
||||
|
||||
from qiskit.validation import BaseModel, BaseSchema, bind_schema
|
||||
from qiskit.validation.fields import Boolean, Integer
|
||||
|
||||
|
||||
class RunConfigSchema(BaseSchema):
|
||||
"""Schema for RunConfig."""
|
||||
|
||||
# Required properties.
|
||||
# None
|
||||
|
||||
# Optional properties.
|
||||
shots = Integer(validate=Range(min=1))
|
||||
max_credits = Integer(validate=Range(min=3, max=10)) # TODO: can we check the range
|
||||
seed = Integer()
|
||||
memory = Boolean() # set default to be False
|
||||
|
||||
|
||||
@bind_schema(RunConfigSchema)
|
||||
class RunConfig(BaseModel):
|
||||
"""Model for RunConfig.
|
||||
|
||||
Please note that this class only describes the required fields. For the
|
||||
full description of the model, please check ``RunConfigSchema``.
|
||||
|
||||
Attributes:
|
||||
shots (int): the number of shots.
|
||||
max_credits (int): the max_credits to use on the IBMQ public devices.
|
||||
seed (int): the seed to use in the simulator for the first experiment.
|
||||
memory (bool): to use memory.
|
||||
"""
|
|
@ -887,9 +887,6 @@
|
|||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"shots"
|
||||
],
|
||||
"title": "Qobj-level configuration",
|
||||
"type": "object"
|
||||
},
|
||||
|
|
|
@ -10,9 +10,10 @@ import warnings
|
|||
import logging
|
||||
|
||||
from qiskit import transpiler
|
||||
from qiskit.transpiler._passmanager import PassManager
|
||||
from qiskit.converters import circuits_to_qobj
|
||||
from qiskit.exceptions import QiskitError
|
||||
from qiskit.qobj import RunConfig
|
||||
from qiskit.qobj import QobjHeader
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,8 +21,8 @@ logger = logging.getLogger(__name__)
|
|||
# pylint: disable=redefined-builtin
|
||||
def compile(circuits, backend,
|
||||
config=None, basis_gates=None, coupling_map=None, initial_layout=None,
|
||||
shots=1024, max_credits=10, seed=None, qobj_id=None,
|
||||
skip_transpiler=False, seed_mapper=None, pass_manager=None, memory=False):
|
||||
shots=1024, max_credits=10, seed=None, qobj_id=None, seed_mapper=None,
|
||||
pass_manager=None, memory=False):
|
||||
"""Compile a list of circuits into a qobj.
|
||||
|
||||
Args:
|
||||
|
@ -38,7 +39,6 @@ def compile(circuits, backend,
|
|||
qobj_id (int): identifier for the generated qobj
|
||||
pass_manager (PassManager): a pass manger for the transpiler pipeline
|
||||
memory (bool): if True, per-shot measurement bitstrings are returned as well
|
||||
skip_transpiler (bool): DEPRECATED skip transpiler and create qobj directly
|
||||
|
||||
Returns:
|
||||
Qobj: the qobj to be run on the backends
|
||||
|
@ -46,32 +46,33 @@ def compile(circuits, backend,
|
|||
Raises:
|
||||
QiskitError: if the desired options are not supported by backend
|
||||
"""
|
||||
if skip_transpiler: # empty pass manager which does nothing
|
||||
pass_manager = PassManager()
|
||||
warnings.warn('The skip_transpiler option has been deprecated. '
|
||||
'Please pass an empty PassManager() instance instead',
|
||||
DeprecationWarning)
|
||||
|
||||
backend_memory = getattr(backend.configuration(), 'memory', False)
|
||||
if memory and not backend_memory:
|
||||
raise QiskitError("Backend %s only returns total counts, not single-shot memory." %
|
||||
backend.name())
|
||||
if config:
|
||||
warnings.warn('The `config` argument is deprecated and '
|
||||
'does not do anything', DeprecationWarning)
|
||||
|
||||
circuits = transpiler.transpile(circuits, backend, basis_gates, coupling_map, initial_layout,
|
||||
seed_mapper, pass_manager)
|
||||
|
||||
# step 4: Making a qobj
|
||||
qobj = circuits_to_qobj(circuits, backend_name=backend.name(),
|
||||
config=config, shots=shots, max_credits=max_credits,
|
||||
qobj_id=qobj_id, basis_gates=basis_gates,
|
||||
coupling_map=coupling_map, seed=seed, memory=memory)
|
||||
run_config = RunConfig()
|
||||
|
||||
if seed:
|
||||
run_config.seed = seed
|
||||
if shots:
|
||||
run_config.shots = shots
|
||||
if max_credits:
|
||||
run_config.max_credits = max_credits
|
||||
if memory:
|
||||
run_config.memory = memory
|
||||
qobj = circuits_to_qobj(circuits, user_qobj_header=QobjHeader(), run_config=run_config,
|
||||
qobj_id=qobj_id)
|
||||
|
||||
return qobj
|
||||
|
||||
|
||||
def execute(circuits, backend, config=None, basis_gates=None, coupling_map=None,
|
||||
initial_layout=None, shots=1024, max_credits=10, seed=None,
|
||||
qobj_id=None, skip_transpiler=False, seed_mapper=None, pass_manager=None,
|
||||
qobj_id=None, seed_mapper=None, pass_manager=None,
|
||||
memory=False, **kwargs):
|
||||
"""Executes a set of circuits.
|
||||
|
||||
|
@ -89,22 +90,16 @@ def execute(circuits, backend, config=None, basis_gates=None, coupling_map=None,
|
|||
qobj_id (int): identifier for the generated qobj
|
||||
pass_manager (PassManager): a pass manger for the transpiler pipeline
|
||||
memory (bool): if True, per-shot measurement bitstrings are returned as well.
|
||||
skip_transpiler (bool): DEPRECATED skip transpiler and create qobj directly
|
||||
kwargs: extra arguments used by AER for running configurable backends.
|
||||
Refer to the backend documentation for details on these arguments
|
||||
|
||||
Returns:
|
||||
BaseJob: returns job instance derived from BaseJob
|
||||
"""
|
||||
if skip_transpiler: # empty pass manager which does nothing
|
||||
pass_manager = PassManager()
|
||||
warnings.warn('The skip_transpiler option has been deprecated. '
|
||||
'Please pass an empty PassManager() instance instead',
|
||||
DeprecationWarning)
|
||||
|
||||
qobj = compile(circuits, backend,
|
||||
config, basis_gates, coupling_map, initial_layout,
|
||||
shots, max_credits, seed, qobj_id,
|
||||
skip_transpiler, seed_mapper, pass_manager, memory)
|
||||
shots, max_credits, seed, qobj_id, seed_mapper,
|
||||
pass_manager, memory)
|
||||
|
||||
return backend.run(qobj, **kwargs)
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
# pylint: disable=unused-import
|
||||
|
||||
|
||||
"""Unroll QASM and different backends."""
|
||||
from qiskit.unrollers.exceptions import BackendError
|
||||
from qiskit.unrollers._dagunroller import DagUnroller
|
||||
from qiskit.unrollers._unrollerbackend import UnrollerBackend
|
||||
from qiskit.unrollers._jsonbackend import JsonBackend
|
|
@ -1,90 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""
|
||||
DAG Unroller
|
||||
"""
|
||||
|
||||
import networkx as nx
|
||||
|
||||
from .exceptions import UnrollerError
|
||||
|
||||
|
||||
class DagUnroller:
|
||||
"""An Unroller that takes Dag circuits as the input."""
|
||||
|
||||
def __init__(self, dag_circuit, backend=None):
|
||||
if dag_circuit is None:
|
||||
raise UnrollerError('Invalid dag circuit!!')
|
||||
|
||||
self.dag_circuit = dag_circuit
|
||||
self.set_backend(backend)
|
||||
|
||||
def set_backend(self, backend):
|
||||
"""Set the backend object.
|
||||
|
||||
Give the same gate definitions to the backend circuit as
|
||||
the input circuit.
|
||||
"""
|
||||
self.backend = backend
|
||||
for name, data in self.dag_circuit.gates.items():
|
||||
self.backend.define_gate(name, data)
|
||||
|
||||
def execute(self):
|
||||
"""Interpret OPENQASM and make appropriate backend calls.
|
||||
|
||||
This does not expand gates. So Unroller must have
|
||||
been previously called. Otherwise non-basis gates will be ignored
|
||||
by this method.
|
||||
"""
|
||||
if self.backend is not None:
|
||||
self._process()
|
||||
return self.backend.get_output()
|
||||
else:
|
||||
raise UnrollerError("backend not attached")
|
||||
|
||||
def _process(self):
|
||||
"""Process dag nodes.
|
||||
|
||||
This method does *not* unroll.
|
||||
"""
|
||||
for qreg in self.dag_circuit.qregs.values():
|
||||
self.backend.new_qreg(qreg)
|
||||
for creg in self.dag_circuit.cregs.values():
|
||||
self.backend.new_creg(creg)
|
||||
for n in nx.topological_sort(self.dag_circuit.multi_graph):
|
||||
current_node = self.dag_circuit.multi_graph.node[n]
|
||||
if current_node["type"] == "op":
|
||||
if current_node["condition"] is not None:
|
||||
self.backend.set_condition(current_node["condition"][0],
|
||||
current_node["condition"][1])
|
||||
|
||||
# TODO: The schema of the snapshot gate is radically
|
||||
# different to other QASM instructions. The current model
|
||||
# of extensions does not support generating custom Qobj
|
||||
# instructions (only custom QASM strings) and the default
|
||||
# instruction generator is not enough to produce a valid
|
||||
# snapshot instruction for the new Qobj format.
|
||||
#
|
||||
# This is a hack since there would be mechanisms for the
|
||||
# extensions to provide their own Qobj instructions.
|
||||
# Extensions should not be hardcoded in the DAGUnroller.
|
||||
extra_fields = None
|
||||
if current_node["op"].name == "snapshot":
|
||||
extra_fields = {'type': str(current_node["op"].param[1]),
|
||||
'label': str(current_node["op"].param[0]),
|
||||
'texparams': []}
|
||||
|
||||
self.backend.start_gate(current_node["op"],
|
||||
qargs=current_node["qargs"],
|
||||
cargs=current_node["cargs"],
|
||||
extra_fields=extra_fields)
|
||||
self.backend.end_gate(current_node["op"])
|
||||
|
||||
self.backend.drop_condition()
|
||||
|
||||
return self.backend.get_output()
|
|
@ -1,235 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
|
||||
"""Backend for the unroller that composes qasm into json file.
|
||||
|
||||
The input is a AST and a basis set and returns a json memory object::
|
||||
|
||||
{
|
||||
"header": {
|
||||
"n_qubits": 2, // int
|
||||
"memory_slots": 2, // int
|
||||
"qubit_labels": [["q", 0], ["q", 1], null], // list[list[string, int] or null]
|
||||
"clbit_labels": [["c", 0], ["c", 1]], // list[list[string, int]]
|
||||
"qreg_sizes": [["q", 1], ["v", 1]], // list[list[string, int]]
|
||||
"creg_sizes": [["c", 2]] // list[list[string, int]]
|
||||
}
|
||||
"instructions": // list[map]
|
||||
[
|
||||
{
|
||||
"name": , // required -- string
|
||||
"params": , // optional -- list[double]
|
||||
"texparams": , // optional -- list[string]
|
||||
"qubits": , // optional -- list[int]
|
||||
"cbits": , //optional -- list[int]
|
||||
"conditional": // optional -- map
|
||||
{
|
||||
"type": "equals", // string
|
||||
"mask": "0xHexadecimalString", // big int
|
||||
"val": "0xHexadecimalString", // big int
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
import sympy
|
||||
|
||||
from qiskit.unrollers.exceptions import BackendError
|
||||
from qiskit.unrollers._unrollerbackend import UnrollerBackend
|
||||
|
||||
|
||||
class JsonBackend(UnrollerBackend):
|
||||
"""Backend for the unroller that makes a Json quantum circuit."""
|
||||
|
||||
def __init__(self, basis=None):
|
||||
"""Setup this backend.
|
||||
|
||||
basis is a list of operation name strings.
|
||||
The default basis is ["U", "CX"].
|
||||
"""
|
||||
super().__init__(basis)
|
||||
self.circuit = {}
|
||||
self.circuit['instructions'] = []
|
||||
self.circuit['header'] = {
|
||||
'n_qubits': 0,
|
||||
'memory_slots': 0,
|
||||
'qubit_labels': [],
|
||||
'clbit_labels': [],
|
||||
'qreg_sizes': [],
|
||||
'creg_sizes': []
|
||||
}
|
||||
self._number_of_qubits = 0
|
||||
self._number_of_clbits = 0
|
||||
self._qreg_sizes = []
|
||||
self._creg_sizes = []
|
||||
self._qubit_order = []
|
||||
self._cbit_order = []
|
||||
self._qubit_order_internal = OrderedDict()
|
||||
self._cbit_order_internal = OrderedDict()
|
||||
|
||||
self.creg = None
|
||||
self.cval = None
|
||||
self.gates = OrderedDict()
|
||||
if basis:
|
||||
self.basis = basis.copy()
|
||||
else:
|
||||
self.basis = [] # default, unroll to U, CX
|
||||
self.listen = True
|
||||
self.in_gate = ""
|
||||
self.printed_gates = []
|
||||
|
||||
def set_basis(self, basis):
|
||||
"""Declare the set of user-defined gates to emit.
|
||||
|
||||
basis is a list of operation name strings.
|
||||
"""
|
||||
self.basis = basis.copy()
|
||||
|
||||
def version(self, version):
|
||||
"""Print the version string.
|
||||
|
||||
v is a version number.
|
||||
"""
|
||||
pass
|
||||
|
||||
def new_qreg(self, qreg):
|
||||
"""Create a new quantum register.
|
||||
|
||||
qreg = QuantumRegister object
|
||||
"""
|
||||
self._qreg_sizes.append([qreg.name, qreg.size])
|
||||
|
||||
# order qubits from lower to higher index. backends will do little endian.
|
||||
for j in range(qreg.size):
|
||||
self._qubit_order.append([qreg.name, j])
|
||||
self._qubit_order_internal[(qreg.name, j)] = self._number_of_qubits + j
|
||||
self._number_of_qubits += qreg.size
|
||||
# TODO: avoid rewriting the same data over and over
|
||||
self.circuit['header']['n_qubits'] = self._number_of_qubits
|
||||
self.circuit['header']['qreg_sizes'] = self._qreg_sizes
|
||||
self.circuit['header']['qubit_labels'] = self._qubit_order
|
||||
|
||||
def new_creg(self, creg):
|
||||
"""Create a new classical register.
|
||||
|
||||
creg = ClassicalRegister object
|
||||
"""
|
||||
self._creg_sizes.append([creg.name, creg.size])
|
||||
# order clbits from lower to higher index. backends will do little endian.
|
||||
for j in range(creg.size):
|
||||
self._cbit_order.append([creg.name, j])
|
||||
self._cbit_order_internal[(creg.name, j)] = self._number_of_clbits + j
|
||||
self._number_of_clbits += creg.size
|
||||
# TODO: avoid rewriting the same data over and over
|
||||
self.circuit['header']['memory_slots'] = self._number_of_clbits
|
||||
self.circuit['header']['creg_sizes'] = self._creg_sizes
|
||||
self.circuit['header']['clbit_labels'] = self._cbit_order
|
||||
|
||||
def define_gate(self, name, gatedata):
|
||||
"""Define a new quantum gate.
|
||||
|
||||
name is a string.
|
||||
gatedata is the AST node for the gate.
|
||||
"""
|
||||
self.gates[name] = gatedata
|
||||
|
||||
def _add_condition(self):
|
||||
"""Check for a condition (self.creg) and add fields if necessary.
|
||||
|
||||
Fields are added to the last operation in the circuit.
|
||||
"""
|
||||
if self.creg is not None:
|
||||
mask = 0
|
||||
for cbit, index in self._cbit_order_internal.items():
|
||||
if cbit[0] == self.creg.name:
|
||||
mask |= (1 << index)
|
||||
# Would be nicer to zero pad the mask, but we
|
||||
# need to know the total number of cbits.
|
||||
# format_spec = "{0:#0{%d}X}" % number_of_clbits
|
||||
# format_spec.format(mask)
|
||||
conditional = {
|
||||
'type': "equals",
|
||||
'mask': "0x%X" % mask,
|
||||
'val': "0x%X" % self.cval
|
||||
}
|
||||
self.circuit['instructions'][-1]['conditional'] = conditional
|
||||
|
||||
def set_condition(self, creg, cval):
|
||||
"""Attach a current condition.
|
||||
|
||||
creg is a name string.
|
||||
cval is the integer value for the test.
|
||||
"""
|
||||
self.creg = creg
|
||||
self.cval = cval
|
||||
|
||||
def drop_condition(self):
|
||||
"""Drop the current condition."""
|
||||
self.creg = None
|
||||
self.cval = None
|
||||
|
||||
def start_gate(self, op, qargs, cargs, extra_fields=None):
|
||||
"""
|
||||
Begin a custom gate.
|
||||
|
||||
Args:
|
||||
op (Instruction): operation to apply to the dag.
|
||||
qargs (list[QuantumRegister, int]): qubit arguments
|
||||
cargs (list[ClassicalRegister, int]): clbit arguments
|
||||
extra_fields (dict): extra_fields used by non-standard instructions
|
||||
for now (e.g. snapshot)
|
||||
|
||||
Raises:
|
||||
BackendError: if using a non-basis opaque gate
|
||||
"""
|
||||
if not self.listen:
|
||||
return
|
||||
if op.name not in self.basis and self.gates[op.name]["opaque"]:
|
||||
raise BackendError("opaque gate %s not in basis" % op.name)
|
||||
if op.name in self.basis:
|
||||
self.in_gate = op
|
||||
self.listen = False
|
||||
qubit_indices = [self._qubit_order_internal.get((qubit[0].name, qubit[1]))
|
||||
for qubit in qargs]
|
||||
clbit_indices = [self._cbit_order_internal.get((cbit[0].name, cbit[1]))
|
||||
for cbit in cargs]
|
||||
gate_instruction = {
|
||||
'name': op.name,
|
||||
'params': list(map(lambda x: x.evalf(), op.param)),
|
||||
'texparams': list(map(sympy.latex, op.param)),
|
||||
'qubits': qubit_indices,
|
||||
'memory': clbit_indices
|
||||
}
|
||||
if extra_fields is not None:
|
||||
gate_instruction.update(extra_fields)
|
||||
self.circuit['instructions'].append(gate_instruction)
|
||||
self._add_condition()
|
||||
|
||||
def end_gate(self, op):
|
||||
"""End a custom gate.
|
||||
|
||||
Args:
|
||||
op (Instruction): operation to apply to the dag.
|
||||
"""
|
||||
if op == self.in_gate:
|
||||
self.in_gate = None
|
||||
self.listen = True
|
||||
|
||||
def get_output(self):
|
||||
"""Returns the generated circuit."""
|
||||
if not self._is_circuit_valid():
|
||||
raise BackendError("Invalid circuit! Please check the syntax of your circuit."
|
||||
"Has Qasm parsing been called?. e.g: unroller.execute().")
|
||||
return self.circuit
|
||||
|
||||
def _is_circuit_valid(self):
|
||||
"""Checks whether the circuit object is a valid one or not."""
|
||||
return (len(self.circuit['header']) > 0 and
|
||||
len(self.circuit['instructions']) >= 0)
|
|
@ -1,153 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""
|
||||
Base backend object for the unroller that raises BackendError.
|
||||
"""
|
||||
from qiskit.unrollers.exceptions import BackendError
|
||||
|
||||
|
||||
class UnrollerBackend:
|
||||
"""Backend for the unroller that raises BackendError.
|
||||
|
||||
This backend also serves as a base class for other unroller backends.
|
||||
"""
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
def __init__(self, basis=None):
|
||||
"""Setup this backend.
|
||||
|
||||
basis is a list of operation name strings.
|
||||
"""
|
||||
if basis:
|
||||
basis = []
|
||||
|
||||
def set_basis(self, basis):
|
||||
"""Declare the set of user-defined gates to emit.
|
||||
|
||||
basis is a list of operation name strings.
|
||||
"""
|
||||
raise BackendError("Backend set_basis unimplemented")
|
||||
|
||||
def version(self, version):
|
||||
"""Print the version string.
|
||||
|
||||
v is a version number.
|
||||
"""
|
||||
raise BackendError("Backend version unimplemented")
|
||||
|
||||
def new_qreg(self, qreg):
|
||||
"""Create a new quantum register.
|
||||
|
||||
qreg = QuantumRegister object
|
||||
"""
|
||||
raise BackendError("Backend new_qreg unimplemented")
|
||||
|
||||
def new_creg(self, creg):
|
||||
"""Create a new classical register.
|
||||
|
||||
creg = ClassicalRegister object
|
||||
"""
|
||||
raise BackendError("Backend new_creg unimplemented")
|
||||
|
||||
def define_gate(self, name, gatedata):
|
||||
"""Define a new quantum gate.
|
||||
|
||||
name is a string.
|
||||
gatedata is the AST node for the gate.
|
||||
"""
|
||||
raise BackendError("Backend define_gate unimplemented")
|
||||
|
||||
def u(self, arg, qubit, nested_scope=None):
|
||||
"""Fundamental single qubit gate.
|
||||
|
||||
arg is 3-tuple of Node expression objects.
|
||||
qubit is (regname,idx) tuple.
|
||||
nested_scope is a list of dictionaries mapping expression variables
|
||||
to Node expression objects in order of increasing nesting depth.
|
||||
"""
|
||||
# pylint: disable=invalid-name
|
||||
raise BackendError("Backend u unimplemented")
|
||||
|
||||
def cx(self, qubit0, qubit1):
|
||||
"""Fundamental two qubit gate.
|
||||
|
||||
qubit0 is (regname,idx) tuple for the control qubit.
|
||||
qubit1 is (regname,idx) tuple for the target qubit.
|
||||
"""
|
||||
# pylint: disable=invalid-name
|
||||
raise BackendError("Backend cx unimplemented")
|
||||
|
||||
def measure(self, qubit, bit):
|
||||
"""Measurement operation.
|
||||
|
||||
qubit is (regname, idx) tuple for the input qubit.
|
||||
bit is (regname, idx) tuple for the output bit.
|
||||
"""
|
||||
raise BackendError("Backend measure unimplemented")
|
||||
|
||||
def barrier(self, qubitlists):
|
||||
"""Barrier instruction.
|
||||
|
||||
qubitlists is a list of lists of (regname, idx) tuples.
|
||||
"""
|
||||
raise BackendError("Backend barrier unimplemented")
|
||||
|
||||
def reset(self, qubit):
|
||||
"""Reset instruction.
|
||||
|
||||
qubit is a (regname, idx) tuple.
|
||||
"""
|
||||
raise BackendError("Backend reset unimplemented")
|
||||
|
||||
def set_condition(self, creg, cval):
|
||||
"""Attach a current condition.
|
||||
|
||||
creg is a name string.
|
||||
cval is the integer value for the test.
|
||||
"""
|
||||
raise BackendError("Backend set_condition unimplemented")
|
||||
|
||||
def drop_condition(self):
|
||||
"""Drop the current condition."""
|
||||
raise BackendError("Backend drop_condition unimplemented")
|
||||
|
||||
def start_gate(self, name, args, qubits, nested_scope=None, extra_fields=None):
|
||||
"""Start a custom gate.
|
||||
|
||||
Args:
|
||||
name (str): name of the gate.
|
||||
args (list[Node]): list of expression nodes.
|
||||
qubits (list[tuple(str, int)]): list of (regname, idx) tuples.
|
||||
nested_scope (list[dict()]): list of dictionaries mapping expression
|
||||
variables to Node expression objects in order of increasing
|
||||
nesting depth.
|
||||
extra_fields (dict(str, obj)): is a dictionary allowing the extension
|
||||
or overriding of the gate instruction properties.
|
||||
|
||||
Raises:
|
||||
BackendError: if the gate is not part of the basis.
|
||||
"""
|
||||
raise BackendError("Backend start_gate unimplemented")
|
||||
|
||||
def end_gate(self, name, args, qubits, nested_scope=None):
|
||||
"""End a custom gate.
|
||||
|
||||
name is name string.
|
||||
args is list of Node expression objects.
|
||||
qubits is list of (regname, idx) tuples.
|
||||
nested_scope is a list of dictionaries mapping expression variables
|
||||
to Node expression objects in order of increasing nesting depth.
|
||||
"""
|
||||
raise BackendError("Backend end_gate unimplemented")
|
||||
|
||||
def get_output(self):
|
||||
"""Returns the output generated by the backend.
|
||||
Depending on the type of Backend, the output could have different types.
|
||||
It must be called once the Qasm parsing has finished
|
||||
"""
|
||||
raise BackendError("Backend get_output unimplemented")
|
|
@ -1,39 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""
|
||||
Exception for errors raised by unroller.
|
||||
"""
|
||||
|
||||
|
||||
from qiskit.exceptions import QiskitError
|
||||
|
||||
|
||||
class UnrollerError(QiskitError):
|
||||
"""Base class for errors raised by unroller."""
|
||||
|
||||
def __init__(self, *message):
|
||||
"""Set the error message."""
|
||||
super().__init__(*message)
|
||||
self.message = ' '.join(message)
|
||||
|
||||
def __str__(self):
|
||||
"""Return the message."""
|
||||
return repr(self.message)
|
||||
|
||||
|
||||
class BackendError(QiskitError):
|
||||
"""Base class for errors raised by unroller backends."""
|
||||
|
||||
def __init__(self, *message):
|
||||
"""Set the error message."""
|
||||
super().__init__(*message)
|
||||
self.message = ' '.join(message)
|
||||
|
||||
def __str__(self):
|
||||
"""Return the message."""
|
||||
return repr(self.message)
|
|
@ -6,6 +6,7 @@
|
|||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
# pylint: disable=redefined-builtin
|
||||
# pylint: disable=unused-import
|
||||
|
||||
"""Tests for the converters."""
|
||||
|
||||
|
@ -20,6 +21,7 @@ from qiskit.qobj import Qobj
|
|||
from qiskit.transpiler import PassManager
|
||||
from qiskit.converters import circuit_to_dag
|
||||
from qiskit.test import QiskitTestCase
|
||||
import qiskit.extensions.simulator
|
||||
|
||||
|
||||
class TestQobjToCircuits(QiskitTestCase):
|
||||
|
|
|
@ -20,6 +20,7 @@ from qiskit.qobj import QobjHeader, validate_qobj_against_schema
|
|||
from qiskit.providers.builtinsimulators import simulatorsjob
|
||||
from qiskit.providers.ibmq import ibmqjob
|
||||
from qiskit.test import QiskitTestCase
|
||||
|
||||
from .._mockutils import FakeBackend
|
||||
|
||||
|
||||
|
@ -131,24 +132,13 @@ class TestQobj(QiskitTestCase):
|
|||
qc1.measure(qr, cr)
|
||||
qc2.measure(qr, cr)
|
||||
circuits = [qc1, qc2]
|
||||
shots = 1024
|
||||
backend = BasicAer.get_backend('qasm_simulator')
|
||||
config = {'seed': 10, 'shots': 1, 'xvals': [1, 2, 3, 4]}
|
||||
qobj1 = compile(circuits, backend=backend, shots=shots, seed=88, config=config)
|
||||
qobj1 = compile(circuits, backend=backend, shots=1024, seed=88)
|
||||
qobj1.experiments[0].config.shots = 50
|
||||
qobj1.experiments[0].config.xvals = [1, 1, 1]
|
||||
config['shots'] = 1000
|
||||
config['xvals'][0] = 'only for qobj2'
|
||||
qobj2 = compile(circuits, backend=backend, shots=shots, seed=88, config=config)
|
||||
qobj1.experiments[1].config.shots = 1
|
||||
self.assertTrue(qobj1.experiments[0].config.shots == 50)
|
||||
self.assertTrue(qobj1.experiments[1].config.shots == 1)
|
||||
self.assertTrue(qobj1.experiments[0].config.xvals == [1, 1, 1])
|
||||
self.assertTrue(qobj1.experiments[1].config.xvals == [1, 2, 3, 4])
|
||||
self.assertTrue(qobj1.config.shots == 1024)
|
||||
self.assertTrue(qobj2.experiments[0].config.shots == 1000)
|
||||
self.assertTrue(qobj2.experiments[1].config.shots == 1000)
|
||||
self.assertTrue(qobj2.experiments[0].config.xvals == ['only for qobj2', 2, 3, 4])
|
||||
self.assertTrue(qobj2.experiments[1].config.xvals == ['only for qobj2', 2, 3, 4])
|
||||
|
||||
|
||||
def _nop():
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017, IBM.
|
||||
#
|
||||
# This source code is licensed under the Apache License, Version 2.0 found in
|
||||
# the LICENSE.txt file in the root directory of this source tree.
|
||||
|
||||
"""Test Qiskit Unroller class."""
|
||||
|
||||
import unittest
|
||||
|
||||
from qiskit import qasm
|
||||
from qiskit.unroll import DagUnroller, JsonBackend
|
||||
from qiskit.converters import ast_to_dag
|
||||
from qiskit.test import QiskitTestCase, Path
|
||||
|
||||
|
||||
class UnrollerTest(QiskitTestCase):
|
||||
"""Test the Unroller."""
|
||||
|
||||
# We need to change the way we create clbit_labels and qubit_labels in order to
|
||||
# enable this test, as they are lists but the order is not important so comparing
|
||||
# them usually fails.
|
||||
@unittest.skip("Temporary skipping")
|
||||
def test_dag_to_json(self):
|
||||
"""Test DagUnroller with JSON backend."""
|
||||
ast = qasm.Qasm(filename=self._get_resource_path('example.qasm', Path.QASMS)).parse()
|
||||
dag_circuit = ast_to_dag(ast)
|
||||
dag_unroller = DagUnroller(dag_circuit, JsonBackend())
|
||||
json_circuit = dag_unroller.execute()
|
||||
expected_result = {
|
||||
'operations':
|
||||
[
|
||||
{'qubits': [5], 'texparams': ['0.5 \\pi', '0', '\\pi'],
|
||||
'name': 'U', 'params': [1.5707963267948966, 0.0, 3.141592653589793]},
|
||||
{'name': 'CX', 'qubits': [5, 2]},
|
||||
{'clbits': [2], 'name': 'measure', 'qubits': [2]},
|
||||
{'qubits': [4], 'texparams': ['0.5 \\pi', '0', '\\pi'], 'name': 'U',
|
||||
'params': [1.5707963267948966, 0.0, 3.141592653589793]},
|
||||
{'name': 'CX', 'qubits': [4, 1]},
|
||||
{'clbits': [1], 'name': 'measure', 'qubits': [1]},
|
||||
{'qubits': [3], 'texparams': ['0.5 \\pi', '0', '\\pi'], 'name': 'U',
|
||||
'params': [1.5707963267948966, 0.0, 3.141592653589793]},
|
||||
{'name': 'CX', 'qubits': [3, 0]},
|
||||
{'name': 'barrier', 'qubits': [3, 4, 5]},
|
||||
{'clbits': [5], 'name': 'measure', 'qubits': [5]},
|
||||
{'clbits': [4], 'name': 'measure', 'qubits': [4]},
|
||||
{'clbits': [3], 'name': 'measure', 'qubits': [3]},
|
||||
{'clbits': [0], 'name': 'measure', 'qubits': [0]}
|
||||
],
|
||||
'header':
|
||||
{
|
||||
'memory_slots': 6,
|
||||
'qubit_labels': [['r', 0], ['r', 1], ['r', 2], ['q', 0], ['q', 1], ['q', 2]],
|
||||
'n_qubits': 6, 'clbit_labels': [['d', 3], ['c', 3]]
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(json_circuit, expected_result)
|
|
@ -326,17 +326,20 @@ class TestCompiler(QiskitTestCase):
|
|||
qobj = compile(qlist, backend=backend)
|
||||
self.assertEqual(len(qobj.experiments), 10)
|
||||
|
||||
def test_compile_skip_transpiler(self):
|
||||
def test_compile_pass_manager(self):
|
||||
"""Test compile with and without an empty pass manager."""
|
||||
qr = QuantumRegister(2)
|
||||
cr = ClassicalRegister(2)
|
||||
qc = QuantumCircuit(qr, cr)
|
||||
qc.u1(3.14, qr[0])
|
||||
qc.u2(3.14, 1.57, qr[0])
|
||||
qc.barrier(qr)
|
||||
qc.measure(qr, cr)
|
||||
backend = BasicAer.get_backend('qasm_simulator')
|
||||
rtrue = execute(qc, backend, seed=42).result()
|
||||
rfalse = execute(qc, backend, seed=42, pass_manager=PassManager()).result()
|
||||
qrtrue = compile(qc, backend, seed=42)
|
||||
rtrue = backend.run(qrtrue).result()
|
||||
qrfalse = compile(qc, backend, seed=42, pass_manager=PassManager())
|
||||
rfalse = backend.run(qrfalse).result()
|
||||
self.assertEqual(rtrue.get_counts(), rfalse.get_counts())
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ from qiskit.transpiler import PassManager, transpile_dag, transpile
|
|||
from qiskit.tools.compiler import circuits_to_qobj
|
||||
from qiskit.converters import circuit_to_dag
|
||||
from qiskit.test import QiskitTestCase
|
||||
from qiskit.qobj.run_config import RunConfig
|
||||
|
||||
|
||||
class TestTranspile(QiskitTestCase):
|
||||
|
@ -66,8 +67,6 @@ class TestTranspile(QiskitTestCase):
|
|||
pass_manager=None)
|
||||
|
||||
qobj = compile(circuit, backend=backend, coupling_map=coupling_map, basis_gates=basis_gates)
|
||||
|
||||
qobj2 = circuits_to_qobj(circuit2, backend.name(), basis_gates=basis_gates,
|
||||
coupling_map=coupling_map, qobj_id=qobj.qobj_id)
|
||||
|
||||
run_config = RunConfig(shots=1024, max_credits=10)
|
||||
qobj2 = circuits_to_qobj(circuit2, qobj_id=qobj.qobj_id, run_config=run_config)
|
||||
self.assertEqual(qobj, qobj2)
|
||||
|
|
Loading…
Reference in New Issue