Pulse command definition (#2263)

* Add pulse backend configuration.

* Add QASM and Pulse backend configuration objects.

* Added QASMBackendConfiguration and PulseBackendConfiguration with factory method from_dict.

* add tests for qasm/pulse backend configuration.

* linting.

* Parameter update

* Cleanup provider models and rename.

* linting

* Linting

* Make QASM -> Qasm

* remove invalid name

* Update open_pulse field to required.

* Remove from_dict hackery.

* Update tests.

* linting.

* linting.

* linting and required variable.

* readd comment.

* Add setting of u_channel_lo frequency.

* Redo qubit signature, all control channels present.

* linting

* Remove lo_freq from pulse channels.

* linting.

* Rework the way lo configuration works. Removed from channels and instead responsibility is placed on assembler.

* Small change to trigger rebuild.

* Fix rebasing.

* Add buffering of commands.

* Add buffer tests.

* linting.

* Small bug in device specification fall back.

* Add buffer to acquire channel.

* Added command definition data structure.

* Added casting of integer input qubits to tuple for cmd_def.

* Added cmd_def object tests. Not running as proper pulse schedule api is not yet running.

* Update imports and making pulse library.

* Added cmd_def and pulse_library to defaults in pulse mock backend

* Remove duplicate of PulseLibraryItem.

* remove redefinition of pulse qobj schema.

* linting

* update schema for parameterizable pulses.

* Add mutable mapping

* Remove mutablemapping and dunder methods.

* cmd_def pulse_library defaults methods.

* Add cmd_def accesor method.

* Update schema for vals and phase of type string.

* Added parameterized schedule and typing to cmd_def.

* Update typing of CmdDef. Add cmd_qubits method.

* Make ConversionMethodBinder generic.

* Rename PulseQobjConverter to InstructionToQobjConverter

* Add conversion logic for qobj to schedules.

* Convert without built pulse_library.

* QobjToInstruction tests and passing.

* Small bug fix.

* Fix cmd_def tests.

* linting.

* linting.

* add linting.

* Add safe expression parsing.

* Add Parameterized Schedule logic.

* Add parameterized schedules with tests.

* Fix cmd_def test.

* Working cmd def.

* Added parameterized cmd_def test

* Update tests.

* Tests passing.

* change cmd_types to cmds)

* Update cmd_def errors.

* Update error strings.

* Fix cmd_qubits.

* Linting.

* update regex and docs.

* Add testing of sanitization

* Update sanitization testing.

* linting.

* Update imports.

* Undo standard imports.

* Fix bug in pulse

* Escape regex
This commit is contained in:
Thomas Alexander 2019-05-01 17:16:36 -04:00 committed by Kevin Krsulich
parent 9b93d17877
commit 52b9d37f17
17 changed files with 887 additions and 122 deletions

View File

@ -19,8 +19,8 @@ from qiskit.exceptions import QiskitError
from qiskit.pulse.commands import PulseInstruction
from qiskit.qobj import (PulseQobj, QobjExperimentHeader,
PulseQobjInstruction, PulseQobjExperimentConfig,
PulseQobjExperiment, PulseQobjConfig, QobjPulseLibrary)
from qiskit.qobj.converters import PulseQobjConverter, LoConfigConverter
PulseQobjExperiment, PulseQobjConfig, PulseLibraryItem)
from qiskit.qobj.converters import InstructionToQobjConverter, LoConfigConverter
logger = logging.getLogger(__name__)
@ -40,7 +40,7 @@ def assemble_schedules(schedules, qobj_id=None, qobj_header=None, run_config=Non
if hasattr(run_config, 'instruction_converter'):
instruction_converter = run_config.instruction_converter
else:
instruction_converter = PulseQobjConverter
instruction_converter = InstructionToQobjConverter
qobj_config = run_config.to_dict()
qubit_lo_range = qobj_config.pop('qubit_lo_range')
@ -75,7 +75,7 @@ def assemble_schedules(schedules, qobj_id=None, qobj_header=None, run_config=Non
})
# setup pulse_library
qobj_config['pulse_library'] = [QobjPulseLibrary(name=pulse.name, samples=pulse.samples)
qobj_config['pulse_library'] = [PulseLibraryItem(name=pulse.name, samples=pulse.samples)
for pulse in user_pulselib]
# create qob experiment field

View File

@ -15,8 +15,8 @@
"""Qiskit schema-conformant objects used by the backends and providers."""
from .backendconfiguration import (BackendConfiguration, PulseBackendConfiguration,
QasmBackendConfiguration, UchannelLO)
QasmBackendConfiguration, UchannelLO, GateConfig)
from .backendproperties import BackendProperties
from .backendstatus import BackendStatus
from .jobstatus import JobStatus
from .pulsedefaults import PulseDefaults
from .pulsedefaults import PulseDefaults, Command

View File

@ -11,17 +11,9 @@ from marshmallow.validate import Length, Range
from qiskit.validation import BaseModel, BaseSchema, bind_schema
from qiskit.validation.base import ObjSchema
from qiskit.validation.fields import (Complex, Integer, List, Nested, Number,
String)
class PulseLibraryItemSchema(BaseSchema):
"""Schema for PulseLibraryItem."""
# Required properties.
name = String(required=True)
samples = List(Complex(), required=True,
validate=Length(min=1))
from qiskit.validation.fields import (Integer, List, Nested, Number, String)
from qiskit.qobj import PulseLibraryItemSchema, PulseQobjInstructionSchema
from qiskit.pulse import CmdDef
class MeasurementKernelSchema(BaseSchema):
@ -49,7 +41,7 @@ class CommandSchema(BaseSchema):
# Optional properties.
qubits = List(Integer(validate=Range(min=0)),
validate=Length(min=1))
sequence = Nested(ObjSchema, many=True)
sequence = Nested(PulseQobjInstructionSchema, many=True)
class PulseDefaultsSchema(BaseSchema):
@ -67,24 +59,6 @@ class PulseDefaultsSchema(BaseSchema):
discriminator = Nested(DiscriminatorSchema)
@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): Pulse name.
samples (list[complex]): Pulse samples.
"""
def __init__(self, name, samples, **kwargs):
self.name = name
self.samples = samples
super().__init__(**kwargs)
@bind_schema(MeasurementKernelSchema)
class MeasurementKernel(BaseModel):
"""Model for MeasurementKernel.
@ -146,3 +120,11 @@ class PulseDefaults(BaseModel):
self.cmd_def = cmd_def
super().__init__(**kwargs)
def build_cmd_def(self):
"""Construct the `CmdDef` object for the backend.
Returns:
CmdDef: `CmdDef` instance generated from defaults
"""
return CmdDef.from_defaults(self.cmd_def, self.pulse_library)

