Exemplo n.º 1
0
 def test_can_create_valid_user_lo_config(self):
     """Test if a LoConfig can be created with valid user_los."""
     channel1 = DriveChannel(0)
     channel2 = MeasureChannel(0)
     user_lo_config = LoConfig({channel1: 1.4, channel2: 3.6})
     self.assertEqual(1.4, user_lo_config.qubit_los[channel1])
     self.assertEqual(3.6, user_lo_config.meas_los[channel2])
Exemplo n.º 2
0
    def test_meas_los(self):
        """Test measurement channel configuration."""
        user_lo_config = LoConfig({self.device.q[0].measure: 3.5})
        converter = LoConfigConverter(PulseQobjExperimentConfig, [1.2], [3.4])

        valid_qobj = PulseQobjExperimentConfig(meas_lo_freq=[3.5])

        self.assertEqual(converter(user_lo_config), valid_qobj)
Exemplo n.º 3
0
    def test_qubit_los(self):
        """Test qubit channel configuration."""
        user_lo_config = LoConfig({self.device.q[0].drive: 1.3})
        converter = LoConfigConverter(PulseQobjExperimentConfig, [1.2], [3.4])

        valid_qobj = PulseQobjExperimentConfig(qubit_lo_freq=[1.3])

        self.assertEqual(converter(user_lo_config), valid_qobj)
 def test_can_create_valid_user_lo_config(self):
     """Test if a LoConfig can be created with valid user_los.
     """
     channel1 = DriveChannel(0, lo_freq=1.2, lo_freq_range=(1.0, 2.0))
     channel2 = MeasureChannel(0, lo_freq=3.4, lo_freq_range=(3.0, 4.0))
     user_lo_config = LoConfig({channel1: 1.4, channel2: 3.6})
     self.assertEqual(1.4, user_lo_config._q_lo_freq[channel1])
     self.assertEqual(3.6, user_lo_config._m_lo_freq[channel2])
    def test_get_channel_lo(self):
        """Test retrieving channel lo from LO config."""
        channel = DriveChannel(0)
        lo_config = LoConfig({channel: 1.0})
        self.assertEqual(lo_config.channel_lo(channel), 1.0)

        channel = MeasureChannel(0)
        lo_config = LoConfig({channel: 2.0})
        self.assertEqual(lo_config.channel_lo(channel), 2.0)

        with self.assertRaises(PulseError):
            lo_config.channel_lo(MeasureChannel(1))
 def test_keep_dict_unchanged_after_updating_the_dict_used_in_construction(self):
     """Test if a LoConfig keeps its dictionary unchanged even after
     the dictionary used in construction is updated.
     """
     channel = DriveChannel(0)
     original = {channel: 3.4}
     user_lo_config = LoConfig(original)
     self.assertEqual(3.4, user_lo_config.qubit_los[channel])
     original[channel] = 5.6
     self.assertEqual(3.4, user_lo_config.qubit_los[channel])
Exemplo n.º 7
0
    def __init__(self, qobj_model, qubit_lo_freq, meas_lo_freq, qubit_lo_range,
                 meas_lo_range, **run_config):
        """Create new converter.

        Args:
            qobj_model (PulseQobjExperimentConfig): qobj model for experiment config.
            qubit_lo_freq (list): List of default qubit lo frequencies.
            meas_lo_freq (list): List of default meas lo frequencies.
            qubit_lo_range (list): List of qubit lo ranges.
            meas_lo_range (list): List of measurement lo ranges.
            run_config (dict): experimental configuration.
        """
        self.qobj_model = qobj_model
        self.qubit_lo_freq = qubit_lo_freq
        self.meas_lo_freq = meas_lo_freq
        self.run_config = run_config

        self.default_lo_config = LoConfig()

        for i, lo_range in enumerate(qubit_lo_range):
            self.default_lo_config.add_lo_range(DriveChannel(i), lo_range)
        for i, lo_range in enumerate(meas_lo_range):
            self.default_lo_config.add_lo_range(MeasureChannel(i), lo_range)
