diff --git a/qiskit/assembler/assemble_circuits.py b/qiskit/assembler/assemble_circuits.py index a4a4177cf7bf..17047941c48d 100644 --- a/qiskit/assembler/assemble_circuits.py +++ b/qiskit/assembler/assemble_circuits.py @@ -116,8 +116,7 @@ def assemble_circuits(circuits, run_config, qobj_id, qobj_header): mask="0x%X" % mask, relation='==', val="0x%X" % val, - register=conditional_reg_idx, - validate=False) + register=conditional_reg_idx) instructions.append(conversion_bfunc) instruction.conditional = conditional_reg_idx max_conditional_idx += 1 diff --git a/qiskit/circuit/instruction.py b/qiskit/circuit/instruction.py index 1172dfba9b20..463fa64a17d7 100644 --- a/qiskit/circuit/instruction.py +++ b/qiskit/circuit/instruction.py @@ -42,7 +42,7 @@ from qiskit.circuit.exceptions import CircuitError from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.classicalregister import ClassicalRegister -from qiskit.qobj.models.qasm import QasmQobjInstruction +from qiskit.qobj.qasm_qobj import QasmQobjInstruction from qiskit.circuit.parameter import ParameterExpression _CUTOFF_PRECISION = 1E-10 @@ -222,7 +222,7 @@ def definition(self, array): def assemble(self): """Assemble a QasmQobjInstruction""" - instruction = QasmQobjInstruction(name=self.name, validate=False) + instruction = QasmQobjInstruction(name=self.name) # Evaluate parameters if self.params: params = [ diff --git a/qiskit/providers/models/pulsedefaults.py b/qiskit/providers/models/pulsedefaults.py index b5e36a4fb2fe..2162c204d583 100644 --- a/qiskit/providers/models/pulsedefaults.py +++ b/qiskit/providers/models/pulsedefaults.py @@ -12,6 +12,8 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. +# pylint: disable=missing-type-doc + """Model and schema for pulse defaults.""" import warnings @@ -20,7 +22,8 @@ from qiskit.validation import BaseModel, BaseSchema, bind_schema, fields from qiskit.validation.base import ObjSchema -from qiskit.qobj import PulseLibraryItemSchema, PulseQobjInstructionSchema, PulseLibraryItem +from qiskit.qobj.models.pulse import PulseLibraryItemSchema, PulseQobjInstructionSchema +from qiskit.qobj import PulseLibraryItem from qiskit.qobj.converters import QobjToInstructionConverter from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap from qiskit.pulse.schedule import ParameterizedSchedule diff --git a/qiskit/qobj/__init__.py b/qiskit/qobj/__init__.py index adb6f472af8a..3ec7bb49ac6f 100644 --- a/qiskit/qobj/__init__.py +++ b/qiskit/qobj/__init__.py @@ -26,11 +26,7 @@ :toctree: ../stubs/ Qobj - QobjInstruction QobjExperimentHeader - QobjExperimentConfig - QobjExperiment - QobjConfig QobjHeader Qasm @@ -58,8 +54,6 @@ PulseQobjConfig QobjMeasurementOption PulseLibraryItem - PulseLibraryItemSchema - PulseQobjInstructionSchema Validation ========== @@ -70,17 +64,34 @@ validate_qobj_against_schema """ -from .models.base import (QobjInstruction, QobjExperimentHeader, QobjExperimentConfig, - QobjExperiment, QobjConfig, QobjHeader) +import warnings -from .models.pulse import (PulseQobjInstruction, PulseQobjExperimentConfig, - PulseQobjExperiment, PulseQobjConfig, - QobjMeasurementOption, PulseLibraryItem, - PulseLibraryItemSchema, PulseQobjInstructionSchema) +from qiskit.qobj.pulse_qobj import PulseQobj +from qiskit.qobj.pulse_qobj import PulseQobjInstruction +from qiskit.qobj.pulse_qobj import PulseQobjExperimentConfig +from qiskit.qobj.pulse_qobj import PulseQobjExperiment +from qiskit.qobj.pulse_qobj import PulseQobjConfig +from qiskit.qobj.pulse_qobj import QobjMeasurementOption +from qiskit.qobj.pulse_qobj import PulseLibraryItem -from .models.qasm import (QasmQobjInstruction, QasmQobjExperimentConfig, - QasmQobjExperiment, QasmQobjConfig) - -from .qobj import Qobj, QasmQobj, PulseQobj +from qiskit.qobj.qasm_qobj import QasmQobj +from qiskit.qobj.qasm_qobj import QasmQobjInstruction +from qiskit.qobj.qasm_qobj import QasmQobjExperiment +from qiskit.qobj.qasm_qobj import QasmQobjConfig +from qiskit.qobj.qasm_qobj import QobjExperimentHeader +from qiskit.qobj.qasm_qobj import QasmQobjExperimentConfig +from qiskit.qobj.qasm_qobj import QobjHeader from .utils import validate_qobj_against_schema + + +class Qobj(QasmQobj): + """A backwards compat alias for QasmQobj.""" + + def __init__(self, qobj_id=None, config=None, experiments=None, + header=None): + """Initialize a Qobj object.""" + warnings.warn('qiskit.qobj.Qobj is deprecated use either QasmQobj or ' + 'PulseQobj depending on your application instead.', + DeprecationWarning, stacklevel=2) + super(Qobj, self).__init__() diff --git a/qiskit/qobj/models/pulse.py b/qiskit/qobj/models/pulse.py index d6669150192a..32e710258e25 100644 --- a/qiskit/qobj/models/pulse.py +++ b/qiskit/qobj/models/pulse.py @@ -14,15 +14,12 @@ """The pulse qobj models.""" -from marshmallow.validate import Range, Regexp, Length, OneOf +from marshmallow.validate import Range, Regexp, Length -from qiskit.qobj.utils import MeasReturnType, MeasLevel -from qiskit.validation import BaseSchema, bind_schema, BaseModel -from qiskit.validation.fields import (Integer, String, Number, Float, Complex, List, +from qiskit.validation import BaseSchema +from qiskit.validation.fields import (Integer, String, Float, Complex, List, Nested, DictParameters, ByType) -from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema, - QobjConfigSchema, QobjInstruction, QobjExperimentConfig, - QobjExperiment, QobjConfig) +from .base import QobjInstructionSchema class QobjMeasurementOptionSchema(BaseSchema): @@ -63,153 +60,3 @@ class PulseQobjInstructionSchema(QobjInstructionSchema): label = String() type = String() parameters = DictParameters(valid_value_types=(int, float, bool, complex)) - - -class PulseQobjExperimentConfigSchema(QobjExperimentConfigSchema): - """Schema for PulseQobjExperimentConfig.""" - - # Optional properties. - qubit_lo_freq = List(Number()) - meas_lo_freq = List(Number()) - - -class PulseQobjExperimentSchema(QobjExperimentSchema): - """Schema for PulseQobjExperiment.""" - - # Required properties. - instructions = Nested(PulseQobjInstructionSchema, required=True, many=True, - validate=Length(min=1)) - - # Optional properties. - config = Nested(PulseQobjExperimentConfigSchema) - - -class PulseQobjConfigSchema(QobjConfigSchema): - """Schema for PulseQobjConfig of device backend.""" - - # Required properties. - meas_level = Integer(required=True, validate=OneOf(choices=(MeasLevel.RAW, - MeasLevel.KERNELED, - MeasLevel.CLASSIFIED))) - meas_return = String(required=True, validate=OneOf(choices=(MeasReturnType.AVERAGE, - MeasReturnType.SINGLE))) - pulse_library = Nested(PulseLibraryItemSchema, required=True, many=True) - qubit_lo_freq = List(Number(validate=Range(min=0)), required=True) - meas_lo_freq = List(Number(validate=Range(min=0)), required=True) - - # Optional properties. - memory_slot_size = Integer(validate=Range(min=1)) - rep_time = Integer(validate=Range(min=0)) - - -@bind_schema(QobjMeasurementOptionSchema) -class QobjMeasurementOption(BaseModel): - """Model for QobjMeasurementOption. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QobjMeasurementOptionSchema``. - - Attributes: - name (str): name of option specified in the backend - params (dict): measurement parameter - """ - def __init__(self, name, params, **kwargs): - self.name = name - self.params = params - - super().__init__(**kwargs) - - -@bind_schema(PulseLibraryItemSchema) -class PulseLibraryItem(BaseModel): - """Model for PulseLibraryItem. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseLibraryItemSchema``. - - Attributes: - name (str): name of pulse - samples (list[complex]]): list of complex values defining pulse shape - """ - - def __init__(self, name, samples, **kwargs): - self.name = name - self.samples = samples - - super().__init__(**kwargs) - - -@bind_schema(PulseQobjInstructionSchema) -class PulseQobjInstruction(QobjInstruction): - """Model for PulseQobjInstruction inherit from QobjInstruction. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseQobjInstructionSchema``. - - Attributes: - name (str): name of the instruction - t0 (int): timing of executing the instruction - """ - def __init__(self, name, t0, **kwargs): - # pylint: disable=invalid-name - self.t0 = t0 - - super().__init__(name=name, - t0=t0, - **kwargs) - - -@bind_schema(PulseQobjExperimentConfigSchema) -class PulseQobjExperimentConfig(QobjExperimentConfig): - """Model for PulseQobjExperimentConfig inherit from QobjExperimentConfig. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseQobjExperimentConfigSchema``. - """ - pass - - -@bind_schema(PulseQobjExperimentSchema) -class PulseQobjExperiment(QobjExperiment): - """Model for PulseQobjExperiment inherit from QobjExperiment. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseQobjExperimentSchema``. - - Attributes: - instructions (list[PulseQobjInstruction]): list of instructions. - """ - def __init__(self, instructions, **kwargs): - - super().__init__(instructions=instructions, - **kwargs) - - -@bind_schema(PulseQobjConfigSchema) -class PulseQobjConfig(QobjConfig): - """Model for PulseQobjConfig inherit from QobjConfig. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseQobjConfigSchema``. - - Attributes: - meas_level (int or MeasLevel): a value represents the level of measurement. - meas_lo_freq (list[float]): local oscillator frequency of measurement pulse. - meas_return (str or MeasReturn): a level of measurement information. - pulse_library (list[qiskit.qobj.PulseLibraryItem]): a pulse library. - qubit_lo_freq (list[float]): local oscillator frequency of driving pulse. - """ - def __init__(self, meas_level, meas_return, pulse_library, - qubit_lo_freq, meas_lo_freq, **kwargs): - self.meas_level = meas_level - self.meas_return = meas_return - self.pulse_library = pulse_library - self.qubit_lo_freq = qubit_lo_freq - self.meas_lo_freq = meas_lo_freq - - super().__init__(meas_level=meas_level, - meas_return=meas_return, - pulse_library=pulse_library, - qubit_lo_freq=qubit_lo_freq, - meas_lo_freq=meas_lo_freq, - **kwargs) diff --git a/qiskit/qobj/models/qasm.py b/qiskit/qobj/models/qasm.py deleted file mode 100644 index 2a8a182ebb0b..000000000000 --- a/qiskit/qobj/models/qasm.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""The qasm qobj models.""" - -from marshmallow.validate import Range, Length - -from qiskit.validation import bind_schema -from qiskit.validation.fields import List, Integer, InstructionParameter, Nested -from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema, - QobjConfigSchema, QobjInstruction, QobjExperimentConfig, - QobjExperiment, QobjConfig) - - -class QasmQobjInstructionSchema(QobjInstructionSchema): - """Schema for QasmQobjInstruction.""" - - # Optional properties. - qubits = List(Integer(validate=Range(min=0)), - validate=Length(min=1)) - params = List(InstructionParameter()) - memory = List(Integer(validate=Range(min=0)), - validate=Length(min=1)) - conditional = Integer(validate=Range(min=0)) - - -class QasmQobjExperimentConfigSchema(QobjExperimentConfigSchema): - """Schema for QasmQobjExperimentConfig.""" - - # Optional properties. - memory_slots = Integer(validate=Range(min=0)) - n_qubits = Integer(validate=Range(min=1)) - - -class QasmQobjExperimentSchema(QobjExperimentSchema): - """Schema for QasmQobjExperiment.""" - - # Required properties. - instructions = Nested(QasmQobjInstructionSchema, required=True, many=True) - - # Optional properties. - config = Nested(QasmQobjExperimentConfigSchema) - - -class QasmQobjConfigSchema(QobjConfigSchema): - """Schema for QasmQobjConfig.""" - - # Optional properties. - n_qubits = Integer(validate=Range(min=1)) - - -@bind_schema(QasmQobjInstructionSchema) -class QasmQobjInstruction(QobjInstruction): - """Model for QasmQobjInstruction inherit from QobjInstruction. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QasmQobjInstructionSchema``. - - Attributes: - name (str): name of the instruction - """ - def __init__(self, name, **kwargs): - super().__init__(name=name, - **kwargs) - - -@bind_schema(QasmQobjExperimentConfigSchema) -class QasmQobjExperimentConfig(QobjExperimentConfig): - """Model for QasmQobjExperimentConfig inherit from QobjExperimentConfig. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QasmQobjExperimentConfigSchema``. - """ - pass - - -@bind_schema(QasmQobjExperimentSchema) -class QasmQobjExperiment(QobjExperiment): - """Model for QasmQobjExperiment inherit from QobjExperiment. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QasmQobjExperimentSchema``. - - Attributes: - instructions (list[QasmQobjInstruction]): list of instructions. - """ - def __init__(self, instructions, **kwargs): - super().__init__(instructions=instructions, - **kwargs) - - -@bind_schema(QasmQobjConfigSchema) -class QasmQobjConfig(QobjConfig): - """Model for QasmQobjConfig inherit from QobjConfig. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QasmQobjConfigSchema``. - """ - pass diff --git a/qiskit/qobj/pulse_qobj.py b/qiskit/qobj/pulse_qobj.py new file mode 100644 index 000000000000..adce2b2e3c16 --- /dev/null +++ b/qiskit/qobj/pulse_qobj.py @@ -0,0 +1,528 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +# pylint: disable=invalid-name,redefined-builtin,method-hidden,arguments-differ +# pylint: disable=super-init-not-called + +"""Module providing definitions of Pulse Qobj classes.""" + +import copy +import json + +import numpy + +from qiskit.qobj.qasm_qobj import QobjDictField +from qiskit.qobj.qasm_qobj import QobjHeader +from qiskit.qobj.qasm_qobj import QobjExperimentHeader +from qiskit.qobj.qasm_qobj import validator + + +class QobjMeasurementOption: + """An individual measurement option.""" + + def __init__(self, name, params=None): + """Instantiate a new QobjMeasurementOption object. + + Args: + name (str): The name of the measurement option + params (list): The parameters of the measurement option. + """ + self.name = name + if params is not None: + self.params = params + + def to_dict(self): + """Return a dict format representation of the QobjMeasurementOption. + + Returns: + dict: The dictionary form of the QasmMeasurementOption. + """ + out_dict = {'name': self.name} + if hasattr(self, 'params'): + out_dict['params'] = self.params + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new QobjMeasurementOption object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + QobjMeasurementOption: The object from the input dictionary. + """ + name = data.pop('name') + return cls(name, **data) + + def __eq__(self, other): + if isinstance(other, QobjMeasurementOption): + if self.to_dict() == other.to_dict(): + return True + return False + + +class PulseQobjInstruction: + """A class representing a single instruction in an PulseQobj Experiment.""" + + def __init__(self, name, t0, ch=None, conditional=None, val=None, phase=None, + duration=None, qubits=None, memory_slot=None, + register_slot=None, kernels=None, discriminators=None, + label=None, type=None, pulse_shape=None, + parameters=None): + """Instantiate a new PulseQobjInstruction object. + + Args: + name (str): The name of the instruction + t0 (int): Pulse start time in integer **dt** units. + ch (str): The channel to apply the pulse instruction. + conditional (int): The register to use for a conditional for this + instruction + val (complex): Complex value to apply, bounded by an absolute value + of 1. + phase (float): if a ``fc`` instruction, the frame change phase in + radians. + duration (int): The duration of the pulse in **dt** units. + qubits (list): A list of ``int`` representing the qubits the + instruction operates on + memory_slot (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of memory slots to store the + measurement results in (must be the same length as qubits). + If a ``bfunc`` instruction this is a single ``int`` of the + memory slot to store the boolean function result in. + register_slot (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of register slots in which to + store the measurement results (must be the same length as + qubits). If a ``bfunc`` instruction this is a single ``int`` + of the register slot in which to store the result. + kernels (list): List of :class:`QobjMeasurementOption` objects + defining the measurement kernels and set of parameters if the + measurement level is 1 or 2. Only used for ``acquire`` + instructions. + discriminators (list): A list of :class:`QobjMeasurementOption` + used to set the discriminators to be used if the measurement + level is 2. Only used for ``acquire`` instructions. + label (str): Label of instruction + type (str): Type of instruction + pulse_shape (str): The shape of the parametric pulse + parameters (dict): The parameters for a parametric pulse + """ + self.name = name + self.t0 = t0 + if ch is not None: + self.ch = ch + if conditional is not None: + self.conditional = conditional + if val is not None: + self.val = val + if phase is not None: + self.phase = phase + if duration is not None: + self.duration = duration + if qubits is not None: + self.qubits = qubits + if memory_slot is not None: + self.memory_slot = memory_slot + if register_slot is not None: + self.register_slot = register_slot + if kernels is not None: + self.kernels = kernels + if discriminators is not None: + self.discriminators = discriminators + if label is not None: + self.label = label + if type is not None: + self.type = type + if pulse_shape is not None: + self.pulse_shape = pulse_shape + if parameters is not None: + self.parameters = parameters + + def to_dict(self): + """Return a dictionary format representation of the Instruction. + + Returns: + dict: The dictionary form of the PulseQobjInstruction. + """ + out_dict = { + 'name': self.name, + 't0': self.t0 + } + for attr in ['ch', 'conditional', 'val', 'phase', 'duration', + 'qubits', 'memory_slot', 'register_slot', + 'label', 'type', 'pulse_shape', 'parameters']: + if hasattr(self, attr): + out_dict[attr] = getattr(self, attr) + if hasattr(self, 'kernels'): + out_dict['kernels'] = [x.to_dict() for x in self.kernels] + if hasattr(self, 'discriminators'): + out_dict['discriminators'] = [ + x.to_dict() for x in self.discriminators] + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new PulseQobjExperimentConfig object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + PulseQobjInstruction: The object from the input dictionary. + """ + t0 = data.pop('t0') + name = data.pop('name') + if 'kernels' in data: + kernels = data.pop('kernels') + kernel_obj = [QobjMeasurementOption.from_dict(x) for x in kernels] + data['kernels'] = kernel_obj + if 'discriminators' in data: + discriminators = data.pop('discriminators') + discriminators_obj = [ + QobjMeasurementOption.from_dict(x) for x in discriminators] + data['discriminators'] = discriminators_obj + return cls(name, t0, **data) + + def __eq__(self, other): + if isinstance(other, PulseQobjInstruction): + if self.to_dict() == other.to_dict(): + return True + return False + + +class PulseQobjConfig(QobjDictField): + """A configuration for a Pulse Qobj.""" + + def __init__(self, meas_level, meas_return, pulse_library, + qubit_lo_freq, meas_lo_freq, memory_slot_size=None, + rep_time=None, shots=None, max_credits=None, + seed_simulator=None, memory_slots=None, **kwargs): + """Instantiate a PulseQobjConfig object. + + Args: + meas_level (int): The measurement level to use. + meas_return (int): The level of measurement information to return. + pulse_library (list): A list of :class:`PulseLibraryItem` objects + which define the set of primative pulses + qubit_lo_freq (list): List of frequencies (as floats) for the qubit + driver LO's in GHz. + meas_lo_freq (list): List of frequencies (as floats) for the' + measurement driver LO's in GHz. + memory_slot_size (int): Size of each memory slot if the output is + Level 0. + rep_time (int): Repetition time of the experiment in μs + shots (int): The number of shots + max_credits (int): the max_credits to use on the IBMQ public devices. + seed_simulator (int): the seed to use in the simulator + memory_slots (list): The number of memory slots on the device + kwargs: Additional free form key value fields to add to the + configuration + """ + self.meas_level = meas_level + self.meas_return = meas_return + self.pulse_library = pulse_library + self.qubit_lo_freq = qubit_lo_freq + self.meas_lo_freq = meas_lo_freq + if memory_slot_size is not None: + self.memory_slot_size = memory_slot_size + if rep_time is not None: + self.rep_time = rep_time or [] + if shots is not None: + self.shots = int(shots) + + if max_credits is not None: + self.max_credits = int(max_credits) + + if seed_simulator is not None: + self.seed_simulator = int(seed_simulator) + + if memory_slots is not None: + self.memory_slots = int(memory_slots) + + if kwargs: + self.__dict__.update(kwargs) + + def to_dict(self): + """Return a dictionary format representation of the Pulse Qobj config. + + Returns: + dict: The dictionary form of the PulseQobjConfig. + """ + out_dict = copy.copy(self.__dict__) + if hasattr(self, 'pulse_library'): + out_dict['pulse_library'] = [ + x.to_dict() for x in self.pulse_library] + + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new PulseQobjConfig object from a dictionary. + + Args: + data (dict): A dictionary for the config + + Returns: + PulseQobjConfig: The object from the input dictionary. + """ + if 'pulse_library' in data: + pulse_lib = data.pop('pulse_library') + pulse_lib_obj = [PulseLibraryItem.from_dict(x) for x in pulse_lib] + data['pulse_library'] = pulse_lib_obj + return cls(**data) + + +class PulseQobjExperiment: + """A Pulse Qobj Experiment. + + Each instance of this class is used to represent an individual Pulse + experiment as part of a larger Pulse Qobj. + """ + + def __init__(self, instructions, config=None, header=None): + """Instantiate a PulseQobjExperiment. + + Args: + config (PulseQobjExperimentConfig): A config object for the experiment + header (PulseQobjExperimentHeader): A header object for the experiment + instructions (list): A list of :class:`PulseQobjInstruction` objects + """ + if config is not None: + self.config = config + if header is not None: + self.header = header + self.instructions = instructions + + def to_dict(self): + """Return a dictionary format representation of the Experiment. + + Returns: + dict: The dictionary form of the PulseQobjExperiment. + """ + out_dict = { + 'instructions': [x.to_dict() for x in self.instructions] + } + if hasattr(self, 'config'): + out_dict['config'] = self.config.to_dict() + if hasattr(self, 'header'): + out_dict['header'] = self.header.to_dict() + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new PulseQobjExperiment object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + PulseQobjExperiment: The object from the input dictionary. + """ + config = None + if 'config' in data: + config = PulseQobjExperimentConfig.from_dict(data.pop('config')) + header = None + if 'header' in data: + header = QobjExperimentHeader.from_dict(data.pop('header')) + instructions = None + if 'instructions' in data: + instructions = [ + PulseQobjInstruction.from_dict( + inst) for inst in data.pop('instructions')] + return cls(instructions, config, header) + + def __eq__(self, other): + if isinstance(other, PulseQobjExperiment): + if self.to_dict() == other.to_dict(): + return True + return False + + +class PulseQobjExperimentConfig(QobjDictField): + """A config for a single Pulse experiment in the qobj.""" + + def __init__(self, qubit_lo_freq=None, meas_lo_freq=None, **kwargs): + """Instantiate a PulseQobjExperimentConfig object. + + Args: + qubit_lo_freq (list): List of frequencies (as floats) for the qubit + driver LO's in GHz. + meas_lo_freq (list): List of frequencies (as floats) for the' + measurement driver LO's in GHz. + kwargs: Additional free form key value fields to add to the + configuration + """ + if qubit_lo_freq is not None: + self.qubit_lo_freq = qubit_lo_freq + if meas_lo_freq is not None: + self.meas_lo_freq = meas_lo_freq + if kwargs: + self.__dict__.update(kwargs) + + +class PulseLibraryItem: + """An item in a pulse library.""" + + def __init__(self, name, samples): + """Instantiate a pulse library item. + + Args: + name (str): A name for the pulse. + samples (list[complex]): A list of complex values defining pulse + shape. + """ + self.name = name + self.samples = samples + + def to_dict(self): + """Return a dictionary format representation of the pulse library item. + + Returns: + dict: The dictionary form of the PulseLibraryItem. + """ + return {'name': self.name, 'samples': self.samples} + + @classmethod + def from_dict(cls, data): + """Create a new PulseLibraryItem object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + PulseLibraryItem: The object from the input dictionary. + """ + return cls(**data) + + def __eq__(self, other): + if isinstance(other, PulseLibraryItem): + if self.to_dict() == other.to_dict(): + return True + return False + + +class PulseQobj: + """A Pulse Qobj.""" + + def __init__(self, qobj_id, config, experiments, + header=None): + """Instatiate a new Pulse Qobj Object. + + Each Pulse Qobj object is used to represent a single payload that will + be passed to a Qiskit provider. It mirrors the Qobj the published + `Qobj specification `_ for Pulse + experiments. + + Args: + qobj_id (str): An identifier for the qobj + config (PulseQobjConfig): A config for the entire run + header (QobjHeader): A header for the entire run + experiments (list): A list of lists of :class:`PulseQobjExperiment` + objects representing an experiment + """ + self.qobj_id = qobj_id + self.config = config + self.header = header or QobjHeader() + self.experiments = experiments + self.type = 'PULSE' + self.schema_version = '1.1.0' + + def _validate_json_schema(self, out_dict): + class PulseQobjEncoder(json.JSONEncoder): + """A json encoder for pulse qobj""" + def default(self, obj): + if isinstance(obj, numpy.ndarray): + return obj.tolist() + if isinstance(obj, complex): + return (obj.real, obj.imag) + return json.JSONEncoder.default(self, obj) + + json_str = json.dumps(out_dict, cls=PulseQobjEncoder) + validator(json.loads(json_str)) + + def to_dict(self, validate=False): + """Return a dictionary format representation of the Pulse Qobj. + + Note this dict is not in the json wire format expected by IBMQ and qobj + specification because complex numbers are still of type complex. Also + this may contain native numpy arrays. When serializing this output + for use with IBMQ you can leverage a json encoder that converts these + as expected. For example: + + .. code-block:: + + import json + import numpy + + class QobjEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, numpy.ndarray): + return obj.tolist() + if isinstance(obj, complex): + return (obj.real, obj.imag) + return json.JSONEncoder.default(self, obj) + + json.dumps(qobj.to_dict(), cls=QobjEncoder) + + Args: + validate (bool): When set to true validate the output dictionary + against the jsonschema for qobj spec. + + Returns: + dict: A dictionary representation of the QasmQobj object + """ + out_dict = { + 'qobj_id': self.qobj_id, + 'header': self.header.to_dict(), + 'config': self.config.to_dict(), + 'schema_version': self.schema_version, + 'type': self.type, + 'experiments': [x.to_dict() for x in self.experiments] + } + if validate: + self._validate_json_schema(out_dict) + + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new PulseQobj object from a dictionary. + + Args: + data (dict): A dictionary representing the PulseQobj to create. It + will be in the same format as output by :func:`to_dict`. + + Returns: + PulseQobj: The PulseQobj from the input dictionary. + """ + config = None + if 'config' in data: + config = PulseQobjConfig.from_dict(data['config']) + experiments = None + if 'experiments' in data: + experiments = [ + PulseQobjExperiment.from_dict( + exp) for exp in data['experiments']] + header = None + if 'header' in data: + header = QobjHeader.from_dict(data['header']) + + return cls(qobj_id=data.get('qobj_id'), config=config, + experiments=experiments, header=header) + + def __eq__(self, other): + if isinstance(other, PulseQobj): + if self.to_dict() == other.to_dict(): + return True + return False diff --git a/qiskit/qobj/qasm_qobj.py b/qiskit/qobj/qasm_qobj.py new file mode 100644 index 000000000000..d86970d2b9ca --- /dev/null +++ b/qiskit/qobj/qasm_qobj.py @@ -0,0 +1,423 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +# pylint: disable=invalid-name + +"""Module providing definitions of QASM Qobj classes.""" + +import os +from types import SimpleNamespace + +import json +import fastjsonschema + + +path_part = 'schemas/qobj_schema.json' +path = os.path.join( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))), + path_part) +with open(path, 'r') as fd: + json_schema = json.loads(fd.read()) +validator = fastjsonschema.compile(json_schema) + + +class QasmQobjInstruction: + """A class representing a single instruction in an QasmQobj Experiment.""" + + def __init__(self, name, params=None, qubits=None, register=None, + memory=None, condition=None, conditional=None, label=None, + mask=None, relation=None, val=None): + """Instatiate a new QasmQobjInstruction object. + + Args: + name (str): The name of the instruction + params (list): The list of parameters for the gate + qubits (list): A list of ``int`` representing the qubits the + instruction operates on + register (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of register slots in which to + store the measurement results (must be the same length as + qubits). If a ``bfunc`` instruction this is a single ``int`` + of the register slot in which to store the result. + memory (list): If a ``measure`` instruction this is a list + of ``int`` containing the list of memory slots to store the + measurement results in (must be the same length as qubits). + If a ``bfunc`` instruction this is a single ``int`` of the + memory slot to store the boolean function result in. + condition (tuple): A tuple of the form ``(int, int)`` where the + first ``int`` is the control register and the second ``int`` is + the control value if the gate has a condition. + conditional (int): The register index of the condition + label (str): An optional label assigned to the instruction + mask (int): For a ``bfunc`` instruction the hex value which is + applied as an ``AND`` to the register bits. + relation (str): Relational operator for comparing the masked + register to the ``val`` kwarg. Can be either ``==`` (equals) or + ``!=`` (not equals). + val (int): Value to which to compare the masked register. In other + words, the output of the function is ``(register AND mask)`` + """ + self.name = name + if params is not None: + self.params = params + if qubits is not None: + self.qubits = qubits + if register is not None: + self.register = register + if memory is not None: + self.memory = memory + if condition is not None: + self._condition = condition + if conditional is not None: + self.conditional = conditional + if label is not None: + self.label = label + if mask is not None: + self.mask = mask + if relation is not None: + self.relation = relation + if val is not None: + self.val = val + + def to_dict(self): + """Return a dictionary format representation of the Instruction. + + Returns: + dict: The dictionary form of the QasmQobjInstruction. + """ + out_dict = {'name': self.name} + for attr in ['params', 'qubits', 'register', 'memory', '_condition', + 'conditional', 'label', 'mask', 'relation', 'val']: + if hasattr(self, attr): + out_dict[attr] = getattr(self, attr) + + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new QasmQobjInstruction object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + QasmQobjInstruction: The object from the input dictionary. + """ + name = data.pop('name') + return cls(name, **data) + + def __eq__(self, other): + if isinstance(other, QasmQobjInstruction): + if self.to_dict() == other.to_dict(): + return True + return False + + +class QasmQobjExperiment: + """A QASM Qobj Experiment. + + Each instance of this class is used to represent a QASM experiment as + part of a larger QASM qobj. + """ + + def __init__(self, config=None, header=None, instructions=None): + """Instatiate a QasmQobjExperiment. + + Args: + config (QasmQobjExperimentConfig): A config object for the experiment + header (QasmQobjExperimentHeader): A header object for the experiment + instructions (list): A list of :class:`QasmQobjInstruction` objects + """ + self.config = config or QasmQobjExperimentConfig() + self.header = header or QasmQobjExperimentHeader() + self.instructions = instructions or [] + + def to_dict(self): + """Return a dictionary format representation of the Experiment. + + Returns: + dict: The dictionary form of the QasmQObjExperiment. + """ + out_dict = { + 'config': self.config.to_dict(), + 'header': self.header.to_dict(), + 'instructions': [x.to_dict() for x in self.instructions] + } + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new QasmQobjExperiment object from a dictionary. + + Args: + data (dict): A dictionary for the experiment config + + Returns: + QasmQobjExperiment: The object from the input dictionary. + """ + config = None + if 'config' in data: + config = QasmQobjExperimentConfig.from_dict(data.pop('config')) + header = None + if 'header' in data: + header = QasmQobjExperimentHeader.from_dict(data.pop('header')) + instructions = None + if 'instructions' in data: + instructions = [ + QasmQobjInstruction.from_dict( + inst) for inst in data.pop('instructions')] + return cls(config, header, instructions) + + def __eq__(self, other): + if isinstance(other, QasmQobjExperiment): + if self.to_dict() == other.to_dict(): + return True + return False + + +class QasmQobjConfig(SimpleNamespace): + """A configuration for a QASM Qobj.""" + + def __init__(self, shots=None, max_credits=None, seed_simulator=None, + memory=None, parameter_binds=None, memory_slots=None, + n_qubits=None, **kwargs): + """Model for RunConfig. + + Args: + shots (int): the number of shots. + max_credits (int): the max_credits to use on the IBMQ public devices. + seed_simulator (int): the seed to use in the simulator + memory (bool): whether to request memory from backend (per-shot readouts) + parameter_binds (list[dict]): List of parameter bindings + memory_slots (int): The number of memory slots on the device + n_qubits (int): The number of qubits on the device + kwargs: Additional free form key value fields to add to the + configuration. + """ + if shots is not None: + self.shots = int(shots) + + if max_credits is not None: + self.max_credits = int(max_credits) + + if seed_simulator is not None: + self.seed_simulator = int(seed_simulator) + + if memory is not None: + self.memory = bool(memory) + + if parameter_binds is not None: + self.parameter_binds = parameter_binds + + if memory_slots is not None: + self.memory_slots = memory_slots + + if n_qubits is not None: + self.n_qubits = n_qubits + + if kwargs: + self.__dict__.update(kwargs) + + def to_dict(self): + """Return a dictionary format representation of the QASM Qobj config. + + Returns: + dict: The dictionary form of the QasmQobjConfig. + """ + return self.__dict__ + + @classmethod + def from_dict(cls, data): + """Create a new QasmQobjConfig object from a dictionary. + + Args: + data (dict): A dictionary for the config + + Returns: + QasmQobjConfig: The object from the input dictionary. + """ + return cls(**data) + + def __eq__(self, other): + if isinstance(other, QasmQobjConfig): + if self.to_dict() == other.to_dict(): + return True + return False + + +class QobjDictField(SimpleNamespace): + """A class used to represent a dictionary field in Qobj + + Exists as a backwards compatibility shim around a dictionary for Qobjs + previously constructed using marshmallow. + """ + + def __init__(self, **kwargs): + """Instantiate a new Qobj dict field object. + + Args: + kwargs: arbitrary keyword arguments that can be accessed as + attributes of the object. + """ + self.__dict__.update(kwargs) + + def to_dict(self): + """Return a dictionary format representation of the QASM Qobj. + + Returns: + dict: The dictionary form of the QobjHeader. + + """ + return self.__dict__ + + @classmethod + def from_dict(cls, data): + """Create a new QobjHeader object from a dictionary. + + Args: + data (dict): A dictionary representing the QobjHeader to create. It + will be in the same format as output by :func:`to_dict`. + + Returns: + QobjDictFieldr: The QobjDictField from the input dictionary. + """ + + return cls(**data) + + def __eq__(self, other): + if isinstance(other, self.__class__): + if self.__dict__ == other.__dict__: + return True + return False + + +class QasmQobjExperimentHeader(QobjDictField): + """A header for a single QASM experiment in the qobj.""" + pass + + +class QasmQobjExperimentConfig(QobjDictField): + """Configuration for a single QASM experiment in the qobj.""" + pass + + +class QobjHeader(QobjDictField): + """A class used to represent a dictionary header in Qobj objects.""" + pass + + +class QobjExperimentHeader(QobjHeader): + """A class representing a header dictionary for a Qobj Experiment.""" + pass + + +class QasmQobj: + """A QASM Qobj.""" + + def __init__(self, qobj_id=None, config=None, experiments=None, + header=None): + """Instatiate a new QASM Qobj Object. + + Each QASM Qobj object is used to represent a single payload that will + be passed to a Qiskit provider. It mirrors the Qobj the published + `Qobj specification `_ for OpenQASM + experiments. + + Args: + qobj_id (str): An identifier for the qobj + config (QasmQobjRunConfig): A config for the entire run + header (QobjHeader): A header for the entire run + experiments (list): A list of lists of :class:`QasmQobjExperiment` + objects representing an experiment + """ + self.header = header or QobjHeader() + self.config = config or QasmQobjConfig() + self.experiments = experiments or [] + self.qobj_id = qobj_id + + def to_dict(self, validate=False): + """Return a dictionary format representation of the QASM Qobj. + + Note this dict is not in the json wire format expected by IBMQ and qobj + specification because complex numbers are still of type complex. Also + this may contain native numpy arrays. When serializing this output + for use with IBMQ you can leverage a json encoder that converts these + as expected. For example: + + .. code-block:: + + import json + import numpy + + class QobjEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, numpy.ndarray): + return obj.tolist() + if isinstance(obj, complex): + return (obj.real, obj.imag) + return json.JSONEncoder.default(self, obj) + + json.dumps(qobj.to_dict(), cls=QobjEncoder) + + + Args: + validate (bool): When set to true validate the output dictionary + against the jsonschema for qobj spec. + + Returns: + dict: A dictionary representation of the QasmQobj object + """ + out_dict = { + 'qobj_id': self.qobj_id, + 'header': self.header.to_dict(), + 'config': self.config.to_dict(), + 'schema_version': '1.1.0', + 'type': 'QASM', + 'experiments': [x.to_dict() for x in self.experiments] + } + if validate: + validator(out_dict) + return out_dict + + @classmethod + def from_dict(cls, data): + """Create a new QASMQobj object from a dictionary. + + Args: + data (dict): A dictionary representing the QasmQobj to create. It + will be in the same format as output by :func:`to_dict`. + + Returns: + QasmQobj: The QasmQobj from the input dictionary. + """ + config = None + if 'config' in data: + config = QasmQobjConfig.from_dict(data['config']) + experiments = None + if 'experiments' in data: + experiments = [ + QasmQobjExperiment.from_dict( + exp) for exp in data['experiments']] + header = None + if 'header' in data: + header = QobjHeader.from_dict(data['header']) + + return cls(qobj_id=data.get('qobj_id'), config=config, + experiments=experiments, header=header) + + def __eq__(self, other): + if isinstance(other, QasmQobj): + if self.to_dict() == other.to_dict(): + return True + return False diff --git a/qiskit/qobj/qobj.py b/qiskit/qobj/qobj.py deleted file mode 100644 index 376f93c69a3a..000000000000 --- a/qiskit/qobj/qobj.py +++ /dev/null @@ -1,153 +0,0 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2017, 2019. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Model for Qobj.""" - -from marshmallow import pre_load -from marshmallow.validate import Equal, OneOf - -from qiskit.qobj.models.base import QobjExperimentSchema, QobjConfigSchema, QobjHeaderSchema -from qiskit.qobj.models.pulse import PulseQobjExperimentSchema, PulseQobjConfigSchema -from qiskit.qobj.models.qasm import QasmQobjExperimentSchema, QasmQobjConfigSchema -from qiskit.validation.base import BaseModel, BaseSchema, bind_schema -from qiskit.validation.fields import Nested, String -from .utils import QobjType - -QOBJ_VERSION = '1.1.0' - -"""Current version of the Qobj schema. - -Qobj schema versions: -* 1.1.0: Qiskit Terra 0.8 -* 1.0.0: Qiskit Terra 0.6 -* 0.0.1: Qiskit Terra 0.5.x format (pre-schemas). -""" - - -class QobjSchema(BaseSchema): - """Schema for Qobj.""" - # Required properties. - qobj_id = String(required=True) - schema_version = String(required=True) - - # Required properties depend on Qobj type. - config = Nested(QobjConfigSchema, required=True) - experiments = Nested(QobjExperimentSchema, required=True, many=True) - header = Nested(QobjHeaderSchema, required=True) - type = String(required=True, validate=OneOf(choices=(QobjType.QASM, QobjType.PULSE))) - - @pre_load - def add_schema_version(self, data, **_): - """Add the schema version on loading.""" - data['schema_version'] = QOBJ_VERSION - return data - - -class QasmQobjSchema(QobjSchema): - """Schema for QasmQobj.""" - - # Required properties. - config = Nested(QasmQobjConfigSchema, required=True) - experiments = Nested(QasmQobjExperimentSchema, required=True, many=True) - - type = String(required=True, validate=Equal(QobjType.QASM)) - - @pre_load - def add_type(self, data, **_): - """Add the Qobj type (QASM) on loading.""" - data['type'] = QobjType.QASM.value - return data - - -class PulseQobjSchema(QobjSchema): - """Schema for PulseQobj.""" - - # Required properties. - config = Nested(PulseQobjConfigSchema, required=True) - experiments = Nested(PulseQobjExperimentSchema, required=True, many=True) - - type = String(required=True, validate=Equal(QobjType.PULSE)) - - @pre_load - def add_type(self, data, **_): - """Add the Qobj type (PULSE) on loading.""" - data['type'] = QobjType.PULSE.value - return data - - -@bind_schema(QobjSchema) -class Qobj(BaseModel): - """Model for Qobj. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QobjSchema``. - - Attributes: - qobj_id (str): Qobj identifier. - config (QobjConfig): config settings for the Qobj. - experiments (list[QobjExperiment]): list of experiments. - header (QobjHeader): headers. - type (str): Qobj type. - """ - def __init__(self, qobj_id, config, experiments, header, type, **kwargs): - # pylint: disable=redefined-builtin - self.qobj_id = qobj_id - self.config = config - self.experiments = experiments - self.header = header - self.type = type - - super().__init__(**kwargs) - - -@bind_schema(QasmQobjSchema) -class QasmQobj(Qobj): - """Model for QasmQobj inherit from Qobj. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``QasmQobjSchema``. - - Attributes: - qobj_id (str): Qobj identifier. - config (QASMQobjConfig): config settings for the Qobj. - experiments (list[QASMQobjExperiment]): list of experiments. - header (QobjHeader): headers. - """ - def __init__(self, qobj_id, config, experiments, header, **kwargs): - super().__init__(qobj_id=qobj_id, - config=config, - experiments=experiments, - header=header, - **kwargs) - - -@bind_schema(PulseQobjSchema) -class PulseQobj(Qobj): - """Model for PulseQobj inherit from Qobj. - - Please note that this class only describes the required fields. For the - full description of the model, please check ``PulseQobjSchema``. - - Attributes: - qobj_id (str): Qobj identifier. - config (PulseQobjConfig): config settings for the Qobj. - experiments (list[PulseQobjExperiment]): list of experiments. - header (QobjHeader): headers. - """ - def __init__(self, qobj_id, config, experiments, header, **kwargs): - super().__init__(qobj_id=qobj_id, - config=config, - experiments=experiments, - header=header, - **kwargs) diff --git a/qiskit/qobj/utils.py b/qiskit/qobj/utils.py index 8bcf37cd7baa..d131d8081e50 100644 --- a/qiskit/qobj/utils.py +++ b/qiskit/qobj/utils.py @@ -16,7 +16,9 @@ from enum import Enum, IntEnum -from qiskit.validation.jsonschema import validate_json_against_schema +from fastjsonschema.exceptions import JsonSchemaException + +from qiskit.validation.jsonschema.exceptions import SchemaValidationError class QobjType(str, Enum): @@ -43,8 +45,13 @@ def validate_qobj_against_schema(qobj): Args: qobj (Qobj): Qobj to be validated. + + Raises: + SchemaValidationError: if the qobj fails schema validation """ - validate_json_against_schema( - qobj.to_dict(), 'qobj', - err_msg='Qobj failed validation. Set Qiskit log level to DEBUG ' - 'for further information.') + try: + qobj.to_dict(validate=True) + except JsonSchemaException as err: + msg = ("Qobj validation failed. Specifically path: %s failed to fulfil" + " %s" % (err.path, err.definition)) + raise SchemaValidationError(msg) diff --git a/qiskit/schemas/qobj_schema.json b/qiskit/schemas/qobj_schema.json index a78816fe3e81..e5e361f4a8d2 100644 --- a/qiskit/schemas/qobj_schema.json +++ b/qiskit/schemas/qobj_schema.json @@ -906,7 +906,6 @@ "description": "Configuration options that apply to all experiments in this qobj. For options that may be set on a per-experiment basis, these are the defaults.", "properties": { "max_credits": { - "default": 3, "type": "integer" }, "memory_slots": { @@ -920,7 +919,6 @@ "type": "integer" }, "seed": { - "default": 1, "type": "integer" }, "shots": { diff --git a/qiskit/test/mock/fake_openpulse_2q.py b/qiskit/test/mock/fake_openpulse_2q.py index a2d4bd4d60db..d2d3a27a723a 100644 --- a/qiskit/test/mock/fake_openpulse_2q.py +++ b/qiskit/test/mock/fake_openpulse_2q.py @@ -20,7 +20,7 @@ from qiskit.providers.models import (GateConfig, PulseBackendConfiguration, PulseDefaults, Command, UchannelLO) from qiskit.providers.models.backendproperties import Nduv, Gate, BackendProperties -from qiskit.qobj import PulseLibraryItem, PulseQobjInstruction +from qiskit.qobj import PulseQobjInstruction from .fake_backend import FakeBackend @@ -81,58 +81,124 @@ def __init__(self): } ) - self._defaults = PulseDefaults( - qubit_freq_est=[4.9, 5.0], - meas_freq_est=[6.5, 6.6], - buffer=10, - pulse_library=[PulseLibraryItem(name='test_pulse_1', samples=[0.j, 0.1j]), - PulseLibraryItem(name='test_pulse_2', samples=[0.j, 0.1j, 1j]), - PulseLibraryItem(name='test_pulse_3', - samples=[0.j, 0.1j, 1j, 0.5 + 0j]), - PulseLibraryItem(name='test_pulse_4', - samples=7*[0.j, 0.1j, 1j, 0.5 + 0j])], - cmd_def=[Command(name='u1', qubits=[0], - sequence=[PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P0')]), - Command(name='u1', qubits=[1], - sequence=[PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P0')]), - Command(name='u2', qubits=[0], - sequence=[PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P1'), - PulseQobjInstruction(name='test_pulse_4', ch='d0', t0=0), - PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P0')]), - Command(name='u2', qubits=[1], - sequence=[PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P1'), - PulseQobjInstruction(name='test_pulse_4', ch='d1', t0=0), - PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P0')]), - Command(name='u3', qubits=[0], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0)]), - Command(name='u3', qubits=[1], - sequence=[PulseQobjInstruction(name='test_pulse_3', ch='d1', t0=0)]), - Command(name='cx', qubits=[0, 1], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0), - PulseQobjInstruction(name='test_pulse_2', ch='u0', t0=10), - PulseQobjInstruction(name='test_pulse_1', ch='d1', t0=20), - PulseQobjInstruction(name='fc', ch='d1', - t0=20, phase=2.1)]), - Command(name='ParametrizedGate', qubits=[0, 1], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0), - PulseQobjInstruction(name='test_pulse_2', ch='u0', t0=10), - PulseQobjInstruction(name='pv', ch='d1', - t0=2, val='cos(P2)'), - PulseQobjInstruction(name='test_pulse_1', ch='d1', t0=20), - PulseQobjInstruction(name='fc', ch='d1', - t0=20, phase=2.1)]), - Command(name='measure', qubits=[0, 1], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='m0', t0=0), - PulseQobjInstruction(name='test_pulse_1', ch='m1', t0=0), - PulseQobjInstruction(name='acquire', duration=10, t0=0, - qubits=[0, 1], memory_slot=[0, 1])])] - ) + self._defaults = PulseDefaults.from_dict({ + 'qubit_freq_est': [4.9, 5.0], + 'meas_freq_est': [6.5, 6.6], + 'buffer': 10, + 'pulse_library': [ + { + 'name': 'test_pulse_1', + 'samples': [[0.0, 0.0], [0.0, 0.1]] + }, + { + 'name': 'test_pulse_2', + 'samples': [[0.0, 0.0], [0.0, 0.1], [0.0, 1.0]] + }, + { + 'name': 'test_pulse_3', + 'samples': [[0.0, 0.0], [0.0, 0.1], [0.0, 1.0], [0.5, 0.0]] + }, + { + 'name': 'test_pulse_4', + 'samples': 7 * [ + [0.0, 0.0], [0.0, 0.1], [0.0, 1.0], [0.5, 0.0] + ] + } + ], + 'cmd_def': [ + Command.from_dict({ + 'name': 'u1', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='fc', ch='d0', + t0=0, phase='-P0').to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'u1', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='fc', ch='d1', + t0=0, phase='-P0').to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'u2', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='fc', ch='d0', + t0=0, + phase='-P1').to_dict(), + PulseQobjInstruction(name='test_pulse_4', ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='fc', ch='d0', t0=0, + phase='-P0').to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'u2', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='fc', ch='d1', t0=0, + phase='-P1').to_dict(), + PulseQobjInstruction(name='test_pulse_4', + ch='d1', t0=0).to_dict(), + PulseQobjInstruction(name='fc', ch='d1', + t0=0, phase='-P0').to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'u3', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', ch='d0', + t0=0).to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'u3', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_3', ch='d1', + t0=0).to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'cx', + 'qubits': [0, 1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_2', ch='u0', + t0=10).to_dict(), + PulseQobjInstruction(name='test_pulse_1', ch='d1', + t0=20).to_dict(), + PulseQobjInstruction(name='fc', ch='d1', + t0=20, phase=2.1).to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'ParametrizedGate', + 'qubits': [0, 1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_2', ch='u0', + t0=10).to_dict(), + PulseQobjInstruction(name='pv', ch='d1', + t0=2, val='cos(P2)').to_dict(), + PulseQobjInstruction(name='test_pulse_1', ch='d1', + t0=20).to_dict(), + PulseQobjInstruction(name='fc', ch='d1', + t0=20, phase=2.1).to_dict() + ]}).to_dict(), + Command.from_dict({ + 'name': 'measure', + 'qubits': [0, 1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', ch='m0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_1', ch='m1', + t0=0).to_dict(), + PulseQobjInstruction(name='acquire', duration=10, t0=0, + qubits=[0, 1], + memory_slot=[0, 1]).to_dict() + ]}).to_dict() + ] + }) mock_time = datetime.datetime.now() dt = 1.3333 # pylint: disable=invalid-name diff --git a/qiskit/test/mock/fake_openpulse_3q.py b/qiskit/test/mock/fake_openpulse_3q.py index d0aac380ebf7..eb841cc9a567 100644 --- a/qiskit/test/mock/fake_openpulse_3q.py +++ b/qiskit/test/mock/fake_openpulse_3q.py @@ -18,7 +18,7 @@ from qiskit.providers.models import (GateConfig, PulseBackendConfiguration, PulseDefaults, Command, UchannelLO) -from qiskit.qobj import PulseLibraryItem, PulseQobjInstruction +from qiskit.qobj import PulseQobjInstruction from .fake_backend import FakeBackend @@ -69,74 +69,187 @@ def __init__(self): ] ) - self._defaults = PulseDefaults( - qubit_freq_est=[4.9, 5.0, 4.8], - meas_freq_est=[6.5, 6.6, 6.4], - buffer=10, - pulse_library=[PulseLibraryItem(name='test_pulse_1', samples=[0.j, 0.1j]), - PulseLibraryItem(name='test_pulse_2', samples=[0.j, 0.1j, 1j]), - PulseLibraryItem(name='test_pulse_3', - samples=[0.j, 0.1j, 1j, 0.5 + 0j]), - PulseLibraryItem(name='test_pulse_4', - samples=7*[0.j, 0.1j, 1j, 0.5 + 0j])], - cmd_def=[Command(name='u1', qubits=[0], - sequence=[PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P0')]), - Command(name='u1', qubits=[1], - sequence=[PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P0')]), - Command(name='u1', qubits=[2], - sequence=[PulseQobjInstruction(name='fc', ch='d2', - t0=0, phase='-P0')]), - Command(name='u2', qubits=[0], - sequence=[PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P1'), - PulseQobjInstruction(name='test_pulse_4', ch='d0', t0=0), - PulseQobjInstruction(name='fc', ch='d0', - t0=0, phase='-P0')]), - Command(name='u2', qubits=[1], - sequence=[PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P1'), - PulseQobjInstruction(name='test_pulse_4', ch='d1', t0=0), - PulseQobjInstruction(name='fc', ch='d1', - t0=0, phase='-P0')]), - Command(name='u2', qubits=[2], - sequence=[PulseQobjInstruction(name='test_pulse_3', ch='d2', t0=0), - PulseQobjInstruction(name='fc', ch='d2', - t0=0, phase='-P0')]), - Command(name='u3', qubits=[0], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0)]), - Command(name='u3', qubits=[1], - sequence=[PulseQobjInstruction(name='test_pulse_3', ch='d1', t0=0)]), - Command(name='cx', qubits=[0, 1], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0), - PulseQobjInstruction(name='test_pulse_2', ch='u0', t0=10), - PulseQobjInstruction(name='test_pulse_1', ch='d1', t0=20), - PulseQobjInstruction(name='fc', ch='d1', - t0=20, phase=2.1)]), - Command(name='cx', qubits=[1, 2], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d1', t0=0), - PulseQobjInstruction(name='test_pulse_2', ch='u1', t0=10), - PulseQobjInstruction(name='test_pulse_1', ch='d2', t0=20), - PulseQobjInstruction(name='fc', ch='d2', - t0=20, phase=2.1)]), - Command(name='ParametrizedGate', qubits=[0, 1], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='d0', t0=0), - PulseQobjInstruction(name='test_pulse_2', ch='u0', t0=10), - PulseQobjInstruction(name='pv', ch='d1', - t0=2, val='cos(P2)'), - PulseQobjInstruction(name='test_pulse_1', ch='d1', t0=20), - PulseQobjInstruction(name='fc', ch='d1', - t0=20, phase=2.1)]), - Command(name='measure', qubits=[0, 1, 2], - sequence=[PulseQobjInstruction(name='test_pulse_1', ch='m0', t0=0), - PulseQobjInstruction(name='test_pulse_1', ch='m1', t0=0), - PulseQobjInstruction(name='test_pulse_1', ch='m2', t0=0), - PulseQobjInstruction(name='acquire', duration=10, t0=0, - qubits=[0, 1, 2], - memory_slot=[0, 1, 2])])] - ) + self._defaults = PulseDefaults.from_dict({ + 'qubit_freq_est': [4.9, 5.0, 4.8], + 'meas_freq_est': [6.5, 6.6, 6.4], + 'buffer': 10, + 'pulse_library': [ + { + 'name': 'test_pulse_1', + 'samples': [[0.0, 0.0], [0.0, 0.1]] + }, + { + 'name': 'test_pulse_2', + 'samples': [[0.0, 0.0], [0.0, 0.1], [0.0, 1.0]] + }, + { + 'name': 'test_pulse_3', + 'samples': [[0.0, 0.0], [0.0, 0.1], [0.0, 1.0], [0.5, 0.0]] + }, + { + 'name': 'test_pulse_4', + 'samples': 7 * [ + [0.0, 0.0], [0.0, 0.1], [0.0, 1.0], [0.5, 0.0] + ] + } + ], + 'cmd_def': [ + Command.from_dict({ + 'name': 'u1', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='fc', + ch='d0', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u1', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='fc', + ch='d1', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u1', + 'qubits': [2], + 'sequence': [ + PulseQobjInstruction(name='fc', + ch='d2', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u2', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='fc', + ch='d0', + t0=0, + phase='-P1').to_dict(), + PulseQobjInstruction(name='test_pulse_4', + ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='fc', + ch='d0', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u2', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='fc', + ch='d1', + t0=0, + phase='-P1').to_dict(), + PulseQobjInstruction(name='test_pulse_4', + ch='d1', + t0=0).to_dict(), + PulseQobjInstruction(name='fc', + ch='d1', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u2', + 'qubits': [2], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_3', + ch='d2', + t0=0).to_dict(), + PulseQobjInstruction(name='fc', + ch='d2', + t0=0, + phase='-P0').to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u3', + 'qubits': [0], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', + ch='d0', + t0=0).to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'u3', + 'qubits': [1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_3', + ch='d1', + t0=0).to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'cx', + 'qubits': [0, 1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', + ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_2', + ch='u0', + t0=10).to_dict(), + PulseQobjInstruction(name='test_pulse_1', + ch='d1', + t0=20).to_dict(), + PulseQobjInstruction(name='fc', + ch='d1', + t0=20, + phase=2.1).to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'cx', + 'qubits': [1, 2], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', + ch='d1', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_2', + ch='u1', + t0=10).to_dict(), + PulseQobjInstruction(name='test_pulse_1', + ch='d2', + t0=20).to_dict(), + PulseQobjInstruction(name='fc', + ch='d2', + t0=20, + phase=2.1).to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'ParametrizedGate', + 'qubits': [0, 1], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', + ch='d0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_2', + ch='u0', + t0=10).to_dict(), + PulseQobjInstruction(name='pv', + ch='d1', + t0=2, + val='cos(P2)').to_dict(), + PulseQobjInstruction(name='test_pulse_1', + ch='d1', + t0=20).to_dict(), + PulseQobjInstruction(name='fc', + ch='d1', + t0=20, + phase=2.1).to_dict()]}).to_dict(), + Command.from_dict({ + 'name': 'measure', + 'qubits': [0, 1, 2], + 'sequence': [ + PulseQobjInstruction(name='test_pulse_1', + ch='m0', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_1', + ch='m1', + t0=0).to_dict(), + PulseQobjInstruction(name='test_pulse_1', + ch='m2', + t0=0).to_dict(), + PulseQobjInstruction(name='acquire', + duration=10, + t0=0, + qubits=[0, 1, 2], + memory_slot=[0, 1, 2]).to_dict()] + }).to_dict() + ] + }) super().__init__(configuration) def defaults(self): # pylint: disable=missing-docstring diff --git a/releasenotes/notes/qobj-no-marshmallow-3f2b3c7b10584b02.yaml b/releasenotes/notes/qobj-no-marshmallow-3f2b3c7b10584b02.yaml new file mode 100644 index 000000000000..24dfb75c07fb --- /dev/null +++ b/releasenotes/notes/qobj-no-marshmallow-3f2b3c7b10584b02.yaml @@ -0,0 +1,142 @@ +--- +upgrade: + - | + `fastjsonschema `_ is added as a + dependency. This is used for much faster validation of qobj dictionaries + against the JSON schema when the ``to_dict()`` method is called on qobj + objects with the ``validate`` set to ``True``. + - | + The classes: + + * ``QobjInstruction`` + * ``QobjExperimentHeader`` + * ``QobjExperimentConfig`` + * ``QobjExperiment`` + * ``QobjConfig`` + * ``QobjHeader`` + * ``PulseQobjInstruction`` + * ``PulseQobjExperimentConfig`` + * ``PulseQobjExperiment`` + * ``PulseQobjConfig`` + * ``QobjMeasurementOption`` + * ``PulseLibraryItem`` + * ``PulseLibraryItemSchema`` + * ``PulseQobjInstructionSchema`` + * ``QasmQobjInstruction`` + * ``QasmQobjExperimentConfig`` + * ``QasmQobjExperiment`` + * ``QasmQobjConfig`` + * ``QasmQobj`` + * ``PulseQobj`` + + from ``qiskit.qobj`` do not validate their inputs by default anymore. If + you would like to validate them against the qobj schema this can be done + by setting the ``validate`` kwarg to ``True`` on to_dict() method + from the top level classes ``QasmQobj`` and ``PulseQobj``. For example: + + .. code-block: + + from qiskit import qobj + + my_qasm = qobj.QasmQobj( + qobj_id='12345', + header=qobj.QobjHeader(), + config=qobj.QasmQobjConfig(shots=1024, memory_slots=2, + max_credits=10), + experiments=[ + qobj.QasmQobjExperiment(instructions=[ + qobj.QasmQobjInstruction(name='u1', qubits=[1], + params=[0.4]), + qobj.QasmQobjInstruction(name='u2', qubits=[1], + params=[0.4, 0.2]) + ]) + ] + ) + qasm_dict = my_qasm.to_dict(validate=True) + + which will validate the output dictionary against the Qasm jsonschema. + + - | + The output from ``qiskit.qobj.QasmQobj.to_dict()`` and + ``qiskit.qobj.PulseQobj.to_dict()`` is no longer in a dictionary format + for json serialization as expected by IBMQ's API. These Qobj objects are + the current format we pass to providers/backends and while having a + dictionary format that could just be passed to the IBMQ api directly was + moderately useful for the qiskit-ibmq-provider it made things more difficult + for other providers. Especially for providers that wrap local simulators. + Moving forward the definitions of what is passed between providers and + the IBMQ API requests will be further decoupled (in a backwards compatible + manner) which should ease the burden of writing providers and backends. + + The only functional difference between the output of these methods now is + that complex numbers are represented with the ``complex`` type and numpy + arrays are not silently converted to list types. If you want to json encode + a dictionary from the ``to_dict()`` methods as before this can be done by + building a custom json encoder. For example:: + + import json + + from qiskit import qobj + + my_qasm = qobj.QasmQobj( + qobj_id='12345', + header=qobj.QobjHeader(), + config=qobj.QasmQobjConfig(shots=1024, memory_slots=2, + max_credits=10), + experiments=[ + qobj.QasmQobjExperiment(instructions=[ + qobj.QasmQobjInstruction(name='u1', qubits=[1], + params=[0.4]), + qobj.QasmQobjInstruction(name='u2', qubits=[1], + params=[0.4, 0.2]) + ]) + ] + ) + qasm_dict = my_qasm.to_dict() + + class QobjEncoder(json.JSONEncoder): + """A json encoder for pulse qobj""" + def default(self, obj): + # Convert numpy arrays: + if hasattr(obj, 'tolist'): + return obj.tolist() + # Use Qobj complex json format: + if isinstance(obj, complex): + return (obj.real, obj.imag) + return json.JSONEncoder.default(self, obj) + + json_str = json.dumps(qasm_dict, cls=QobjEncoder) + + will generate a json string in the same exact manner that + ``json.dumps(my_qasm.to_dict())`` did in previous releases. + +other: + - | + The qasm and pulse qobj classes: + + * ``QobjInstruction`` + * ``QobjExperimentHeader`` + * ``QobjExperimentConfig`` + * ``QobjExperiment`` + * ``QobjConfig`` + * ``QobjHeader`` + * ``PulseQobjInstruction`` + * ``PulseQobjExperimentConfig`` + * ``PulseQobjExperiment`` + * ``PulseQobjConfig`` + * ``QobjMeasurementOption`` + * ``PulseLibraryItem`` + * ``PulseLibraryItemSchema`` + * ``PulseQobjInstructionSchema`` + * ``QasmQobjInstruction`` + * ``QasmQobjExperimentConfig`` + * ``QasmQobjExperiment`` + * ``QasmQobjConfig`` + * ``QasmQobj`` + * ``PulseQobj`` + + From ``qiskit.qobj`` have all been reimplemented without using the + marsmallow library. These new implementations are designed to be drop-in + replacement (except for as noted in the upgrade release notes) but + specifics inherited from marshmallow may not work. Please file issues for + any incompatibilities found. diff --git a/requirements.txt b/requirements.txt index 4532f6128d31..34497695c09e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ psutil>=5 scipy>=1.0 sympy>=1.3 dill>=0.3 +fastjsonschema>=2.10 python-constraint>=1.4 diff --git a/setup.py b/setup.py index ef388b0b73b3..9164532975ce 100755 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ "scipy>=1.0", "sympy>=1.3", "dill>=0.3", + "fastjsonschema>=2.10", "python-constraint>=1.4", ] diff --git a/test/python/circuit/test_unitary.py b/test/python/circuit/test_unitary.py index cd5d24793eca..fb07fe14589f 100644 --- a/test/python/circuit/test_unitary.py +++ b/test/python/circuit/test_unitary.py @@ -12,6 +12,8 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. +# pylint: disable=arguments-differ,method-hidden + """Quick program to test the qi tools modules.""" import json @@ -166,9 +168,20 @@ def test_qobj_with_unitary_matrix(self): self.assertEqual(instr.name, 'unitary') assert_allclose(numpy.array(instr.params[0]).astype(numpy.complex64), matrix) # check conversion to dict - qobj_dict = qobj.to_dict() + qobj_dict = qobj.to_dict(validate=True) + + class NumpyEncoder(json.JSONEncoder): + """Class for encoding json str with complex and numpy arrays.""" + def default(self, obj): + if isinstance(obj, numpy.ndarray): + return obj.tolist() + if isinstance(obj, complex): + return (obj.real, obj.imag) + return json.JSONEncoder.default(self, obj) + # check json serialization - self.assertTrue(isinstance(json.dumps(qobj_dict), str)) + self.assertTrue(isinstance(json.dumps(qobj_dict, cls=NumpyEncoder), + str)) def test_labeled_unitary(self): """test qobj output with unitary matrix""" diff --git a/test/python/compiler/test_assembler.py b/test/python/compiler/test_assembler.py index b10f5bcdd315..495b0bd7903c 100644 --- a/test/python/compiler/test_assembler.py +++ b/test/python/compiler/test_assembler.py @@ -632,9 +632,9 @@ def test_assemble_parametric(self): self.assertDictEqual(qobj_insts[2].parameters, {'duration': 25, 'amp': 1}) self.assertDictEqual(qobj_insts[3].parameters, {'duration': 150, 'sigma': 8, 'amp': 0.2, 'width': 140}) - self.assertListEqual( + self.assertEqual( qobj.to_dict()['experiments'][0]['instructions'][0]['parameters']['amp'], - [0.0, 0.5]) + 0.5j) def test_assemble_parametric_unsupported(self): """Test that parametric pulses are translated to SamplePulses if they're not supported diff --git a/test/python/qobj/test_qobj.py b/test/python/qobj/test_qobj.py index 8cc0a8f0848c..d0e810618773 100644 --- a/test/python/qobj/test_qobj.py +++ b/test/python/qobj/test_qobj.py @@ -67,7 +67,7 @@ def setUp(self): } self.bad_qobj = copy.deepcopy(self.valid_qobj) - self.bad_qobj.experiments = None # set experiments to None to cause the qobj to be invalid + self.bad_qobj.experiments = [] def test_to_dict_against_schema(self): """Test dictionary representation of Qobj against its schema.""" @@ -182,9 +182,7 @@ def setUp(self): 'memory_slot_size': 8192, 'meas_return': 'avg', 'pulse_library': [{'name': 'pulse0', - 'samples': [[0.0, 0.0], - [0.5, 0.0], - [0.0, 0.0]]} + 'samples': [0, 0.5, 0]} ], 'qubit_lo_freq': [4.9], 'meas_lo_freq': [6.9], @@ -195,7 +193,7 @@ def setUp(self): {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 1.57}, {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 0}, {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 'P1'}, - {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': [0.1, 0.0]}, + {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 0.1+0j}, {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 'P1'}, {'name': 'acquire', 't0': 15, 'duration': 5, 'qubits': [0], 'memory_slot': [0], @@ -234,14 +232,14 @@ def test_from_dict_per_class(self): {'meas_level': 1, 'memory_slot_size': 8192, 'meas_return': 'avg', - 'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}], + 'pulse_library': [{'name': 'pulse0', 'samples': [0.1 + 0j]}], 'qubit_lo_freq': [4.9], 'meas_lo_freq': [6.9], 'rep_time': 1000}, ), PulseLibraryItem: ( PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j]), - {'name': 'pulse0', 'samples': [[0.1, 0.0]]} + {'name': 'pulse0', 'samples': [0.1+0j]} ), PulseQobjExperiment: ( PulseQobjExperiment( @@ -277,14 +275,14 @@ def test_to_dict_per_class(self): {'meas_level': 1, 'memory_slot_size': 8192, 'meas_return': 'avg', - 'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}], + 'pulse_library': [{'name': 'pulse0', 'samples': [0.1+0j]}], 'qubit_lo_freq': [4.9], 'meas_lo_freq': [6.9], 'rep_time': 1000}, ), PulseLibraryItem: ( PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j]), - {'name': 'pulse0', 'samples': [[0.1, 0.0]]} + {'name': 'pulse0', 'samples': [0.1+0j]} ), PulseQobjExperiment: ( PulseQobjExperiment(