View File

@ -19,3 +19,5 @@ from .commands import (Acquire, FrameChange, PersistentValue, SamplePulse, Snaps
Kernel, Discriminator, functional_pulse)
from .configuration import LoConfig, LoRange
from .schedule import Schedule
from .cmd_def import CmdDef
from .exceptions import PulseError

192
qiskit/pulse/cmd_def.py Normal file
View File

@ -0,0 +1,192 @@
# -*- coding: utf-8 -*-
# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.
"""
Command definition module. Relates circuit gates to pulse commands.
"""
from typing import List, Tuple, Iterable, Union, Dict
from qiskit.qobj import PulseQobjInstruction
from qiskit.qobj.converters import QobjToInstructionConverter
from .commands import SamplePulse
from .exceptions import PulseError
from .schedule import Schedule, ParameterizedSchedule
# pylint: disable=missing-return-doc
def _to_qubit_tuple(qubit_tuple: Union[int, Iterable[int]]) -> Tuple[int]:
"""Convert argument to tuple.
Args:
qubit_tuple: Qubits to enforce as tuple.
Raises:
PulseError: If qubits are not integers
"""
try:
qubit_tuple = tuple(qubit_tuple)
except TypeError:
qubit_tuple = (qubit_tuple,)
if not all(isinstance(i, int) for i in qubit_tuple):
raise PulseError("All qubits must be integers.")
return qubit_tuple
class CmdDef:
"""Command definition class. Relates `Gate`s to `Schedule`s."""
def __init__(self, schedules: Dict = None):
"""Create command definition from backend.
Args:
schedules: Keys are tuples of (cmd_name, *qubits) and values are
`Schedule` or `ParameterizedSchedule`
"""
self._cmd_dict = {}
if schedules:
for key, schedule in schedules.items():
self.add(key[0], key[1:], schedule)
@classmethod
def from_defaults(cls, flat_cmd_def: List[PulseQobjInstruction],
pulse_library: Dict[str, SamplePulse]) -> 'CmdDef':
"""Create command definition from backend defaults output.
Args:
flat_cmd_def: Command definition list returned by backend
pulse_library: Dictionary of `SamplePulse`s
"""
converter = QobjToInstructionConverter(pulse_library, buffer=0)
cmd_def = cls()
for cmd in flat_cmd_def:
qubits = cmd.qubits
name = cmd.name
instructions = []
for instr in cmd.sequence:
instructions.append(converter(instr))
cmd_def.add(name, qubits, ParameterizedSchedule(*instructions, name=name))
return cmd_def
def add(self, cmd_name: str, qubits: Union[int, Iterable[int]],
schedule: Union[ParameterizedSchedule, Schedule]):
"""Add a command to the `CommandDefinition`
Args:
cmd_name: Name of the command
qubits: Qubits command applies to
schedule: Schedule to be added
"""
qubits = _to_qubit_tuple(qubits)
cmd_dict = self._cmd_dict.setdefault(cmd_name, {})
if isinstance(schedule, Schedule):
schedule = ParameterizedSchedule(schedule, name=schedule.name)
cmd_dict[qubits] = schedule
def has(self, cmd_name: str, qubits: Union[int, Iterable[int]]) -> bool:
"""Has command of name with qubits.
Args:
cmd_name: Name of the command
qubits: Ordered list of qubits command applies to
"""
qubits = _to_qubit_tuple(qubits)
if cmd_name in self._cmd_dict:
if qubits in self._cmd_dict[cmd_name]:
return True
return False
def get(self, cmd_name: str, qubits: Union[int, Iterable[int]],
**params: Dict[str, Union[float, complex]]) -> Schedule:
"""Get command from command definition.
Args:
cmd_name: Name of the command
qubits: Ordered list of qubits command applies to
**params: Command parameters to be used to generate schedule
Raises:
PulseError: If command for qubits is not available
"""
qubits = _to_qubit_tuple(qubits)
if self.has(cmd_name, qubits):
schedule = self._cmd_dict[cmd_name][qubits]
if isinstance(schedule, ParameterizedSchedule):
return schedule.bind_parameters(**params)
return schedule.flatten()
else:
raise PulseError('Command {0} for qubits {1} is not present '
'in CmdDef'.format(cmd_name, qubits))
def get_parameters(self, cmd_name: str, qubits: Union[int, Iterable[int]]) -> Tuple[str]:
"""Get command parameters from command definition.
Args:
cmd_name: Name of the command
qubits: Ordered list of qubits command applies to
Raises:
PulseError: If command for qubits is not available
"""
qubits = _to_qubit_tuple(qubits)
if self.has(cmd_name, qubits):
schedule = self._cmd_dict[cmd_name][qubits]
return schedule.parameters
else:
raise PulseError('Command {0} for qubits {1} is not present '
'in CmdDef'.format(cmd_name, qubits))
def pop(self, cmd_name: str, qubits: Union[int, Iterable[int]],
**params: Dict[str, Union[float, complex]]) -> Schedule:
"""Pop command from command definition.
Args:
cmd_name: Name of the command
qubits: Ordered list of qubits command applies to
**params: Command parameters to be used to generate schedule
Raises:
PulseError: If command for qubits is not available
"""
qubits = _to_qubit_tuple(qubits)
if self.has(cmd_name, qubits):
cmd_dict = self._cmd_dict[cmd_name]
schedule = cmd_dict.pop(qubits)
if isinstance(schedule, ParameterizedSchedule):
return schedule.bind_parameters(**params)
return schedule
else:
raise PulseError('Command {0} for qubits {1} is not present '
'in CmdDef'.format(cmd_name, qubits))
def cmds(self) -> List[str]:
"""Return all command names available in CmdDef."""
return list(self._cmd_dict.keys())
def cmd_qubits(self, cmd_name: str) -> List[Tuple[int]]:
"""Get all qubit orderings this command exists for."""
if cmd_name in self._cmd_dict:
return list(sorted(self._cmd_dict[cmd_name].keys()))
raise PulseError('Command %s does not exist in CmdDef.' % cmd_name)
def __repr__(self):
return repr(self._cmd_dict)

