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."""
|
||||
|
||||
from .models.base import (QobjInstruction, QobjExperimentHeader,
|
||||
QobjExperimentConfig, QobjExperiment,
|
||||
QobjConfig, QobjHeader)
|
||||
from .models.base import (QobjInstruction, QobjExperimentHeader, QobjExperimentConfig,
|
||||
QobjExperiment, QobjConfig, QobjHeader)
|
||||
|
||||
from .models.pulse import (PulseQobjInstruction, PulseQobjExperimentConfig,
|
||||
PulseQobjExperiment, PulseQobjConfig,
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
from marshmallow.validate import Range, Regexp, Length, OneOf
|
||||
|
||||
from qiskit.qobj.utils import MeasReturnType
|
||||
from qiskit.validation import bind_schema, BaseSchema, BaseModel
|
||||
from qiskit.validation.fields import (Integer, String, Number, Complex,
|
||||
List, Nested, MeasurementParameter)
|
||||
from qiskit.validation import BaseSchema, bind_schema, BaseModel
|
||||
from qiskit.validation.fields import Integer, String, Number, Complex, List, Nested, DictParameters
|
||||
from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema,
|
||||
QobjConfigSchema, QobjInstruction, QobjExperimentConfig,
|
||||
QobjExperiment, QobjConfig)
|
||||
|
@ -23,7 +22,8 @@ class QobjMeasurementOptionSchema(BaseSchema):
|
|||
|
||||
# Required properties.
|
||||
name = String(required=True)
|
||||
params = MeasurementParameter(required=True)
|
||||
params = DictParameters(valid_value_types=(int, float, str, bool, type(None)),
|
||||
required=True)
|
||||
|
||||
|
||||
class QobjPulseLibrarySchema(BaseSchema):
|
||||
|
@ -76,18 +76,20 @@ class PulseQobjExperimentSchema(QobjExperimentSchema):
|
|||
|
||||
|
||||
class PulseQobjConfigSchema(QobjConfigSchema):
|
||||
"""Schema for PulseQobjConfig."""
|
||||
"""Schema for PulseQobjConfig of device backend."""
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
# Required properties.
|
||||
# TODO : check if they are always required by backend
|
||||
meas_level = Integer(required=True, validate=Range(min=0, max=2))
|
||||
memory_slot_size = Integer(required=True)
|
||||
pulse_library = Nested(QobjPulseLibrarySchema, many=True, required=True)
|
||||
qubit_lo_freq = List(Number(), required=True)
|
||||
meas_lo_freq = List(Number(), required=True)
|
||||
rep_time = Integer(required=True)
|
||||
meas_return = String(validate=OneOf(choices=(MeasReturnType.AVERAGE,
|
||||
MeasReturnType.SINGLE)))
|
||||
meas_return = String(required=True, validate=OneOf(choices=(MeasReturnType.AVERAGE,
|
||||
MeasReturnType.SINGLE)))
|
||||
pulse_library = Nested(QobjPulseLibrarySchema, 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)
|
||||
|
@ -182,29 +184,22 @@ class PulseQobjConfig(QobjConfig):
|
|||
|
||||
Attributes:
|
||||
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.
|
||||
pulse_library (list[QobjPulseLibrary]): a pulse library.
|
||||
qubit_lo_freq (list): the list of frequencies for qubit drive LO's in GHz.
|
||||
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.
|
||||
pulse_library (list[qiskit.qobj.QobjPulseLibrary]): a pulse library.
|
||||
qubit_lo_freq (list[float]): local oscillator frequency of driving pulse.
|
||||
"""
|
||||
def __init__(self, meas_level, memory_slot_size, meas_return,
|
||||
pulse_library, qubit_lo_freq, meas_lo_freq, rep_time,
|
||||
**kwargs):
|
||||
def __init__(self, meas_level, meas_return, pulse_library,
|
||||
qubit_lo_freq, meas_lo_freq, **kwargs):
|
||||
self.meas_level = meas_level
|
||||
self.memory_slot_size = memory_slot_size
|
||||
self.meas_return = meas_return
|
||||
self.pulse_library = pulse_library
|
||||
self.qubit_lo_freq = qubit_lo_freq
|
||||
self.meas_lo_freq = meas_lo_freq
|
||||
self.rep_time = rep_time
|
||||
|
||||
super().__init__(meas_level=meas_level,
|
||||
memory_slot_size=memory_slot_size,
|
||||
meas_return=meas_return,
|
||||
pulse_library=pulse_library,
|
||||
qubit_lo_freq=qubit_lo_freq,
|
||||
meas_lo_freq=meas_lo_freq,
|
||||
rep_time=rep_time,
|
||||
**kwargs)
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"type": "array",
|
||||
"description": "List of basis gates names on the backend",
|
||||
"items": {"type": "string"},
|
||||
"minItems": 1
|
||||
"minItems": 0
|
||||
},
|
||||
"coupling_map": {
|
||||
"type": "array",
|
||||
|
@ -66,7 +66,7 @@
|
|||
"type": "array",
|
||||
"description": "List of basis gates on the backend",
|
||||
"items": {"$ref": "#/definitions/gateconfig"},
|
||||
"minItems": 1
|
||||
"minItems": 0
|
||||
},
|
||||
"local": {
|
||||
"type": "boolean",
|
||||
|
|
|
@ -720,7 +720,7 @@
|
|||
"description": "Total number of qubits used in this experiment.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Experiment level configuration",
|
||||
"type": "object"
|
||||
|
@ -736,10 +736,10 @@
|
|||
"description": "Total number of (slow) measurement slots used in this experiment.",
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"n_qubits": {
|
||||
"description": "Total number of qubits used in this experiment.",
|
||||
"minimum": 1,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"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.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
},
|
||||
"seed": {
|
||||
"default": 1,
|
||||
"type": "integer"
|
||||
|
@ -904,7 +904,7 @@
|
|||
"description": "Number of repetitions of each experiment",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Qobj-level configuration",
|
||||
"type": "object"
|
||||
|
@ -1007,12 +1007,10 @@
|
|||
},
|
||||
"required": [
|
||||
"meas_level",
|
||||
"pulse_library",
|
||||
"memory_slot_size",
|
||||
"meas_return",
|
||||
"qubit_lo_freq",
|
||||
"meas_lo_freq",
|
||||
"rep_time"
|
||||
"meas_return",
|
||||
"pulse_library",
|
||||
"qubit_lo_freq"
|
||||
]
|
||||
},
|
||||
"experiments": {
|
||||
|
|
|
@ -31,9 +31,9 @@ from marshmallow import fields as _fields
|
|||
|
||||
from qiskit.validation import ModelTypeValidator
|
||||
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):
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
"""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.exceptions import ValidationError
|
||||
|
@ -74,3 +74,10 @@ class List(_fields.List, ModelTypeValidator):
|
|||
raise ValidationError(errors)
|
||||
|
||||
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.exceptions import ValidationError
|
||||
from marshmallow.compat import Mapping, Iterable
|
||||
from marshmallow.compat import Mapping
|
||||
|
||||
from qiskit.validation import ModelTypeValidator
|
||||
|
||||
|
@ -124,15 +124,27 @@ class InstructionParameter(ModelTypeValidator):
|
|||
return root_value
|
||||
|
||||
|
||||
class MeasurementParameter(ModelTypeValidator):
|
||||
class DictParameters(ModelTypeValidator):
|
||||
"""Field for objects used in measurement kernel and discriminator parameters.
|
||||
"""
|
||||
default_error_messages = {
|
||||
'invalid': 'Not a valid mapping type.',
|
||||
'invalid_sub': 'Not a valid value.'
|
||||
'invalid_mapping': 'Not a valid mapping type.',
|
||||
'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):
|
||||
if value is None:
|
||||
|
@ -141,41 +153,47 @@ class MeasurementParameter(ModelTypeValidator):
|
|||
_check_type = super().check_type
|
||||
|
||||
errors = []
|
||||
if isinstance(value, Mapping):
|
||||
for v in value.values():
|
||||
try:
|
||||
_check_type(v, None, value)
|
||||
except ValidationError as err:
|
||||
errors.append(err.messages)
|
||||
else:
|
||||
errors.append('Not a valid mapping type.')
|
||||
if not isinstance(data[attr], Mapping):
|
||||
self.fail('invalid_mapping')
|
||||
|
||||
try:
|
||||
if isinstance(value, Mapping):
|
||||
for v in value.values():
|
||||
self.check_type(v, attr, data)
|
||||
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:
|
||||
raise ValidationError(errors)
|
||||
|
||||
return value
|
||||
|
||||
def _serialize_sub(self, value):
|
||||
def _validate_values(self, value):
|
||||
# pylint: disable=too-many-return-statements
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, (int, float, str, bool)):
|
||||
if isinstance(value, self.valid_value_types):
|
||||
return value
|
||||
if isinstance(value, Iterable):
|
||||
return [self._serialize_sub(each) for each in value]
|
||||
if is_collection(value):
|
||||
return [self._validate_values(each) for each in value]
|
||||
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):
|
||||
# pylint: disable=too-many-return-statements
|
||||
if value is None:
|
||||
return None
|
||||
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):
|
||||
# pylint: disable=too-many-return-statements
|
||||
|
@ -184,4 +202,4 @@ class MeasurementParameter(ModelTypeValidator):
|
|||
if isinstance(value, Mapping):
|
||||
return value
|
||||
|
||||
return self.fail('invalid')
|
||||
return self.fail('invalid_mapping')
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
"""Validators for Qiskit validated classes."""
|
||||
|
||||
from collections.abc import Mapping
|
||||
|
||||
from marshmallow import ValidationError
|
||||
from marshmallow.validate import Validator
|
||||
|
||||
|
@ -68,7 +70,13 @@ class PatternProperties(Validator):
|
|||
|
||||
def __call__(self, value):
|
||||
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.
|
||||
field = None
|
||||
for validator, candidate in self.pattern_properties.items():
|
||||
|
|
|
@ -178,8 +178,7 @@ class TestPulseQobj(QiskitTestCase):
|
|||
],
|
||||
'qubit_lo_freq': [4.9],
|
||||
'meas_lo_freq': [6.9],
|
||||
'rep_time': 1000
|
||||
},
|
||||
'rep_time': 1000},
|
||||
'experiments': [
|
||||
{'instructions': [
|
||||
{'name': 'pulse0', 't0': 0, 'ch': 'd0'},
|
||||
|
@ -225,7 +224,7 @@ class TestPulseQobj(QiskitTestCase):
|
|||
'pulse_library': [{'name': 'pulse0', 'samples': [[0.1, 0.0]]}],
|
||||
'qubit_lo_freq': [4.9],
|
||||
'meas_lo_freq': [6.9],
|
||||
'rep_time': 1000}
|
||||
'rep_time': 1000},
|
||||
),
|
||||
QobjPulseLibrary: (
|
||||
QobjPulseLibrary(name='pulse0', samples=[0.1 + 0.0j]),
|
||||
|
|
Loading…
Reference in New Issue