mirror of https://github.com/Qiskit/qiskit.git
PulseQobj and Json Schema updates for pulse simulator (#2052)
* add json schema of pulse simulator configuration * update custom field of nested dictionary parameter * add hamiltonian schema * change dt validation type to float * add specific QobjConfig * remove simulator dedicated config * remove helper qobjs and use pattern properties * update unittest * avoid lint error * relax required restriction in pulse config * modify simulator config and add schema for each field * fix schema * update unittest * removed unnecessary validation * remove lint error * change module name and import * update simulator_spec * set required to meas_lo_freq and qubit_lo_freq * update field name * allow for empty list of gates and basis_gates * remove lint error * reordered pulse qobj config arguments. * Remove simulator_spec from jsonschema. * remove simulator spec.
This commit is contained in:
parent
eddef45d42
commit
7922df9518
|
@ -7,9 +7,8 @@
|
||||||
|
|
||||||
"""Module for the Qobj structure."""
|
"""Module for the Qobj structure."""
|
||||||
|
|
||||||
from .models.base import (QobjInstruction, QobjExperimentHeader,
|
from .models.base import (QobjInstruction, QobjExperimentHeader, QobjExperimentConfig,
|
||||||
QobjExperimentConfig, QobjExperiment,
|
QobjExperiment, QobjConfig, QobjHeader)
|
||||||
QobjConfig, QobjHeader)
|
|
||||||
|
|
||||||
from .models.pulse import (PulseQobjInstruction, PulseQobjExperimentConfig,
|
from .models.pulse import (PulseQobjInstruction, PulseQobjExperimentConfig,
|
||||||
PulseQobjExperiment, PulseQobjConfig,
|
PulseQobjExperiment, PulseQobjConfig,
|
||||||
|
|
|
@ -10,9 +10,8 @@
|
||||||
from marshmallow.validate import Range, Regexp, Length, OneOf
|
from marshmallow.validate import Range, Regexp, Length, OneOf
|
||||||
|
|
||||||
from qiskit.qobj.utils import MeasReturnType
|
from qiskit.qobj.utils import MeasReturnType
|
||||||
from qiskit.validation import bind_schema, BaseSchema, BaseModel
|
from qiskit.validation import BaseSchema, bind_schema, BaseModel
|
||||||
from qiskit.validation.fields import (Integer, String, Number, Complex,
|
from qiskit.validation.fields import Integer, String, Number, Complex, List, Nested, DictParameters
|
||||||
List, Nested, MeasurementParameter)
|
|
||||||
from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema,
|
from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema,
|
||||||
QobjConfigSchema, QobjInstruction, QobjExperimentConfig,
|
QobjConfigSchema, QobjInstruction, QobjExperimentConfig,
|
||||||
QobjExperiment, QobjConfig)
|
QobjExperiment, QobjConfig)
|
||||||
|
@ -23,7 +22,8 @@ class QobjMeasurementOptionSchema(BaseSchema):
|
||||||
|
|
||||||
# Required properties.
|
# Required properties.
|
||||||
name = String(required=True)
|
name = String(required=True)
|
||||||
params = MeasurementParameter(required=True)
|
params = DictParameters(valid_value_types=(int, float, str, bool, type(None)),
|
||||||
|
required=True)
|
||||||
|
|
||||||
|
|
||||||
class QobjPulseLibrarySchema(BaseSchema):
|
class QobjPulseLibrarySchema(BaseSchema):
|
||||||
|
@ -76,18 +76,20 @@ class PulseQobjExperimentSchema(QobjExperimentSchema):
|
||||||
|
|
||||||
|
|
||||||
class PulseQobjConfigSchema(QobjConfigSchema):
|
class PulseQobjConfigSchema(QobjConfigSchema):
|
||||||
"""Schema for PulseQobjConfig."""
|
"""Schema for PulseQobjConfig of device backend."""
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
|
||||||
# Required properties.
|
# Required properties.
|
||||||
# TODO : check if they are always required by backend
|
|
||||||
meas_level = Integer(required=True, validate=Range(min=0, max=2))
|
meas_level = Integer(required=True, validate=Range(min=0, max=2))
|
||||||
memory_slot_size = Integer(required=True)
|
meas_return = String(required=True, validate=OneOf(choices=(MeasReturnType.AVERAGE,
|
||||||
pulse_library = Nested(QobjPulseLibrarySchema, many=True, required=True)
|
MeasReturnType.SINGLE)))
|
||||||
qubit_lo_freq = List(Number(), required=True)
|
pulse_library = Nested(QobjPulseLibrarySchema, required=True, many=True)
|
||||||
meas_lo_freq = List(Number(), required=True)
|
qubit_lo_freq = List(Number(validate=Range(min=0)), required=True)
|
||||||
rep_time = Integer(required=True)
|
meas_lo_freq = List(Number(validate=Range(min=0)), required=True)
|
||||||
meas_return = String(validate=OneOf(choices=(MeasReturnType.AVERAGE,
|
|
||||||
MeasReturnType.SINGLE)))
|
# Optional properties.
|
||||||
|
memory_slot_size = Integer(validate=Range(min=1))
|
||||||
|
rep_time = Integer(validate=Range(min=0))
|
||||||
|
|
||||||
|
|
||||||
@bind_schema(QobjMeasurementOptionSchema)
|
@bind_schema(QobjMeasurementOptionSchema)
|
||||||
|
@ -182,29 +184,22 @@ class PulseQobjConfig(QobjConfig):
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
meas_level (int): a value represents the level of measurement.
|
meas_level (int): a value represents the level of measurement.
|
||||||
memory_slot_size (int): size of memory slot
|
meas_lo_freq (list[float]): local oscillator frequency of measurement pulse.
|
||||||
meas_return (str): a level of measurement information.
|
meas_return (str): a level of measurement information.
|
||||||
pulse_library (list[QobjPulseLibrary]): a pulse library.
|
pulse_library (list[qiskit.qobj.QobjPulseLibrary]): a pulse library.
|
||||||
qubit_lo_freq (list): the list of frequencies for qubit drive LO's in GHz.
|
qubit_lo_freq (list[float]): local oscillator frequency of driving pulse.
|
||||||
meas_lo_freq (list): the list of frequencies for measurement drive LO's in GHz.
|
|
||||||
rep_time (int): the value of repetition time of experiment in us.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, meas_level, memory_slot_size, meas_return,
|
def __init__(self, meas_level, meas_return, pulse_library,
|
||||||
pulse_library, qubit_lo_freq, meas_lo_freq, rep_time,
|
qubit_lo_freq, meas_lo_freq, **kwargs):
|
||||||
**kwargs):
|
|
||||||
self.meas_level = meas_level
|
self.meas_level = meas_level
|
||||||
self.memory_slot_size = memory_slot_size
|
|
||||||
self.meas_return = meas_return
|
self.meas_return = meas_return
|
||||||
self.pulse_library = pulse_library
|
self.pulse_library = pulse_library
|
||||||
self.qubit_lo_freq = qubit_lo_freq
|
self.qubit_lo_freq = qubit_lo_freq
|
||||||
self.meas_lo_freq = meas_lo_freq
|
self.meas_lo_freq = meas_lo_freq
|
||||||
self.rep_time = rep_time
|
|
||||||
|
|
||||||
super().__init__(meas_level=meas_level,
|
super().__init__(meas_level=meas_level,
|
||||||
memory_slot_size=memory_slot_size,
|
|
||||||
meas_return=meas_return,
|
meas_return=meas_return,
|
||||||
pulse_library=pulse_library,
|
pulse_library=pulse_library,
|
||||||
qubit_lo_freq=qubit_lo_freq,
|
qubit_lo_freq=qubit_lo_freq,
|
||||||
meas_lo_freq=meas_lo_freq,
|
meas_lo_freq=meas_lo_freq,
|
||||||
rep_time=rep_time,
|
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of basis gates names on the backend",
|
"description": "List of basis gates names on the backend",
|
||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
"minItems": 1
|
"minItems": 0
|
||||||
},
|
},
|
||||||
"coupling_map": {
|
"coupling_map": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of basis gates on the backend",
|
"description": "List of basis gates on the backend",
|
||||||
"items": {"$ref": "#/definitions/gateconfig"},
|
"items": {"$ref": "#/definitions/gateconfig"},
|
||||||
"minItems": 1
|
"minItems": 0
|
||||||
},
|
},
|
||||||
"local": {
|
"local": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|
|
@ -720,7 +720,7 @@
|
||||||
"description": "Total number of qubits used in this experiment.",
|
"description": "Total number of qubits used in this experiment.",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Experiment level configuration",
|
"title": "Experiment level configuration",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
@ -736,10 +736,10 @@
|
||||||
"description": "Total number of (slow) measurement slots used in this experiment.",
|
"description": "Total number of (slow) measurement slots used in this experiment.",
|
||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"n_qubits": {
|
"n_qubits": {
|
||||||
"description": "Total number of qubits used in this experiment.",
|
"description": "Total number of qubits used in this experiment.",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"qreg_sizes": {
|
"qreg_sizes": {
|
||||||
|
@ -895,7 +895,7 @@
|
||||||
"description": "The number of qubits requested on the backend, equivalent to the max of n_qubits requested by individual experiments.",
|
"description": "The number of qubits requested on the backend, equivalent to the max of n_qubits requested by individual experiments.",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"seed": {
|
"seed": {
|
||||||
"default": 1,
|
"default": 1,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -904,7 +904,7 @@
|
||||||
"description": "Number of repetitions of each experiment",
|
"description": "Number of repetitions of each experiment",
|
||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": "Qobj-level configuration",
|
"title": "Qobj-level configuration",
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
@ -1007,12 +1007,10 @@
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"meas_level",
|
"meas_level",
|
||||||
"pulse_library",
|
|
||||||
"memory_slot_size",
|
|
||||||
"meas_return",
|
|
||||||
"qubit_lo_freq",
|
|
||||||
"meas_lo_freq",
|
"meas_lo_freq",
|
||||||
"rep_time"
|
"meas_return",
|
||||||
|
"pulse_library",
|
||||||
|
"qubit_lo_freq"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"experiments": {
|
"experiments": {
|
||||||
|
|
|
@ -31,9 +31,9 @@ from marshmallow import fields as _fields
|
||||||
|
|
||||||
from qiskit.validation import ModelTypeValidator
|
from qiskit.validation import ModelTypeValidator
|
||||||
from qiskit.validation.fields.polymorphic import ByAttribute, ByType, TryFrom
|
from qiskit.validation.fields.polymorphic import ByAttribute, ByType, TryFrom
|
||||||
from qiskit.validation.fields.containers import Nested, List
|
from qiskit.validation.fields.containers import Nested, List, Dict
|
||||||
|
|
||||||
from .custom import Complex, InstructionParameter, MeasurementParameter
|
from .custom import Complex, InstructionParameter, DictParameters
|
||||||
|
|
||||||
|
|
||||||
class String(_fields.String, ModelTypeValidator):
|
class String(_fields.String, ModelTypeValidator):
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
"""Container fields that represent nested/collections of schemas or types."""
|
"""Container fields that represent nested/collections of schemas or types."""
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable, Mapping
|
||||||
|
|
||||||
from marshmallow import fields as _fields
|
from marshmallow import fields as _fields
|
||||||
from marshmallow.exceptions import ValidationError
|
from marshmallow.exceptions import ValidationError
|
||||||
|
@ -74,3 +74,10 @@ class List(_fields.List, ModelTypeValidator):
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class Dict(_fields.Dict, ModelTypeValidator):
|
||||||
|
# pylint: disable=missing-docstring
|
||||||
|
__doc__ = _fields.Dict.__doc__
|
||||||
|
|
||||||
|
valid_types = (Mapping, )
|
||||||
|
|
|
@ -12,7 +12,7 @@ import sympy
|
||||||
|
|
||||||
from marshmallow.utils import is_collection
|
from marshmallow.utils import is_collection
|
||||||
from marshmallow.exceptions import ValidationError
|
from marshmallow.exceptions import ValidationError
|
||||||
from marshmallow.compat import Mapping, Iterable
|
from marshmallow.compat import Mapping
|
||||||
|
|
||||||
from qiskit.validation import ModelTypeValidator
|
from qiskit.validation import ModelTypeValidator
|
||||||
|
|
||||||
|
@ -124,15 +124,27 @@ class InstructionParameter(ModelTypeValidator):
|
||||||
return root_value
|
return root_value
|
||||||
|
|
||||||
|
|
||||||
class MeasurementParameter(ModelTypeValidator):
|
class DictParameters(ModelTypeValidator):
|
||||||
"""Field for objects used in measurement kernel and discriminator parameters.
|
"""Field for objects used in measurement kernel and discriminator parameters.
|
||||||
"""
|
"""
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid': 'Not a valid mapping type.',
|
'invalid_mapping': 'Not a valid mapping type.',
|
||||||
'invalid_sub': 'Not a valid value.'
|
'invalid': '{input} cannot be parsed as a parameter.'
|
||||||
}
|
}
|
||||||
|
|
||||||
valid_types = (int, float, str, bool, Iterable, Mapping, type(None))
|
def __init__(self, valid_value_types, **kwargs):
|
||||||
|
"""Create new model.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
valid_value_types (tuple): valid types as values.
|
||||||
|
"""
|
||||||
|
# pylint: disable=missing-param-doc
|
||||||
|
|
||||||
|
super(DictParameters, self).__init__(**kwargs)
|
||||||
|
self.valid_value_types = valid_value_types
|
||||||
|
|
||||||
|
def _expected_types(self):
|
||||||
|
return self.valid_value_types
|
||||||
|
|
||||||
def check_type(self, value, attr, data):
|
def check_type(self, value, attr, data):
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -141,41 +153,47 @@ class MeasurementParameter(ModelTypeValidator):
|
||||||
_check_type = super().check_type
|
_check_type = super().check_type
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
if isinstance(value, Mapping):
|
if not isinstance(data[attr], Mapping):
|
||||||
for v in value.values():
|
self.fail('invalid_mapping')
|
||||||
try:
|
|
||||||
_check_type(v, None, value)
|
try:
|
||||||
except ValidationError as err:
|
if isinstance(value, Mapping):
|
||||||
errors.append(err.messages)
|
for v in value.values():
|
||||||
else:
|
self.check_type(v, attr, data)
|
||||||
errors.append('Not a valid mapping type.')
|
elif is_collection(value):
|
||||||
|
for v in value:
|
||||||
|
self.check_type(v, attr, data)
|
||||||
|
else:
|
||||||
|
_check_type(value, attr, data)
|
||||||
|
except ValidationError as err:
|
||||||
|
errors.append(err.messages)
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def _serialize_sub(self, value):
|
def _validate_values(self, value):
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
if isinstance(value, (int, float, str, bool)):
|
if isinstance(value, self.valid_value_types):
|
||||||
return value
|
return value
|
||||||
if isinstance(value, Iterable):
|
if is_collection(value):
|
||||||
return [self._serialize_sub(each) for each in value]
|
return [self._validate_values(each) for each in value]
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
return {str(k): self._serialize_sub(v) for k, v in value.items()}
|
return {str(k): self._validate_values(v) for k, v in value.items()}
|
||||||
|
|
||||||
return self.fail('invalid_sub', input=value)
|
return self.fail('invalid', input=value)
|
||||||
|
|
||||||
def _serialize(self, value, attr, obj):
|
def _serialize(self, value, attr, obj):
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
return {str(k): self._serialize_sub(v) for k, v in value.items()}
|
return {str(k): self._validate_values(v) for k, v in value.items()}
|
||||||
|
|
||||||
return self.fail('invalid')
|
return self.fail('invalid_mapping')
|
||||||
|
|
||||||
def _deserialize(self, value, attr, data):
|
def _deserialize(self, value, attr, data):
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
|
@ -184,4 +202,4 @@ class MeasurementParameter(ModelTypeValidator):
|
||||||
if isinstance(value, Mapping):
|
if isinstance(value, Mapping):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
return self.fail('invalid')
|
return self.fail('invalid_mapping')
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
"""Validators for Qiskit validated classes."""
|
"""Validators for Qiskit validated classes."""
|
||||||
|
|
||||||
|
from collections.abc import Mapping
|
||||||
|
|
||||||
from marshmallow import ValidationError
|
from marshmallow import ValidationError
|
||||||
from marshmallow.validate import Validator
|
from marshmallow.validate import Validator
|
||||||
|
|
||||||
|
@ -68,7 +70,13 @@ class PatternProperties(Validator):
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
errors = {}
|
errors = {}
|
||||||
for key, value_ in value.__dict__.items():
|
|
||||||
|
if isinstance(value, Mapping):
|
||||||
|
_dict = value
|
||||||
|
else:
|
||||||
|
_dict = value.__dict__
|
||||||
|
|
||||||
|
for key, value_ in _dict.items():
|
||||||
# Attempt to validate the keys against any field.
|
# Attempt to validate the keys against any field.
|
||||||
field = None
|
field = None
|
||||||
for validator, candidate in self.pattern_properties.items():
|
for validator, candidate in self.pattern_properties.items():
|
||||||
|
|
|
@ -178,8 +178,7 @@ class TestPulseQobj(QiskitTestCase):
|
||||||
],
|
],
|
||||||
'qubit_lo_freq': [4.9],
|
'qubit_lo_freq': [4.9],
|
||||||
'meas_lo_freq': [6.9],
|
'meas_lo_freq': [6.9],
|
||||||
'rep_time': 1000
|
'rep_time': 1000},
|
||||||
},
|
|
||||||
'experiments': [
|
'experiments': [
|
||||||
{'instructions': [
|
{'instructions': [
|
||||||
{'name': 'pulse0', 't0': 0, 'ch': 'd0'},
|
{'name': 'pulse0', 't0': 0, 'ch': 'd0'},
|
||||||
|
@ -225,7 +224,7 @@ class TestPulseQobj(QiskitTestCase):
|
||||||
'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}],
|
'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}],
|
||||||
'qubit_lo_freq': [4.9],
|
'qubit_lo_freq': [4.9],
|
||||||
'meas_lo_freq': [6.9],
|
'meas_lo_freq': [6.9],
|
||||||
'rep_time': 1000}
|
'rep_time': 1000},
|
||||||
),
|
),
|
||||||
QobjPulseLibrary: (
|
QobjPulseLibrary: (
|
||||||
QobjPulseLibrary(name='pulse0', samples=[0.1 + 0.0j]),
|
QobjPulseLibrary(name='pulse0', samples=[0.1 + 0.0j]),
|
||||||
|
|
Loading…
Reference in New Issue