View File

@ -23,7 +23,7 @@ class SamplePulse(Command):
"""Create new sample pulse command.
Args:
samples (ndarray): Complex array of pulse envelope.
samples (Union[np.ndarray, List[Complex]]): Complex array of pulse envelope.
name (str): Unique name to identify the pulse.
Raises:
PulseError: when pulse envelope amplitude exceeds 1.
@ -33,7 +33,7 @@ class SamplePulse(Command):
if np.any(np.abs(samples) > 1):
raise PulseError('Absolute value of pulse envelope amplitude exceeds 1.')
self._samples = samples
self._samples = np.asarray(samples, dtype=np.complex_)
@property
def samples(self):

View File

@ -121,7 +121,7 @@ def _fix_gaussian_width(gaussian_samples, amp: float, center: float, sigma: floa
gaussian_samples -= zero_offset
amp_scale_factor = 1.
if rescale_amp:
amp_scale_factor = amp/(amp-zero_offset)
amp_scale_factor = amp/(amp-zero_offset) if amp-zero_offset != 0 else 1.
gaussian_samples *= amp_scale_factor
if ret_scale_factor:

View File

@ -11,15 +11,12 @@
# 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=missing-return-doc,cyclic-import
"""
Schedule.
"""
import itertools
import logging
from typing import List, Tuple, Iterable, Union
from typing import List, Tuple, Iterable, Union, Dict
from qiskit.pulse import ops
from .channels import Channel
@ -29,6 +26,8 @@ from .exceptions import PulseError
logger = logging.getLogger(__name__)
# pylint: disable=missing-return-doc,cyclic-import
class Schedule(ScheduleComponent):
"""Schedule of `ScheduleComponent`s. The composite node of a schedule tree."""
@ -210,3 +209,59 @@ class Schedule(ScheduleComponent):
if len(instructions) > 50:
return res + ', ...)'
return res + ')'
class ParameterizedSchedule:
"""Temporary parameterized schedule class.
This should not be returned to users as it is currently only a helper class.
This class is takes an input command definition that accepts
a set of parameters. Calling `bind` on the class will return a `Schedule`.
# TODO: In the near future this will be replaced with proper incorporation of parameters
into the `Schedule` class.
"""
def __init__(self, *schedules, parameters=None, name=None):
full_schedules = []
parameterized = []
parameters = parameters or []
self.name = name or ''
# partition schedules into callable and schedules
for schedule in schedules:
if isinstance(schedule, ParameterizedSchedule):
parameterized.append(schedule)
parameters += schedule.parameters
elif callable(schedule):
parameterized.append(schedule)
elif isinstance(schedule, Schedule):
full_schedules.append(schedule)
else:
raise PulseError('Input type: {0} not supported'.format(type(schedule)))
self._parameterized = tuple(parameterized)
self._schedules = tuple(full_schedules)
self._parameters = tuple(sorted(parameters))
@property
def parameters(self) -> Tuple[str]:
"""Schedule parameters."""
return self._parameters
def bind_parameters(self, *args: List[float], **kwargs: Dict[str, float]) -> Schedule:
"""Generate the Schedule from params to evaluate command expressions"""
bound_schedule = Schedule(name=self.name)
schedules = list(self._schedules)
for param_sched in self._parameterized:
# recursively call until based callable is reached
schedules.append(param_sched(*args, **kwargs))
# construct evaluated schedules
for sched in schedules:
bound_schedule |= sched
return bound_schedule
def __call__(self, *args: List[float], **kwargs: Dict[str, float]) -> Schedule:
return self.bind_parameters(*args, **kwargs)

View File

@ -19,7 +19,8 @@ from .models.base import (QobjInstruction, QobjExperimentHeader, QobjExperimentC
from .models.pulse import (PulseQobjInstruction, PulseQobjExperimentConfig,
PulseQobjExperiment, PulseQobjConfig,
QobjMeasurementOption, QobjPulseLibrary)
QobjMeasurementOption, PulseLibraryItem,
PulseLibraryItemSchema, PulseQobjInstructionSchema)
from .models.qasm import (QasmQobjInstruction, QasmQobjExperimentConfig,
QasmQobjExperiment, QasmQobjConfig)

View File

@ -9,5 +9,5 @@
Helper modules to convert qiskit frontend object to proper qobj model.
"""
from .pulse_instruction import PulseQobjConverter
from .pulse_instruction import InstructionToQobjConverter, QobjToInstructionConverter
from .lo_config import LoConfigConverter

View File