Exemplo n.º 8
0
def _parse_pulse_args(backend, qubit_lo_freq, meas_lo_freq, qubit_lo_range,
                      meas_lo_range, schedule_los, meas_level, meas_return,
                      meas_map, memory_slot_size, rep_time, parametric_pulses,
                      **run_config):
    """Build a pulse RunConfig replacing unset arguments with defaults derived from the `backend`.
    See `assemble` for more information on the required arguments.

    Returns:
        RunConfig: a run config, which is a standardized object that configures the qobj
            and determines the runtime environment.
    Raises:
        SchemaValidationError: If the given meas_level is not allowed for the given `backend`.
    """
    # grab relevant info from backend if it exists
    backend_config = None
    backend_default = None
    if backend:
        backend_default = backend.defaults()
        backend_config = backend.configuration()

        if meas_level not in getattr(backend_config, 'meas_levels',
                                     [MeasLevel.CLASSIFIED]):
            raise SchemaValidationError((
                'meas_level = {} not supported for backend {}, only {} is supported'
            ).format(meas_level, backend_config.backend_name,
                     backend_config.meas_levels))

    meas_map = meas_map or getattr(backend_config, 'meas_map', None)

    schedule_los = schedule_los or []
    if isinstance(schedule_los, (LoConfig, dict)):
        schedule_los = [schedule_los]

    # Convert to LoConfig if LO configuration supplied as dictionary
    schedule_los = [
        lo_config if isinstance(lo_config, LoConfig) else LoConfig(lo_config)
        for lo_config in schedule_los
    ]

    if not qubit_lo_freq and hasattr(backend_default, 'qubit_freq_est'):
        qubit_lo_freq = backend_default.qubit_freq_est
    if not meas_lo_freq and hasattr(backend_default, 'meas_freq_est'):
        meas_lo_freq = backend_default.meas_freq_est

    qubit_lo_range = qubit_lo_range or getattr(backend_config,
                                               'qubit_lo_range', None)
    meas_lo_range = meas_lo_range or getattr(backend_config, 'meas_lo_range',
                                             None)

    dynamic_reprate_enabled = getattr(backend_config,
                                      'dynamic_reprate_enabled', False)

    rep_time = rep_time or getattr(backend_config, 'rep_times', None)
    if rep_time:
        if dynamic_reprate_enabled:
            warnings.warn(
                "Dynamic rep rates are supported on this backend. 'rep_delay' will be "
                "used instead of 'rep_time'.", RuntimeWarning)
        if isinstance(rep_time, list):
            rep_time = rep_time[0]
        rep_time = int(rep_time * 1e6)  # convert sec to μs

    parametric_pulses = parametric_pulses or getattr(backend_config,
                                                     'parametric_pulses', [])

    # create run configuration and populate
    run_config_dict = dict(qubit_lo_freq=qubit_lo_freq,
                           meas_lo_freq=meas_lo_freq,
                           qubit_lo_range=qubit_lo_range,
                           meas_lo_range=meas_lo_range,
                           schedule_los=schedule_los,
                           meas_level=meas_level,
                           meas_return=meas_return,
                           meas_map=meas_map,
                           memory_slot_size=memory_slot_size,
                           rep_time=rep_time,
                           parametric_pulses=parametric_pulses,
                           **run_config)
    run_config = RunConfig(
        **{k: v
           for k, v in run_config_dict.items() if v is not None})

    return run_config
Exemplo n.º 9
0
def _parse_run_args(backend, qobj_id, qobj_header, shots, memory, max_credits,
                    seed_simulator, default_qubit_los, default_meas_los,
                    schedule_los, meas_level, meas_return, memory_slots,
                    memory_slot_size, rep_time, parameter_binds, **run_config):
    """Resolve the various types of args allowed to the assemble() function through
    duck typing, overriding args, etc. Refer to the assemble() docstring for details on
    what types of inputs are allowed.

    Here the args are resolved by converting them to standard instances, and prioritizing
    them in case a run option is passed through multiple args (explicitly setting an arg
    has more priority than the arg set by backend)

    Returns:
        RunConfig: a run config, which is a standardized object that configures the qobj
            and determines the runtime environment.
    """
    # grab relevant info from backend if it exists
    backend_config = None
    backend_default = None
    if backend:
        backend_config = backend.configuration()
        # TODO : Remove usage of config.defaults when backend.defaults() is updated.
        try:
            backend_default = backend.defaults()
        except (ModelValidationError, AttributeError):
            from collections import namedtuple
            backend_config_defaults = getattr(backend_config, 'defaults', {})
            BackendDefault = namedtuple('BackendDefault',
                                        ('qubit_freq_est', 'meas_freq_est'))
            backend_default = BackendDefault(
                qubit_freq_est=backend_config_defaults.get('qubit_freq_est'),
                meas_freq_est=backend_config_defaults.get('meas_freq_est'))

    memory_slots = memory_slots or getattr(backend_config, 'memory_slots',
                                           None)
    rep_time = rep_time or getattr(backend_config, 'rep_times', None)
    if isinstance(rep_time, list):
        rep_time = rep_time[-1]

    parameter_binds = parameter_binds or []

    # add default empty lo config
    schedule_los = schedule_los or []
    if isinstance(schedule_los, (LoConfig, dict)):
        schedule_los = [schedule_los]

    # Convert to LoConfig if lo configuration supplied as dictionary
    schedule_los = [
        lo_config if isinstance(lo_config, LoConfig) else LoConfig(lo_config)
        for lo_config in schedule_los
    ]

    qubit_lo_freq = default_qubit_los or getattr(backend_default,
                                                 'qubit_freq_est', [])
    meas_lo_freq = default_meas_los or getattr(backend_default,
                                               'meas_freq_est', [])

    # an identifier for the Qobj
    qobj_id = qobj_id or str(uuid.uuid4())

    # The header that goes at the top of the Qobj (and later Result)
    # we process it as dict, then write entries that are not None to a QobjHeader object
    qobj_header = qobj_header or {}
    if isinstance(qobj_header, QobjHeader):
        qobj_header = qobj_header.to_dict()
    backend_name = getattr(backend_config, 'backend_name', None)
    backend_version = getattr(backend_config, 'backend_version', None)
    qobj_header = {
        **dict(backend_name=backend_name, backend_version=backend_version),
        **qobj_header
    }
    qobj_header = QobjHeader(
        **{k: v
           for k, v in qobj_header.items() if v is not None})

    # create run configuration and populate
    run_config_dict = dict(
        shots=shots,
        memory=memory,
        max_credits=max_credits,
        seed_simulator=seed_simulator,
        seed=seed_simulator,  # deprecated
        qubit_lo_freq=qubit_lo_freq,
        meas_lo_freq=meas_lo_freq,
        schedule_los=schedule_los,
        meas_level=meas_level,
        meas_return=meas_return,
        memory_slots=memory_slots,
        memory_slot_size=memory_slot_size,
        rep_time=rep_time,
        parameter_binds=parameter_binds,
        **run_config)
    run_config = RunConfig(
        **{k: v
           for k, v in run_config_dict.items() if v is not None})

    return qobj_id, qobj_header, run_config