@ -6,77 +6,67 @@
# the LICENSE.txt file in the root directory of this source tree.
"""Helper class used to convert a pulse instruction into PulseQobjInstruction."""
import re
import math
import functools
from sympy.parsing.sympy_parser import (parse_expr, standard_transformations,
implicit_multiplication_application,
function_exponentiation)
from sympy import Symbol
from qiskit.pulse import commands
from qiskit.pulse import commands, channels, Schedule
from qiskit.pulse.schedule import ParameterizedSchedule
from qiskit.pulse.exceptions import PulseError
from qiskit.qobj import QobjMeasurementOption
from qiskit import QiskitError
class ConversionMethodBinder:
"""Instruction conversion method registrar."""
"""Conversion method registrar."""
def __init__(self):
"""Acts as method registration decorator and tracker for instruction conversion methods."""
"""Acts as method registration decorator and tracker for conversion methods."""
self._bound_instructions = {}
def __call__(self, type_instruction):
def __call__(self, bound):
""" Converter decorator method.
Pulse instruction converter is defined for each instruction type,
and this decorator binds converter function to valid instruction type.
Converter is defined for object to be converted matched on hash
Args:
type_instruction (Instruction): valid pulse instruction class to the converter.
bound (Hashable): Hashable object to bind to the converter.
"""
# pylint: disable=missing-return-doc, missing-return-type-doc
def _apply_converter(converter):
"""Return decorated converter function."""
@functools.wraps(converter)
def _call_valid_converter(self, shift, instruction):
"""Return a dictionary for to be used to construct a qobj
if the given instruction matches the
bound instruction type supplied to the function,
otherwise return None."""
if isinstance(instruction, type_instruction):
return converter(self, shift, instruction)
else:
raise PulseError('Supplied instruction {0} '
'is not of type {1}.'.format(instruction, type_instruction))
# Track conversion methods for class.
self._bound_instructions[type_instruction] = _call_valid_converter
return _call_valid_converter
self._bound_instructions[bound] = converter
return converter
return _apply_converter
def get_bound_method(self, instruction):
"""Get conversion method for instruction."""
def get_bound_method(self, bound):
"""Get conversion method for bound object."""
try:
return self._bound_instructions[type(instruction)]
return self._bound_instructions[bound]
except KeyError:
raise PulseError('Qobj conversion method for %s is not found.' % instruction)
raise PulseError('Bound method for %s is not found.' % bound)
class PulseQobjConverter:
"""
This class exists for separating entity of pulse instructions and qobj instruction,
and provides some alleviation of the complexity of the assembler.
class InstructionToQobjConverter:
"""Converts pulse Instructions to Qobj models.
Converter is constructed with qobj model and some experimental configuration,
Converter is constructed with qobj model and experimental configuration,
and returns proper qobj instruction to each backend.
Pulse instruction and its qobj are strongly depends on the design of backend,
and third party providers can be easily add their custom pulse instruction by
providing custom converter inherit from this.
Third party providers can be add their own custom pulse instructions by
providing custom converter methods.
To create custom converter for custom instruction
To create a custom converter for custom instruction
```
class CustomConverter(PulseQobjConverter):
class CustomConverter(InstructionToQobjConverter):
@bind_instruction(CustomInstruction)
def convert_custom_command(self, shift, instruction):
@ -108,7 +98,7 @@ class PulseQobjConverter:
def __call__(self, shift, instruction):
method = self.bind_instruction.get_bound_method(instruction)
method = self.bind_instruction.get_bound_method(type(instruction))
return method(self, shift, instruction)
@bind_instruction(commands.AcquireInstruction)
@ -226,3 +216,287 @@ class PulseQobjConverter:
'type': instruction.type
}
return self._qobj_model(**command_dict)
# pylint: disable=invalid-name
# get math operations valid in python. Presumably these are valid in sympy
_math_ops = [math_op for math_op in math.__dict__ if not math_op.startswith('__')]
# only allow valid math ops
_math_ops_regex = r"(" + ")|(".join(_math_ops) + ")"
# match consecutive alphanumeric, and single consecutive math ops +-/.()
# and multiple * for exponentiation
_allowedchars = re.compile(r'([+\/\-\(\)\.])?([\sa-zA-Z\d]+[+\/\-\(\)\.]?\*{0,2})*')
# match any sequence of chars and numbers
_expr_regex = r'([a-zA-Z]+\d*)'
# and valid params
_param_regex = r'(P\d+)'
# only valid sequences are P# for parameters and valid math operations above
_valid_sub_expr = re.compile(_param_regex+'|'+_math_ops_regex)
# pylint: enable=invalid-name
def _is_math_expr_safe(expr):
r"""Verify mathematical expression is sanitized.
Only allow strings of form 'P\d+' and operations from `math`.
Allowed chars are [a-zA-Z]. Allowed math operators are '+*/().'
where only '*' are allowed to be consecutive.
Args:
expr (str): Expression to sanitize
Returns:
bool: Whether the string is safe to parse math from
Raise:
QiskitError: If math expression is not sanitized
"""
only_allowed_chars = _allowedchars.match(expr)
if not only_allowed_chars:
return False
elif not only_allowed_chars.group(0) == expr:
return False
sub_expressions = re.findall(_expr_regex, expr)
if not all([_valid_sub_expr.match(sub_exp) for sub_exp in sub_expressions]):
return False
return True
def _parse_string_expr(expr): # pylint: disable=missing-return-type-doc
"""Parse a mathematical string expression and extract free parameters.
Args:
expr (str): String expression to parse
Returns:
(Callable, Tuple[str]): Returns a callable function and tuple of string symbols
Raises:
QiskitError: If expression is not safe
"""
# remove these strings from expression and hope sympy knows these math expressions
# these are effectively reserved keywords
subs = [('numpy.', ''), ('np.', ''), ('math.', '')]
for match, sub in subs:
expr = expr.replace(match, sub)
if not _is_math_expr_safe(expr):
raise QiskitError('Expression: "%s" is not safe to evaluate.' % expr)
params = sorted(re.findall(_param_regex, expr))
local_dict = {param: Symbol(param) for param in params}
symbols = list(local_dict.keys())
transformations = (standard_transformations + (implicit_multiplication_application,) +
(function_exponentiation,))
parsed_expr = parse_expr(expr, local_dict=local_dict, transformations=transformations)
def parsed_fun(*args, **kwargs):
subs = {}
matched_params = []
if args:
subs.update({symbols[i]: arg for i, arg in enumerate(args)})
matched_params += list(params[i] for i in range(len(args)))
elif kwargs:
subs.update({local_dict[key]: value for key, value in kwargs.items()
if key in local_dict})
matched_params += list(key for key in kwargs if key in params)
if not set(matched_params).issuperset(set(params)):
raise PulseError('Supplied params ({args}, {kwargs}) do not match '
'{params}'.format(args=args, kwargs=kwargs, params=params))
return complex(parsed_expr.evalf(subs=subs))
return parsed_fun, params
class QobjToInstructionConverter:
"""Converts Qobj models to pulse Instructions
"""
# pylint: disable=invalid-name,missing-return-type-doc
# class level tracking of conversion methods
bind_name = ConversionMethodBinder()
chan_regex = re.compile(r'([a-zA-Z]+)(\d+)')
def __init__(self, pulse_library, buffer=0, **run_config):
"""Create new converter.
Args:
pulse_library (List[PulseLibraryItem]): Pulse library to be used in conversion
buffer (int): Channel buffer
run_config (dict): experimental configuration.
"""
self.buffer = buffer
self._run_config = run_config
# bind pulses to conversion methods
for pulse in pulse_library:
self.bind_pulse(pulse)
def __call__(self, instruction):
method = self.bind_name.get_bound_method(instruction.name)
return method(self, instruction)
def get_channel(self, channel):
"""Parse and retrieve channel from ch string.
Args:
channel (str): Channel to match
Returns:
(Channel, int): Matched channel
Raises:
PulseError: Is raised if valid channel is not matched
"""
match = self.chan_regex.match(channel)
if match:
prefix, index = match.group(1), int(match.group(2))
if prefix == channels.DriveChannel.prefix:
return channels.DriveChannel(index, buffer=self.buffer)
elif prefix == channels.MeasureChannel.prefix:
return channels.MeasureChannel(index, buffer=self.buffer)
elif prefix == channels.ControlChannel.prefix:
return channels.ControlChannel(index, buffer=self.buffer)
raise PulseError('Channel %s is not valid' % channel)
@bind_name('acquire')
def convert_acquire(self, instruction):
"""Return converted `AcquireInstruction`.
Args:
instruction (PulseQobjInstruction): acquire qobj
Returns:
Schedule: Converted and scheduled Instruction
"""
t0 = instruction.t0
duration = instruction.duration
qubits = instruction.qubits
discriminators = (instruction.discriminators
if hasattr(instruction, 'discriminators') else None)
kernels = (instruction.kernels
if hasattr(instruction, 'kernels') else None)
mem_slots = instruction.memory_slot
reg_slots = (instruction.register_slot
if hasattr(instruction, 'register_slot') else None)
if not isinstance(discriminators, list):
discriminators = [discriminators for _ in range(len(qubits))]
if not isinstance(kernels, list):
kernels = [kernels for _ in range(len(qubits))]
schedule = Schedule()
for i, qubit in enumerate(qubits):
kernel = kernels[i]
if kernel:
kernel = commands.Kernel(name=kernel.name,
params=kernel.params)
discriminator = discriminators[i]
if discriminator:
discriminator = commands.Discriminator(name=discriminator.name,
params=discriminator.params)
channel = channels.AcquireChannel(qubit, buffer=self.buffer)
if reg_slots:
register_slot = channels.RegisterSlot(reg_slots[i])
else:
register_slot = None
memory_slot = channels.MemorySlot(mem_slots[i])
cmd = commands.Acquire(duration, discriminator=discriminator, kernel=kernel)
schedule |= commands.AcquireInstruction(cmd, channel, memory_slot, register_slot) << t0
return schedule
@bind_name('fc')
def convert_frame_change(self, instruction):
"""Return converted `FrameChangeInstruction`.
Args:
instruction (PulseQobjInstruction): frame change qobj
Returns:
Schedule: Converted and scheduled Instruction
"""
t0 = instruction.t0
channel = self.get_channel(instruction.ch)
phase = instruction.phase
# This is parameterized
if isinstance(phase, str):
phase_expr, params = _parse_string_expr(phase)
def gen_fc_sched(*args, **kwargs):
phase = abs(phase_expr(*args, **kwargs))
return commands.FrameChange(phase)(channel) << t0
return ParameterizedSchedule(gen_fc_sched, parameters=params)
return commands.FrameChange(phase)(channel) << t0
@bind_name('pv')
def convert_persistent_value(self, instruction):
"""Return converted `PersistentValueInstruction`.
Args:
instruction (PulseQobjInstruction): persistent value qobj
Returns:
Schedule: Converted and scheduled Instruction
"""
t0 = instruction.t0
channel = self.get_channel(instruction.ch)
val = instruction.val
# This is parameterized
if isinstance(val, str):
val_expr, params = _parse_string_expr(val)
def gen_fc_sched(*args, **kwargs):
val = complex(val_expr(*args, **kwargs))
return commands.PersistentValue(val)(channel) << t0
return ParameterizedSchedule(gen_fc_sched, parameters=params)
return commands.PersistentValue(val)(channel) << t0
def bind_pulse(self, pulse):
"""Bind the supplied pulse to a converter method by pulse name.
Args:
pulse (PulseLibraryItem): Pulse to bind
"""
# pylint: disable=unused-variable
pulse = commands.SamplePulse(pulse.samples, pulse.name)
@self.bind_name(pulse.name)
def convert_named_drive(self, instruction):
"""Return converted `PulseInstruction`.
Args:
instruction (PulseQobjInstruction): pulse qobj
Returns:
Schedule: Converted and scheduled pulse
"""
t0 = instruction.t0
channel = self.get_channel(instruction.ch)
return pulse(channel) << t0
@bind_name('snapshot')
def convert_snapshot(self, instruction):
"""Return converted `Snapshot`.
Args:
instruction (PulseQobjInstruction): snapshot qobj
Returns:
Schedule: Converted and scheduled Snapshot
"""
t0 = instruction.t0
return commands.Snapshot(instruction.label, instruction.type) << t0

View File

@ -11,7 +11,8 @@ from marshmallow.validate import Range, Regexp, Length, OneOf
from qiskit.qobj.utils import MeasReturnType
from qiskit.validation import BaseSchema, bind_schema, BaseModel
from qiskit.validation.fields import Integer, String, Number, Complex, List, Nested, DictParameters
from qiskit.validation.fields import (Integer, String, Number, Complex, List,
Nested, DictParameters, ByType)
from .base import (QobjInstructionSchema, QobjExperimentConfigSchema, QobjExperimentSchema,
QobjConfigSchema, QobjInstruction, QobjExperimentConfig,
QobjExperiment, QobjConfig)
@ -26,8 +27,8 @@ class QobjMeasurementOptionSchema(BaseSchema):
required=True)
class QobjPulseLibrarySchema(BaseSchema):
"""Schema for QobjPulseLibrary."""
class PulseLibraryItemSchema(BaseSchema):
"""Schema for PulseLibraryItem."""
# Required properties.
name = String(required=True)
@ -44,8 +45,8 @@ class PulseQobjInstructionSchema(QobjInstructionSchema):
# Optional properties.
ch = String(validate=Regexp('[dum]([0-9])+'))
conditional = Integer(validate=Range(min=0))
phase = Number()
val = Complex()
val = ByType([Complex(), String()])
phase = ByType([String(), Number()])
duration = Integer(validate=Range(min=1))
qubits = List(Integer(validate=Range(min=0)), validate=Length(min=1))
memory_slot = List(Integer(validate=Range(min=0)), validate=Length(min=1))
@ -83,7 +84,7 @@ class PulseQobjConfigSchema(QobjConfigSchema):
meas_level = Integer(required=True, validate=Range(min=0, max=2))
meas_return = String(required=True, validate=OneOf(choices=(MeasReturnType.AVERAGE,
MeasReturnType.SINGLE)))
pulse_library = Nested(QobjPulseLibrarySchema, required=True, many=True)
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)
@ -110,12 +111,12 @@ class QobjMeasurementOption(BaseModel):
super().__init__(**kwargs)
@bind_schema(QobjPulseLibrarySchema)
class QobjPulseLibrary(BaseModel):
"""Model for QobjPulseLibrary.
@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 ``QobjPulseLibrarySchema``.
full description of the model, please check ``PulseLibraryItemSchema``.
Attributes:
name (str): name of pulse
@ -186,7 +187,7 @@ class PulseQobjConfig(QobjConfig):
meas_level (int): a value represents the level of measurement.
meas_lo_freq (list[float]): local oscillator frequency of measurement pulse.
meas_return (str): a level of measurement information.
pulse_library (list[qiskit.qobj.QobjPulseLibrary]): a pulse library.
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,

View File

@ -115,13 +115,15 @@
]
},
"val": {
"items": {
"OneOf": [
{"items": {
"type": "number"
},
"maxItems": 2,
"minItems": 2,
"type": "array"
}
"type": "array"},
{"type": "string"}
]}
},
"required": [
"val",
@ -138,7 +140,9 @@
]
},
"phase": {
"type": "number"
"OneOf":[
{"type": "number"},
{"type": "string"}]
}
},
"required": [

View File

@ -31,12 +31,13 @@ import time
from qiskit.result import Result
from qiskit.providers import BaseBackend, BaseJob
from qiskit.providers.models import (BackendProperties, PulseDefaults, UchannelLO,
QasmBackendConfiguration, PulseBackendConfiguration)
from qiskit.providers.models.backendconfiguration import GateConfig
from qiskit.providers.models import (BackendProperties, GateConfig,
QasmBackendConfiguration, PulseBackendConfiguration,
PulseDefaults, Command, UchannelLO)
from qiskit.qobj import (QasmQobj, QobjExperimentHeader, QobjHeader,
QasmQobjInstruction, QasmQobjExperimentConfig,
QasmQobjExperiment, QasmQobjConfig)
QasmQobjExperiment, QasmQobjConfig, PulseLibraryItem,
PulseQobjInstruction)
from qiskit.providers.jobstatus import JobStatus
from qiskit.providers.baseprovider import BaseProvider
from qiskit.providers.exceptions import QiskitBackendNotFoundError
@ -60,8 +61,9 @@ class FakeProvider(BaseProvider):
# pylint: enable=no-member
if not filtered_backends:
raise QiskitBackendNotFoundError()
else:
backend = filtered_backends[0]
backend = filtered_backends[0]
return backend
def backends(self, name=None, **kwargs):
@ -73,7 +75,7 @@ class FakeProvider(BaseProvider):
FakeMelbourne(),
FakeRueschlikon(),
FakeTokyo(),
FakeOpenPulse2Q()],
FakeOpenPulse2Q()]
super().__init__()
@ -192,8 +194,23 @@ class FakeOpenPulse2Q(FakeBackend):
qubit_freq_est=[4.9, 5.0],
meas_freq_est=[6.5, 6.6],
buffer=10,
pulse_library=[],
cmd_def=[]
pulse_library=[PulseLibraryItem(name='test_pulse_1', samples=[0.j, 0.1j]),
PulseLibraryItem(name='test_pulse_2', samples=[0.j, 0.1j, 1j])],
cmd_def=[Command(name='u1', qubits=[0],
sequence=[PulseQobjInstruction(name='fc', ch='d0',
t0=0, phase='-P1*np.pi')]),
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='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],
sequence=[PulseQobjInstruction(name='test_pulse_1', ch='m0', t0=0),
PulseQobjInstruction(name='acquire', duration=10, t0=0,
qubits=[0], memory_slot=[0])])]
)
super().__init__(configuration)

View File

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.
"""Test for the CmdDef object."""
import numpy as np
from qiskit.test import QiskitTestCase
from qiskit.test.mock import FakeProvider
from qiskit.qobj.converters import QobjToInstructionConverter
from qiskit.qobj import PulseQobjInstruction
from qiskit.pulse import (CmdDef, SamplePulse, Schedule, DeviceSpecification,
PulseError, PersistentValue)
class TestCmdDef(QiskitTestCase):
"""Test CmdDef methods."""
def setUp(self):
self.provider = FakeProvider()
self.backend = self.provider.get_backend('fake_openpulse_2q')
self.device = DeviceSpecification.create_from(self.backend)
def test_get_backend(self):
"""Test that backend is fetchable with cmd def present."""
def test_init(self):
"""Test `init`, `has`."""
sched = Schedule()
sched.append(SamplePulse(np.ones(5))(self.device.q[0].drive))
cmd_def = CmdDef({('tmp', 0): sched})
self.assertTrue(cmd_def.has('tmp', 0))
def test_add(self):
"""Test `add`, `has`, `get`, `cmdss`."""
sched = Schedule()
sched.append(SamplePulse(np.ones(5))(self.device.q[0].drive))
cmd_def = CmdDef()
cmd_def.add('tmp', 1, sched)
cmd_def.add('tmp', 0, sched)
self.assertEqual(sched.instructions, cmd_def.get('tmp', (0,)).instructions)
self.assertIn('tmp', cmd_def.cmds())
self.assertEqual(cmd_def.cmd_qubits('tmp'), [(0,), (1,)])
def test_pop(self):
"""Test pop with default."""
sched = Schedule()
sched.append(SamplePulse(np.ones(5))(self.device.q[0].drive))
cmd_def = CmdDef()
cmd_def.add('tmp', 0, sched)
cmd_def.pop('tmp', 0)
self.assertFalse(cmd_def.has('tmp', 0))
with self.assertRaises(PulseError):
cmd_def.pop('not_there', (0,))
def test_repr(self):
"""Test repr."""
sched = Schedule()
sched.append(SamplePulse(np.ones(5))(self.device.q[0].drive))
cmd_def = CmdDef({('tmp', 0): sched})
repr(cmd_def)
def test_parameterized_schedule(self):
"""Test building parameterized schedule."""
cmd_def = CmdDef()
converter = QobjToInstructionConverter([], buffer=0)
qobj = PulseQobjInstruction(name='pv', ch='u1', t0=10, val='P2*cos(np.pi*P1)')
converted_instruction = converter(qobj)
cmd_def.add('pv_test', 0, converted_instruction)
self.assertEqual(cmd_def.get_parameters('pv_test', 0), ('P1', 'P2'))
sched = cmd_def.get('pv_test', 0, P1='0', P2=-1)
self.assertEqual(sched.instructions[0][-1].command.value, -1)
def test_build_cmd_def(self):
"""Test building of parameterized cmd_def from defaults."""
defaults = self.backend.defaults()
cmd_def = defaults.build_cmd_def()
cx_pv = cmd_def.get('cx', (0, 1), P2=0)
pv_found = False
for _, instr in cx_pv.instructions:
cmd = instr.command
if isinstance(cmd, PersistentValue):
self.assertEqual(cmd.value, 1)
pv_found = True
self.assertTrue(pv_found)
self.assertEqual(cmd_def.get_parameters('u1', 0), ('P1',))
u1_minus_pi = cmd_def.get('u1', 0, P1=1)
fc_cmd = u1_minus_pi.instructions[0][-1].command
self.assertEqual(fc_cmd.phase, np.pi)

View File

@ -12,15 +12,20 @@
import numpy as np
from qiskit.test import QiskitTestCase
from qiskit.qobj import PulseQobjInstruction, PulseQobjExperimentConfig
from qiskit.qobj.converters import PulseQobjConverter, LoConfigConverter
from qiskit.pulse.commands import SamplePulse, FrameChange, PersistentValue, Snapshot, Acquire
from qiskit.qobj import (PulseQobjInstruction, PulseQobjExperimentConfig, PulseLibraryItem,
QobjMeasurementOption)
from qiskit.qobj.converters import (InstructionToQobjConverter, QobjToInstructionConverter,
LoConfigConverter)
from qiskit.qobj.converters.pulse_instruction import _is_math_expr_safe
from qiskit.pulse.commands import (SamplePulse, FrameChange, PersistentValue, Snapshot, Acquire,
Discriminator, Kernel)
from qiskit.pulse.channels import (DeviceSpecification, Qubit, AcquireChannel, DriveChannel,
MeasureChannel, RegisterSlot, MemorySlot)
ControlChannel, MeasureChannel, RegisterSlot, MemorySlot,)
from qiskit.pulse.schedule import ParameterizedSchedule
from qiskit.pulse import LoConfig
class TestInstructionConverter(QiskitTestCase):
class TestInstructionToQobjConverter(QiskitTestCase):
"""Pulse converter tests."""
def setUp(self):
@ -38,7 +43,7 @@ class TestInstructionConverter(QiskitTestCase):
def test_drive_instruction(self):
"""Test converted qobj from PulseInstruction."""
converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
command = SamplePulse(np.arange(0, 0.01), name='linear')
instruction = command(self.device.q[0].drive)
@ -52,7 +57,7 @@ class TestInstructionConverter(QiskitTestCase):
def test_frame_change(self):
"""Test converted qobj from FrameChangeInstruction."""
converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
command = FrameChange(phase=0.1)
instruction = command(self.device.q[0].drive)
@ -67,7 +72,7 @@ class TestInstructionConverter(QiskitTestCase):
def test_persistent_value(self):
"""Test converted qobj from PersistentValueInstruction."""
converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
command = PersistentValue(value=0.1j)
instruction = command(self.device.q[0].drive)
@ -82,7 +87,7 @@ class TestInstructionConverter(QiskitTestCase):
def test_acquire(self):
"""Test converted qobj from AcquireInstruction."""
converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
command = Acquire(duration=10)
instruction = command(self.device.q, self.device.mem, self.device.c)
@ -99,7 +104,7 @@ class TestInstructionConverter(QiskitTestCase):
def test_snapshot(self):
"""Test converted qobj from SnapShot."""
converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
instruction = Snapshot(name='label', snap_type='type')
valid_qobj = PulseQobjInstruction(
@ -112,6 +117,138 @@ class TestInstructionConverter(QiskitTestCase):
self.assertEqual(converter(0, instruction), valid_qobj)
class TestQobjToInstructionConverter(QiskitTestCase):
"""Pulse converter tests."""
def setUp(self):
self.linear = SamplePulse(np.arange(0, 0.01), name='linear')
self.pulse_library = [PulseLibraryItem(name=self.linear.name,
samples=self.linear.samples.tolist())]
self.converter = QobjToInstructionConverter(self.pulse_library, buffer=0)
self.device = DeviceSpecification(
qubits=[
Qubit(0, DriveChannel(0), MeasureChannel(0), AcquireChannel(0))
],
registers=[
RegisterSlot(0)
],
mem_slots=[
MemorySlot(0)
]
)
def test_drive_instruction(self):
"""Test converted qobj from PulseInstruction."""
cmd = self.linear
instruction = cmd(DriveChannel(0)) << 10
qobj = PulseQobjInstruction(name='linear', ch='d0', t0=10)
converted_instruction = self.converter(qobj)
self.assertEqual(converted_instruction.timeslots, instruction.timeslots)
self.assertEqual(converted_instruction.instructions[0][-1].command, cmd)
def test_frame_change(self):
"""Test converted qobj from FrameChangeInstruction."""
cmd = FrameChange(phase=0.1)
instruction = cmd(MeasureChannel(0))
qobj = PulseQobjInstruction(name='fc', ch='m0', t0=0, phase=0.1)
converted_instruction = self.converter(qobj)
self.assertEqual(converted_instruction.timeslots, instruction.timeslots)
self.assertEqual(converted_instruction.instructions[0][-1].command, cmd)
def test_persistent_value(self):
"""Test converted qobj from PersistentValueInstruction."""
cmd = PersistentValue(value=0.1j)
instruction = cmd(ControlChannel(1))
qobj = PulseQobjInstruction(name='pv', ch='u1', t0=0, val=0.1j)
converted_instruction = self.converter(qobj)
self.assertEqual(converted_instruction.timeslots, instruction.timeslots)
self.assertEqual(converted_instruction.instructions[0][-1].command, cmd)
def test_acquire(self):
"""Test converted qobj from AcquireInstruction."""
cmd = Acquire(10, Discriminator(name='test_disc', params={'test_params': 1.0}),
Kernel(name='test_kern', params={'test_params': 'test'}))
instruction = cmd(self.device.q, self.device.mem, self.device.c)
qobj = PulseQobjInstruction(name='acquire', t0=0, duration=10, qubits=[0],
memory_slot=[0], register_slot=[0],
kernels=[QobjMeasurementOption(
name='test_kern', params={'test_params': 'test'})],
discriminators=[QobjMeasurementOption(
name='test_disc', params={'test_params': 1.0})])
converted_instruction = self.converter(qobj)
self.assertEqual(converted_instruction.timeslots, instruction.timeslots)
self.assertEqual(converted_instruction.instructions[0][-1].command, cmd)
def test_snapshot(self):
"""Test converted qobj from SnapShot."""
cmd = Snapshot(name='label', snap_type='type')
instruction = cmd << 10
qobj = PulseQobjInstruction(name='snapshot', t0=10, label='label', type='type')
converted_instruction = self.converter(qobj)
self.assertEqual(converted_instruction.timeslots, instruction.timeslots)
self.assertEqual(converted_instruction.instructions[0][-1], cmd)
def test_parameterized_frame_change(self):
"""Test converted qobj from FrameChangeInstruction."""
cmd = FrameChange(phase=4.)
instruction = cmd(MeasureChannel(0)) << 10
qobj = PulseQobjInstruction(name='fc', ch='m0', t0=10, phase='P1**2')
converted_instruction = self.converter(qobj)
self.assertIsInstance(converted_instruction, ParameterizedSchedule)
evaluated_instruction = converted_instruction.bind_parameters(2.)
self.assertEqual(evaluated_instruction.timeslots, instruction.timeslots)
self.assertEqual(evaluated_instruction.instructions[0][-1].command, cmd)
def test_parameterized_persistent_value(self):
"""Test converted qobj from PersistentValueInstruction."""
cmd = PersistentValue(value=0.5+0.j)
instruction = cmd(ControlChannel(1)) << 10
qobj = PulseQobjInstruction(name='pv', ch='u1', t0=10, val='P1*cos(np.pi*P2)')
converted_instruction = self.converter(qobj)
self.assertIsInstance(converted_instruction, ParameterizedSchedule)
evaluated_instruction = converted_instruction.bind_parameters(P1=0.5, P2=0.)
self.assertEqual(evaluated_instruction.timeslots, instruction.timeslots)
self.assertEqual(evaluated_instruction.instructions[0][-1].command, cmd)
def test_expression_sanitizer(self):
"""Test math expression sanitization."""
self.assertFalse(_is_math_expr_safe('INSERT INTO students VALUES (?,?)'))
self.assertFalse(_is_math_expr_safe('import math'))
self.assertFalse(_is_math_expr_safe('complex'))
self.assertFalse(_is_math_expr_safe('2***2'))
self.assertFalse(_is_math_expr_safe('avdfd*3'))
self.assertFalse(_is_math_expr_safe('Cos(1+2)'))
self.assertFalse(_is_math_expr_safe('hello_world'))
self.assertFalse(_is_math_expr_safe('1_2'))
self.assertFalse(_is_math_expr_safe('2+-2'))
self.assertTrue(_is_math_expr_safe('1+1*2*3.2+8*cos(1)**2'))
self.assertTrue(_is_math_expr_safe('pi*2'))
self.assertTrue(_is_math_expr_safe('-P1*cos(P2)'))
self.assertTrue(_is_math_expr_safe('-P1*P2*P3'))
class TestLoConverter(QiskitTestCase):
"""LO converter tests."""

View File

@ -27,7 +27,7 @@ from qiskit.providers.basicaer import basicaerjob
from qiskit.qobj import (QasmQobj, PulseQobj, QobjHeader,
PulseQobjInstruction, PulseQobjExperiment,
PulseQobjConfig, QobjMeasurementOption,
QobjPulseLibrary, QasmQobjInstruction,
PulseLibraryItem, QasmQobjInstruction,
QasmQobjExperiment, QasmQobjConfig)
from qiskit.qobj import validate_qobj_against_schema
from qiskit.validation.jsonschema.exceptions import SchemaValidationError
@ -146,7 +146,7 @@ class TestPulseQobj(QiskitTestCase):
memory_slot_size=8192,
meas_return='avg',
pulse_library=[
QobjPulseLibrary(name='pulse0',
PulseLibraryItem(name='pulse0',
samples=[0.0 + 0.0j,
0.5 + 0.0j,
0.0 + 0.0j])
@ -221,7 +221,7 @@ class TestPulseQobj(QiskitTestCase):
memory_slot_size=8192,
meas_return='avg',
pulse_library=[
QobjPulseLibrary(name='pulse0', samples=[0.1 + 0.0j])
PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j])
],
qubit_lo_freq=[4.9], meas_lo_freq=[6.9],
rep_time=1000),
@ -233,8 +233,8 @@ class TestPulseQobj(QiskitTestCase):
'meas_lo_freq': [6.9],
'rep_time': 1000},
),
QobjPulseLibrary: (
QobjPulseLibrary(name='pulse0', samples=[0.1 + 0.0j]),
PulseLibraryItem: (
PulseLibraryItem(name='pulse0', samples=[0.1 + 0.0j]),
{'name': 'pulse0', 'samples': [[0.1, 0.0]]}
),
PulseQobjExperiment: (