Exemplo n.º 10
0
def _parse_common_args(
    backend,
    qobj_id,
    qobj_header,
    shots,
    memory,
    max_credits,
    seed_simulator,
    init_qubits,
    rep_delay,
    qubit_lo_freq,
    meas_lo_freq,
    qubit_lo_range,
    meas_lo_range,
    schedule_los,
    **run_config,
):
    """Resolve the various types of args allowed to the assemble() function through
    duck typing, overriding args, etc. Refer to the assemble() docstring for details on
    what types of inputs are allowed.

    Here the args are resolved by converting them to standard instances, and prioritizing
    them in case a run option is passed through multiple args (explicitly setting an arg
    has more priority than the arg set by backend)

    Returns:
        RunConfig: a run config, which is a standardized object that configures the qobj
            and determines the runtime environment.

    Raises:
        QiskitError:
            - If the memory arg is True and the backend does not support memory.
            - If ``shots`` exceeds ``max_shots`` for the configured backend.
            - If ``shots`` are not int type.
            - If any of qubit or meas lo's, or associated ranges do not have length equal to
            ``n_qubits``.
            - If qubit or meas lo's do not fit into perscribed ranges.
    """
    # grab relevant info from backend if it exists
    backend_config = None
    backend_defaults = None
    n_qubits = None
    if backend:
        backend_config = backend.configuration()
        n_qubits = backend_config.n_qubits
        # check for memory flag applied to backend that does not support memory
        if memory and not backend_config.memory:
            raise QiskitError(
                f"memory not supported by backend {backend_config.backend_name}"
            )

        # try to set defaults for pulse, other leave as None
        if backend_config.open_pulse:
            try:
                backend_defaults = backend.defaults()
            except AttributeError:
                pass

    # an identifier for the Qobj
    qobj_id = qobj_id or str(uuid.uuid4())

    # The header that goes at the top of the Qobj (and later Result)
    # we process it as dict, then write entries that are not None to a QobjHeader object
    qobj_header = qobj_header or {}
    if isinstance(qobj_header, QobjHeader):
        qobj_header = qobj_header.to_dict()
    backend_name = getattr(backend_config, "backend_name", None)
    backend_version = getattr(backend_config, "backend_version", None)
    qobj_header = {
        **dict(backend_name=backend_name, backend_version=backend_version),
        **qobj_header,
    }
    qobj_header = QobjHeader(
        **{k: v
           for k, v in qobj_header.items() if v is not None})

    max_shots = getattr(backend_config, "max_shots", None)
    if shots is None:
        if max_shots:
            shots = min(1024, max_shots)
        else:
            shots = 1024
    elif not isinstance(shots, int):
        raise QiskitError("Argument 'shots' should be of type 'int'")
    elif max_shots and max_shots < shots:
        raise QiskitError(
            "Number of shots specified: %s exceeds max_shots property of the "
            "backend: %s." % (shots, max_shots))

    dynamic_reprate_enabled = getattr(backend_config,
                                      "dynamic_reprate_enabled", False)
    if dynamic_reprate_enabled:
        default_rep_delay = getattr(backend_config, "default_rep_delay", None)
        rep_delay_range = getattr(backend_config, "rep_delay_range", None)
        rep_delay = _parse_rep_delay(rep_delay, default_rep_delay,
                                     rep_delay_range)
    else:
        if rep_delay is not None:
            rep_delay = None
            warnings.warn(
                "Dynamic rep rates not supported on this backend, cannot use rep_delay.",
                RuntimeWarning,
            )

    qubit_lo_freq = qubit_lo_freq or getattr(backend_defaults,
                                             "qubit_freq_est", None)
    meas_lo_freq = meas_lo_freq or getattr(backend_defaults, "meas_freq_est",
                                           None)

    qubit_lo_range = qubit_lo_range or getattr(backend_config,
                                               "qubit_lo_range", None)
    meas_lo_range = meas_lo_range or getattr(backend_config, "meas_lo_range",
                                             None)

    # check that LO frequencies are in the perscribed range
    _check_lo_freqs(qubit_lo_freq, qubit_lo_range, "qubit")
    _check_lo_freqs(meas_lo_freq, meas_lo_range, "meas")

    # configure experiment level LO frequencies
    schedule_los = schedule_los or []
    if isinstance(schedule_los, (LoConfig, dict)):
        schedule_los = [schedule_los]

    # Convert to LoConfig if LO configuration supplied as dictionary
    schedule_los = [
        lo_config if isinstance(lo_config, LoConfig) else LoConfig(lo_config)
        for lo_config in schedule_los
    ]

    # create run configuration and populate
    run_config_dict = dict(
        shots=shots,
        memory=memory,
        max_credits=max_credits,
        seed_simulator=seed_simulator,
        init_qubits=init_qubits,
        rep_delay=rep_delay,
        qubit_lo_freq=qubit_lo_freq,
        meas_lo_freq=meas_lo_freq,
        qubit_lo_range=qubit_lo_range,
        meas_lo_range=meas_lo_range,
        schedule_los=schedule_los,
        n_qubits=n_qubits,
        **run_config,
    )

    return qobj_id, qobj_header, run_config_dict
Exemplo n.º 11
0
 def test_fail_to_create_with_invalid_channel(self):
     """Test if a LoConfig cannot be created with invalid channel.
     """
     channel = AcquireChannel(0)
     with self.assertRaises(PulseError):
         LoConfig({channel: 1.0})
Exemplo n.º 12
0
 def test_fail_to_create_with_out_of_range_user_lo(self):
     """Test if a LoConfig cannot be created with invalid user_los.
     """
     channel = DriveChannel(0)
     with self.assertRaises(PulseError):
         LoConfig({channel: 3.3}, {channel: (1.0, 2.0)})
Exemplo n.º 13
0
 def test_can_create_empty_user_lo_config(self):
     """Test if a LoConfig can be created without no arguments.
     """
     user_lo_config = LoConfig()
     self.assertEqual({}, user_lo_config.qubit_los)
     self.assertEqual({}, user_lo_config.meas_los)
 def test_can_create_empty_user_lo_config(self):
     """Test if a LoConfig can be created without no arguments.
     """
     user_lo_config = LoConfig()
     self.assertEqual({}, user_lo_config._q_lo_freq)
     self.assertEqual({}, user_lo_config._m_lo_freq)
Exemplo n.º 15
0
class LoConfigConverter:
    """ This class supports to convert LoConfig into ~`lo_freq` attribute of configs.
    The format of LO frequency setup can be easily modified by replacing
    `get_qubit_los` and `get_meas_los` to align with your backend.
    """
    def __init__(self, qobj_model, qubit_lo_freq, meas_lo_freq, qubit_lo_range,
                 meas_lo_range, **run_config):
        """Create new converter.

        Args:
            qobj_model (PulseQobjExperimentConfig): qobj model for experiment config.
            qubit_lo_freq (list): List of default qubit lo frequencies.
            meas_lo_freq (list): List of default meas lo frequencies.
            qubit_lo_range (list): List of qubit lo ranges.
            meas_lo_range (list): List of measurement lo ranges.
            run_config (dict): experimental configuration.
        """
        self.qobj_model = qobj_model
        self.qubit_lo_freq = qubit_lo_freq
        self.meas_lo_freq = meas_lo_freq
        self.run_config = run_config

        self.default_lo_config = LoConfig()

        for i, lo_range in enumerate(qubit_lo_range):
            self.default_lo_config.add_lo_range(DriveChannel(i), lo_range)
        for i, lo_range in enumerate(meas_lo_range):
            self.default_lo_config.add_lo_range(MeasureChannel(i), lo_range)

    def __call__(self, user_lo_config):
        """Return PulseQobjExperimentConfig

        Args:
            user_lo_config (LoConfig): A dictionary of LOs to format.

        Returns:
            PulseQobjExperimentConfig: qobj.
        """
        lo_config = {}

        q_los = self.get_qubit_los(user_lo_config)
        if q_los:
            lo_config['qubit_lo_freq'] = q_los

        m_los = self.get_meas_los(user_lo_config)
        if m_los:
            lo_config['meas_lo_freq'] = m_los

        return self.qobj_model(**lo_config)

    def get_qubit_los(self, user_lo_config):
        """Embed default qubit LO frequencies from backend and format them to list object.
        If configured lo frequency is the same as default, this method returns `None`.

        Args:
            user_lo_config (LoConfig): A dictionary of LOs to format.

        Returns:
            list: A list of qubit LOs.

        Raises:
            PulseError: when LO frequencies are missing.
        """
        _q_los = self.qubit_lo_freq.copy()

        for channel, lo_freq in user_lo_config.qubit_los.items():
            self.default_lo_config.check_lo(channel, lo_freq)
            _q_los[channel.index] = lo_freq

        if _q_los == self.qubit_lo_freq:
            return None

        return _q_los

    def get_meas_los(self, user_lo_config):
        """Embed default meas LO frequencies from backend and format them to list object.
        If configured lo frequency is the same as default, this method returns `None`.

        Args:
            user_lo_config (LoConfig): A dictionary of LOs to format.

        Returns:
            list: A list of meas LOs.

        Raises:
            PulseError: when LO frequencies are missing.
        """
        _m_los = self.meas_lo_freq.copy()

        for channel, lo_freq in user_lo_config.meas_los.items():
            self.default_lo_config.check_lo(channel, lo_freq)
            _m_los[channel.index] = lo_freq

        if _m_los == self.meas_lo_freq:
            return None

        return _m_los