qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0__cp38-abi3-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +27 -16
- qiskit/_accelerate.pyd +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/assembler/__init__.py +5 -10
- qiskit/assembler/disassemble.py +5 -6
- qiskit/circuit/__init__.py +1061 -232
- qiskit/circuit/_classical_resource_map.py +10 -6
- qiskit/circuit/_utils.py +18 -8
- qiskit/circuit/annotated_operation.py +21 -0
- qiskit/circuit/barrier.py +10 -13
- qiskit/circuit/bit.py +0 -1
- qiskit/circuit/classical/__init__.py +2 -2
- qiskit/circuit/classical/expr/__init__.py +39 -5
- qiskit/circuit/classical/expr/constructors.py +84 -1
- qiskit/circuit/classical/expr/expr.py +83 -13
- qiskit/circuit/classical/expr/visitors.py +83 -0
- qiskit/circuit/classical/types/__init__.py +5 -4
- qiskit/circuit/classicalfunction/__init__.py +1 -0
- qiskit/circuit/commutation_checker.py +86 -51
- qiskit/circuit/controlflow/_builder_utils.py +9 -1
- qiskit/circuit/controlflow/break_loop.py +8 -22
- qiskit/circuit/controlflow/builder.py +116 -1
- qiskit/circuit/controlflow/continue_loop.py +8 -22
- qiskit/circuit/controlflow/control_flow.py +47 -8
- qiskit/circuit/controlflow/for_loop.py +8 -23
- qiskit/circuit/controlflow/if_else.py +13 -27
- qiskit/circuit/controlflow/switch_case.py +14 -21
- qiskit/circuit/controlflow/while_loop.py +9 -23
- qiskit/circuit/controlledgate.py +2 -2
- qiskit/circuit/delay.py +7 -5
- qiskit/circuit/gate.py +20 -7
- qiskit/circuit/instruction.py +31 -30
- qiskit/circuit/instructionset.py +9 -22
- qiskit/circuit/library/__init__.py +3 -13
- qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
- qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
- qiskit/circuit/library/blueprintcircuit.py +29 -7
- qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
- qiskit/circuit/library/generalized_gates/isometry.py +51 -254
- qiskit/circuit/library/generalized_gates/pauli.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +4 -1
- qiskit/circuit/library/generalized_gates/rv.py +15 -11
- qiskit/circuit/library/generalized_gates/uc.py +2 -98
- qiskit/circuit/library/generalized_gates/unitary.py +9 -4
- qiskit/circuit/library/hamiltonian_gate.py +11 -5
- qiskit/circuit/library/n_local/efficient_su2.py +5 -5
- qiskit/circuit/library/n_local/n_local.py +100 -49
- qiskit/circuit/library/n_local/two_local.py +3 -59
- qiskit/circuit/library/overlap.py +3 -3
- qiskit/circuit/library/phase_oracle.py +1 -1
- qiskit/circuit/library/quantum_volume.py +39 -38
- qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
- qiskit/circuit/library/standard_gates/global_phase.py +4 -2
- qiskit/circuit/library/standard_gates/i.py +1 -2
- qiskit/circuit/library/standard_gates/iswap.py +1 -2
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
- qiskit/circuit/library/standard_gates/p.py +31 -15
- qiskit/circuit/library/standard_gates/r.py +4 -3
- qiskit/circuit/library/standard_gates/rx.py +7 -4
- qiskit/circuit/library/standard_gates/rxx.py +4 -3
- qiskit/circuit/library/standard_gates/ry.py +7 -4
- qiskit/circuit/library/standard_gates/ryy.py +4 -3
- qiskit/circuit/library/standard_gates/rz.py +7 -4
- qiskit/circuit/library/standard_gates/rzx.py +4 -3
- qiskit/circuit/library/standard_gates/rzz.py +4 -3
- qiskit/circuit/library/standard_gates/s.py +4 -8
- qiskit/circuit/library/standard_gates/t.py +2 -4
- qiskit/circuit/library/standard_gates/u.py +16 -11
- qiskit/circuit/library/standard_gates/u1.py +6 -2
- qiskit/circuit/library/standard_gates/u2.py +4 -2
- qiskit/circuit/library/standard_gates/u3.py +9 -5
- qiskit/circuit/library/standard_gates/x.py +22 -11
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
- qiskit/circuit/library/standard_gates/z.py +1 -2
- qiskit/circuit/measure.py +4 -1
- qiskit/circuit/operation.py +13 -8
- qiskit/circuit/parameter.py +11 -6
- qiskit/circuit/quantumcircuit.py +1910 -260
- qiskit/circuit/quantumcircuitdata.py +2 -2
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/store.py +95 -0
- qiskit/compiler/assembler.py +22 -22
- qiskit/compiler/transpiler.py +63 -112
- qiskit/converters/__init__.py +17 -2
- qiskit/converters/circuit_to_dag.py +7 -0
- qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
- qiskit/converters/circuit_to_gate.py +2 -0
- qiskit/converters/circuit_to_instruction.py +22 -0
- qiskit/converters/dag_to_circuit.py +4 -0
- qiskit/converters/dag_to_dagdependency_v2.py +44 -0
- qiskit/dagcircuit/collect_blocks.py +15 -10
- qiskit/dagcircuit/dagcircuit.py +434 -124
- qiskit/dagcircuit/dagdependency.py +19 -12
- qiskit/dagcircuit/dagdependency_v2.py +641 -0
- qiskit/dagcircuit/dagdepnode.py +19 -16
- qiskit/dagcircuit/dagnode.py +14 -4
- qiskit/passmanager/passmanager.py +11 -11
- qiskit/primitives/__init__.py +22 -12
- qiskit/primitives/backend_estimator.py +3 -5
- qiskit/primitives/backend_estimator_v2.py +410 -0
- qiskit/primitives/backend_sampler_v2.py +287 -0
- qiskit/primitives/base/base_estimator.py +4 -9
- qiskit/primitives/base/base_sampler.py +2 -2
- qiskit/primitives/containers/__init__.py +6 -4
- qiskit/primitives/containers/bit_array.py +293 -2
- qiskit/primitives/containers/data_bin.py +123 -50
- qiskit/primitives/containers/estimator_pub.py +10 -3
- qiskit/primitives/containers/observables_array.py +2 -2
- qiskit/primitives/containers/pub_result.py +1 -1
- qiskit/primitives/containers/sampler_pub.py +19 -3
- qiskit/primitives/containers/sampler_pub_result.py +74 -0
- qiskit/primitives/containers/shape.py +4 -4
- qiskit/primitives/statevector_estimator.py +4 -4
- qiskit/primitives/statevector_sampler.py +7 -12
- qiskit/providers/__init__.py +65 -34
- qiskit/providers/backend.py +2 -2
- qiskit/providers/backend_compat.py +8 -10
- qiskit/providers/basic_provider/__init__.py +2 -23
- qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
- qiskit/providers/basic_provider/basic_simulator.py +81 -21
- qiskit/providers/fake_provider/__init__.py +1 -1
- qiskit/providers/fake_provider/fake_1q.py +1 -1
- qiskit/providers/fake_provider/fake_backend.py +3 -408
- qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
- qiskit/providers/models/__init__.py +2 -2
- qiskit/providers/provider.py +16 -0
- qiskit/pulse/builder.py +4 -1
- qiskit/pulse/parameter_manager.py +60 -4
- qiskit/pulse/schedule.py +29 -13
- qiskit/pulse/utils.py +61 -20
- qiskit/qasm2/__init__.py +1 -5
- qiskit/qasm2/parse.py +1 -4
- qiskit/qasm3/__init__.py +42 -5
- qiskit/qasm3/ast.py +19 -0
- qiskit/qasm3/exporter.py +178 -106
- qiskit/qasm3/printer.py +27 -5
- qiskit/qobj/converters/pulse_instruction.py +6 -6
- qiskit/qpy/__init__.py +299 -67
- qiskit/qpy/binary_io/circuits.py +216 -47
- qiskit/qpy/binary_io/schedules.py +42 -36
- qiskit/qpy/binary_io/value.py +201 -22
- qiskit/qpy/common.py +1 -1
- qiskit/qpy/exceptions.py +20 -0
- qiskit/qpy/formats.py +29 -0
- qiskit/qpy/type_keys.py +21 -0
- qiskit/quantum_info/analysis/distance.py +3 -3
- qiskit/quantum_info/analysis/make_observable.py +2 -1
- qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
- qiskit/quantum_info/operators/channel/chi.py +9 -8
- qiskit/quantum_info/operators/channel/choi.py +10 -9
- qiskit/quantum_info/operators/channel/kraus.py +2 -1
- qiskit/quantum_info/operators/channel/ptm.py +10 -9
- qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
- qiskit/quantum_info/operators/channel/stinespring.py +2 -1
- qiskit/quantum_info/operators/channel/superop.py +12 -11
- qiskit/quantum_info/operators/channel/transformations.py +12 -11
- qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
- qiskit/quantum_info/operators/operator.py +43 -30
- qiskit/quantum_info/operators/scalar_op.py +10 -9
- qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
- qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
- qiskit/quantum_info/operators/symplectic/pauli.py +53 -6
- qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
- qiskit/quantum_info/operators/symplectic/random.py +3 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +61 -36
- qiskit/quantum_info/states/densitymatrix.py +13 -13
- qiskit/quantum_info/states/stabilizerstate.py +3 -3
- qiskit/quantum_info/states/statevector.py +14 -13
- qiskit/quantum_info/states/utils.py +5 -3
- qiskit/result/__init__.py +6 -0
- qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -1
- qiskit/result/mitigation/utils.py +3 -2
- qiskit/scheduler/__init__.py +10 -1
- qiskit/scheduler/methods/__init__.py +1 -8
- qiskit/synthesis/__init__.py +3 -6
- qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
- qiskit/synthesis/evolution/lie_trotter.py +7 -14
- qiskit/synthesis/evolution/qdrift.py +3 -4
- qiskit/synthesis/linear/cnot_synth.py +1 -3
- qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
- qiskit/synthesis/permutation/__init__.py +1 -0
- qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
- qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
- qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
- qiskit/synthesis/unitary/aqc/__init__.py +1 -1
- qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
- qiskit/synthesis/unitary/qsd.py +3 -2
- qiskit/transpiler/__init__.py +7 -3
- qiskit/transpiler/layout.py +140 -61
- qiskit/transpiler/passes/__init__.py +10 -2
- qiskit/transpiler/passes/basis/basis_translator.py +9 -4
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
- qiskit/transpiler/passes/layout/apply_layout.py +8 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
- qiskit/transpiler/passes/layout/set_layout.py +1 -1
- qiskit/transpiler/passes/optimization/__init__.py +2 -0
- qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
- qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
- qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
- qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
- qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
- qiskit/transpiler/passes/routing/__init__.py +1 -0
- qiskit/transpiler/passes/routing/basic_swap.py +13 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +8 -1
- qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
- qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
- qiskit/transpiler/passes/utils/gates_basis.py +3 -3
- qiskit/transpiler/passmanager.py +44 -1
- qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
- qiskit/transpiler/preset_passmanagers/common.py +4 -6
- qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
- qiskit/utils/__init__.py +3 -2
- qiskit/utils/optionals.py +6 -2
- qiskit/utils/parallel.py +24 -15
- qiskit/visualization/array.py +1 -1
- qiskit/visualization/bloch.py +2 -3
- qiskit/visualization/circuit/matplotlib.py +44 -14
- qiskit/visualization/circuit/text.py +38 -18
- qiskit/visualization/counts_visualization.py +3 -6
- qiskit/visualization/dag_visualization.py +6 -7
- qiskit/visualization/gate_map.py +9 -1
- qiskit/visualization/pulse_v2/interface.py +8 -3
- qiskit/visualization/state_visualization.py +3 -2
- qiskit/visualization/timeline/interface.py +18 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/METADATA +12 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/RECORD +261 -251
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/WHEEL +1 -1
- qiskit/_qasm2.pyd +0 -0
- qiskit/_qasm3.pyd +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/entry_points.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
# This code is part of Qiskit.
|
2
2
|
#
|
3
|
-
# (C) Copyright IBM 2019,
|
3
|
+
# (C) Copyright IBM 2019, 2024.
|
4
4
|
#
|
5
5
|
# This code is licensed under the Apache License, Version 2.0. You may
|
6
6
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
@@ -17,28 +17,14 @@ Base class for dummy backends.
|
|
17
17
|
"""
|
18
18
|
|
19
19
|
import warnings
|
20
|
-
import collections
|
21
|
-
import json
|
22
|
-
import os
|
23
|
-
import re
|
24
|
-
|
25
|
-
from typing import List, Iterable
|
26
20
|
|
27
21
|
from qiskit import circuit
|
28
|
-
from qiskit.providers.models import BackendProperties
|
29
|
-
from qiskit.providers import
|
22
|
+
from qiskit.providers.models import BackendProperties
|
23
|
+
from qiskit.providers import BackendV1
|
30
24
|
from qiskit import pulse
|
31
25
|
from qiskit.exceptions import QiskitError
|
32
26
|
from qiskit.utils import optionals as _optionals
|
33
27
|
from qiskit.providers import basic_provider
|
34
|
-
from qiskit.transpiler import Target
|
35
|
-
from qiskit.providers.backend_compat import convert_to_target
|
36
|
-
|
37
|
-
from .utils.json_decoder import (
|
38
|
-
decode_backend_configuration,
|
39
|
-
decode_backend_properties,
|
40
|
-
decode_pulse_defaults,
|
41
|
-
)
|
42
28
|
|
43
29
|
|
44
30
|
class _Credentials:
|
@@ -50,397 +36,6 @@ class _Credentials:
|
|
50
36
|
self.project = "project"
|
51
37
|
|
52
38
|
|
53
|
-
class FakeBackendV2(BackendV2):
|
54
|
-
"""A fake backend class for testing and noisy simulation using real backend
|
55
|
-
snapshots.
|
56
|
-
|
57
|
-
The class inherits :class:`~qiskit.providers.BackendV2` class. This version
|
58
|
-
differs from earlier :class:`~qiskit.providers.fake_provider.FakeBackend` (V1) class in a
|
59
|
-
few aspects. Firstly, configuration attribute no longer exsists. Instead,
|
60
|
-
attributes exposing equivalent required immutable properties of the backend
|
61
|
-
device are added. For example ``fake_backend.configuration().n_qubits`` is
|
62
|
-
accessible from ``fake_backend.num_qubits`` now. Secondly, this version
|
63
|
-
removes extra abstractions :class:`~qiskit.providers.fake_provider.FakeQasmBackend` and
|
64
|
-
:class:`~qiskit.providers.fake_provider.FakePulseBackend` that were present in V1.
|
65
|
-
"""
|
66
|
-
|
67
|
-
# directory and file names for real backend snapshots.
|
68
|
-
dirname = None
|
69
|
-
conf_filename = None
|
70
|
-
props_filename = None
|
71
|
-
defs_filename = None
|
72
|
-
backend_name = None
|
73
|
-
|
74
|
-
def __init__(self):
|
75
|
-
"""FakeBackendV2 initializer."""
|
76
|
-
self._conf_dict = self._get_conf_dict_from_json()
|
77
|
-
self._props_dict = None
|
78
|
-
self._defs_dict = None
|
79
|
-
super().__init__(
|
80
|
-
provider=None,
|
81
|
-
name=self._conf_dict.get("backend_name"),
|
82
|
-
description=self._conf_dict.get("description"),
|
83
|
-
online_date=self._conf_dict.get("online_date"),
|
84
|
-
backend_version=self._conf_dict.get("backend_version"),
|
85
|
-
)
|
86
|
-
self._target = None
|
87
|
-
self.sim = None
|
88
|
-
|
89
|
-
if "channels" in self._conf_dict:
|
90
|
-
self._parse_channels(self._conf_dict["channels"])
|
91
|
-
|
92
|
-
def _parse_channels(self, channels):
|
93
|
-
type_map = {
|
94
|
-
"acquire": pulse.AcquireChannel,
|
95
|
-
"drive": pulse.DriveChannel,
|
96
|
-
"measure": pulse.MeasureChannel,
|
97
|
-
"control": pulse.ControlChannel,
|
98
|
-
}
|
99
|
-
identifier_pattern = re.compile(r"\D+(?P<index>\d+)")
|
100
|
-
|
101
|
-
channels_map = {
|
102
|
-
"acquire": collections.defaultdict(list),
|
103
|
-
"drive": collections.defaultdict(list),
|
104
|
-
"measure": collections.defaultdict(list),
|
105
|
-
"control": collections.defaultdict(list),
|
106
|
-
}
|
107
|
-
for identifier, spec in channels.items():
|
108
|
-
channel_type = spec["type"]
|
109
|
-
out = re.match(identifier_pattern, identifier)
|
110
|
-
if out is None:
|
111
|
-
# Identifier is not a valid channel name format
|
112
|
-
continue
|
113
|
-
channel_index = int(out.groupdict()["index"])
|
114
|
-
qubit_index = tuple(spec["operates"]["qubits"])
|
115
|
-
chan_obj = type_map[channel_type](channel_index)
|
116
|
-
channels_map[channel_type][qubit_index].append(chan_obj)
|
117
|
-
setattr(self, "channels_map", channels_map)
|
118
|
-
|
119
|
-
def _setup_sim(self):
|
120
|
-
if _optionals.HAS_AER:
|
121
|
-
from qiskit_aer import AerSimulator
|
122
|
-
|
123
|
-
self.sim = AerSimulator()
|
124
|
-
if self.target and self._props_dict:
|
125
|
-
noise_model = self._get_noise_model_from_backend_v2()
|
126
|
-
self.sim.set_options(noise_model=noise_model)
|
127
|
-
# Update fake backend default too to avoid overwriting
|
128
|
-
# it when run() is called
|
129
|
-
self.set_options(noise_model=noise_model)
|
130
|
-
|
131
|
-
else:
|
132
|
-
self.sim = basic_provider.BasicSimulator()
|
133
|
-
|
134
|
-
def _get_conf_dict_from_json(self):
|
135
|
-
if not self.conf_filename:
|
136
|
-
return None
|
137
|
-
conf_dict = self._load_json(self.conf_filename)
|
138
|
-
decode_backend_configuration(conf_dict)
|
139
|
-
conf_dict["backend_name"] = self.backend_name
|
140
|
-
return conf_dict
|
141
|
-
|
142
|
-
def _set_props_dict_from_json(self):
|
143
|
-
if self.props_filename:
|
144
|
-
props_dict = self._load_json(self.props_filename)
|
145
|
-
decode_backend_properties(props_dict)
|
146
|
-
self._props_dict = props_dict
|
147
|
-
|
148
|
-
def _set_defs_dict_from_json(self):
|
149
|
-
if self.defs_filename:
|
150
|
-
defs_dict = self._load_json(self.defs_filename)
|
151
|
-
decode_pulse_defaults(defs_dict)
|
152
|
-
self._defs_dict = defs_dict
|
153
|
-
|
154
|
-
def _load_json(self, filename: str) -> dict:
|
155
|
-
with open(os.path.join(self.dirname, filename)) as f_json:
|
156
|
-
the_json = json.load(f_json)
|
157
|
-
return the_json
|
158
|
-
|
159
|
-
@property
|
160
|
-
def target(self) -> Target:
|
161
|
-
"""A :class:`qiskit.transpiler.Target` object for the backend.
|
162
|
-
|
163
|
-
:rtype: Target
|
164
|
-
"""
|
165
|
-
if self._target is None:
|
166
|
-
self._get_conf_dict_from_json()
|
167
|
-
if self._props_dict is None:
|
168
|
-
self._set_props_dict_from_json()
|
169
|
-
if self._defs_dict is None:
|
170
|
-
self._set_defs_dict_from_json()
|
171
|
-
conf = BackendConfiguration.from_dict(self._conf_dict)
|
172
|
-
props = None
|
173
|
-
if self._props_dict is not None:
|
174
|
-
props = BackendProperties.from_dict(self._props_dict)
|
175
|
-
defaults = None
|
176
|
-
if self._defs_dict is not None:
|
177
|
-
defaults = PulseDefaults.from_dict(self._defs_dict)
|
178
|
-
|
179
|
-
self._target = convert_to_target(
|
180
|
-
configuration=conf, properties=props, defaults=defaults
|
181
|
-
)
|
182
|
-
return self._target
|
183
|
-
|
184
|
-
@property
|
185
|
-
def max_circuits(self):
|
186
|
-
return None
|
187
|
-
|
188
|
-
@classmethod
|
189
|
-
def _default_options(cls):
|
190
|
-
"""Return the default options
|
191
|
-
|
192
|
-
This method will return a :class:`qiskit.providers.Options`
|
193
|
-
subclass object that will be used for the default options. These
|
194
|
-
should be the default parameters to use for the options of the
|
195
|
-
backend.
|
196
|
-
|
197
|
-
Returns:
|
198
|
-
qiskit.providers.Options: A options object with
|
199
|
-
default values set
|
200
|
-
"""
|
201
|
-
if _optionals.HAS_AER:
|
202
|
-
from qiskit_aer import AerSimulator
|
203
|
-
|
204
|
-
return AerSimulator._default_options()
|
205
|
-
else:
|
206
|
-
return basic_provider.BasicSimulator._default_options()
|
207
|
-
|
208
|
-
@property
|
209
|
-
def dtm(self) -> float:
|
210
|
-
"""Return the system time resolution of output signals
|
211
|
-
|
212
|
-
Returns:
|
213
|
-
The output signal timestep in seconds.
|
214
|
-
"""
|
215
|
-
dtm = self._conf_dict.get("dtm")
|
216
|
-
if dtm is not None:
|
217
|
-
# converting `dtm` in nanoseconds in configuration file to seconds
|
218
|
-
return dtm * 1e-9
|
219
|
-
else:
|
220
|
-
return None
|
221
|
-
|
222
|
-
@property
|
223
|
-
def meas_map(self) -> List[List[int]]:
|
224
|
-
"""Return the grouping of measurements which are multiplexed
|
225
|
-
This is required to be implemented if the backend supports Pulse
|
226
|
-
scheduling.
|
227
|
-
|
228
|
-
Returns:
|
229
|
-
The grouping of measurements which are multiplexed
|
230
|
-
"""
|
231
|
-
return self._conf_dict.get("meas_map")
|
232
|
-
|
233
|
-
def drive_channel(self, qubit: int):
|
234
|
-
"""Return the drive channel for the given qubit.
|
235
|
-
|
236
|
-
This is required to be implemented if the backend supports Pulse
|
237
|
-
scheduling.
|
238
|
-
|
239
|
-
Returns:
|
240
|
-
DriveChannel: The Qubit drive channel
|
241
|
-
"""
|
242
|
-
drive_channels_map = getattr(self, "channels_map", {}).get("drive", {})
|
243
|
-
qubits = (qubit,)
|
244
|
-
if qubits in drive_channels_map:
|
245
|
-
return drive_channels_map[qubits][0]
|
246
|
-
return None
|
247
|
-
|
248
|
-
def measure_channel(self, qubit: int):
|
249
|
-
"""Return the measure stimulus channel for the given qubit.
|
250
|
-
|
251
|
-
This is required to be implemented if the backend supports Pulse
|
252
|
-
scheduling.
|
253
|
-
|
254
|
-
Returns:
|
255
|
-
MeasureChannel: The Qubit measurement stimulus line
|
256
|
-
"""
|
257
|
-
measure_channels_map = getattr(self, "channels_map", {}).get("measure", {})
|
258
|
-
qubits = (qubit,)
|
259
|
-
if qubits in measure_channels_map:
|
260
|
-
return measure_channels_map[qubits][0]
|
261
|
-
return None
|
262
|
-
|
263
|
-
def acquire_channel(self, qubit: int):
|
264
|
-
"""Return the acquisition channel for the given qubit.
|
265
|
-
|
266
|
-
This is required to be implemented if the backend supports Pulse
|
267
|
-
scheduling.
|
268
|
-
|
269
|
-
Returns:
|
270
|
-
AcquireChannel: The Qubit measurement acquisition line.
|
271
|
-
"""
|
272
|
-
acquire_channels_map = getattr(self, "channels_map", {}).get("acquire", {})
|
273
|
-
qubits = (qubit,)
|
274
|
-
if qubits in acquire_channels_map:
|
275
|
-
return acquire_channels_map[qubits][0]
|
276
|
-
return None
|
277
|
-
|
278
|
-
def control_channel(self, qubits: Iterable[int]):
|
279
|
-
"""Return the secondary drive channel for the given qubit
|
280
|
-
|
281
|
-
This is typically utilized for controlling multiqubit interactions.
|
282
|
-
This channel is derived from other channels.
|
283
|
-
|
284
|
-
This is required to be implemented if the backend supports Pulse
|
285
|
-
scheduling.
|
286
|
-
|
287
|
-
Args:
|
288
|
-
qubits: Tuple or list of qubits of the form
|
289
|
-
``(control_qubit, target_qubit)``.
|
290
|
-
|
291
|
-
Returns:
|
292
|
-
List[ControlChannel]: The multi qubit control line.
|
293
|
-
"""
|
294
|
-
control_channels_map = getattr(self, "channels_map", {}).get("control", {})
|
295
|
-
qubits = tuple(qubits)
|
296
|
-
if qubits in control_channels_map:
|
297
|
-
return control_channels_map[qubits]
|
298
|
-
return []
|
299
|
-
|
300
|
-
def run(self, run_input, **options):
|
301
|
-
"""Run on the fake backend using a simulator.
|
302
|
-
|
303
|
-
This method runs circuit jobs (an individual or a list of QuantumCircuit
|
304
|
-
) and pulse jobs (an individual or a list of Schedule or ScheduleBlock)
|
305
|
-
using a :class:`.BasicSimulator` or Aer simulator and returns a
|
306
|
-
:class:`~qiskit.providers.Job` object.
|
307
|
-
|
308
|
-
If qiskit-aer is installed, jobs will be run using AerSimulator with
|
309
|
-
noise model of the fake backend. Otherwise, jobs will be run using
|
310
|
-
:class:`.BasicSimulator` without noise.
|
311
|
-
|
312
|
-
Currently noisy simulation of a pulse job is not supported yet in
|
313
|
-
FakeBackendV2.
|
314
|
-
|
315
|
-
Args:
|
316
|
-
run_input (QuantumCircuit or Schedule or ScheduleBlock or list): An
|
317
|
-
individual or a list of
|
318
|
-
:class:`~qiskit.circuit.QuantumCircuit`,
|
319
|
-
:class:`~qiskit.pulse.ScheduleBlock`, or
|
320
|
-
:class:`~qiskit.pulse.Schedule` objects to run on the backend.
|
321
|
-
options: Any kwarg options to pass to the backend for running the
|
322
|
-
config. If a key is also present in the options
|
323
|
-
attribute/object then the expectation is that the value
|
324
|
-
specified will be used instead of what's set in the options
|
325
|
-
object.
|
326
|
-
|
327
|
-
Returns:
|
328
|
-
Job: The job object for the run
|
329
|
-
|
330
|
-
Raises:
|
331
|
-
QiskitError: If a pulse job is supplied and qiskit-aer is not installed.
|
332
|
-
"""
|
333
|
-
circuits = run_input
|
334
|
-
pulse_job = None
|
335
|
-
if isinstance(circuits, (pulse.Schedule, pulse.ScheduleBlock)):
|
336
|
-
pulse_job = True
|
337
|
-
elif isinstance(circuits, circuit.QuantumCircuit):
|
338
|
-
pulse_job = False
|
339
|
-
elif isinstance(circuits, list):
|
340
|
-
if circuits:
|
341
|
-
if all(isinstance(x, (pulse.Schedule, pulse.ScheduleBlock)) for x in circuits):
|
342
|
-
pulse_job = True
|
343
|
-
elif all(isinstance(x, circuit.QuantumCircuit) for x in circuits):
|
344
|
-
pulse_job = False
|
345
|
-
if pulse_job is None: # submitted job is invalid
|
346
|
-
raise QiskitError(
|
347
|
-
"Invalid input object %s, must be either a "
|
348
|
-
"QuantumCircuit, Schedule, or a list of either" % circuits
|
349
|
-
)
|
350
|
-
if pulse_job: # pulse job
|
351
|
-
raise QiskitError("Pulse simulation is currently not supported for fake backends.")
|
352
|
-
# circuit job
|
353
|
-
if not _optionals.HAS_AER:
|
354
|
-
warnings.warn("Aer not found using BasicProvider and no noise", RuntimeWarning)
|
355
|
-
if self.sim is None:
|
356
|
-
self._setup_sim()
|
357
|
-
self.sim._options = self._options
|
358
|
-
job = self.sim.run(circuits, **options)
|
359
|
-
return job
|
360
|
-
|
361
|
-
def _get_noise_model_from_backend_v2(
|
362
|
-
self,
|
363
|
-
gate_error=True,
|
364
|
-
readout_error=True,
|
365
|
-
thermal_relaxation=True,
|
366
|
-
temperature=0,
|
367
|
-
gate_lengths=None,
|
368
|
-
gate_length_units="ns",
|
369
|
-
):
|
370
|
-
"""Build noise model from BackendV2.
|
371
|
-
|
372
|
-
This is a temporary fix until qiskit-aer supports building noise model
|
373
|
-
from a BackendV2 object.
|
374
|
-
"""
|
375
|
-
|
376
|
-
from qiskit.circuit import Delay
|
377
|
-
from qiskit.providers.exceptions import BackendPropertyError
|
378
|
-
from qiskit_aer.noise import NoiseModel
|
379
|
-
from qiskit_aer.noise.device.models import (
|
380
|
-
_excited_population,
|
381
|
-
basic_device_gate_errors,
|
382
|
-
basic_device_readout_errors,
|
383
|
-
)
|
384
|
-
from qiskit_aer.noise.passes import RelaxationNoisePass
|
385
|
-
|
386
|
-
if self._props_dict is None:
|
387
|
-
self._set_props_dict_from_json()
|
388
|
-
|
389
|
-
properties = BackendProperties.from_dict(self._props_dict)
|
390
|
-
basis_gates = self.operation_names
|
391
|
-
num_qubits = self.num_qubits
|
392
|
-
dt = self.dt
|
393
|
-
|
394
|
-
noise_model = NoiseModel(basis_gates=basis_gates)
|
395
|
-
|
396
|
-
# Add single-qubit readout errors
|
397
|
-
if readout_error:
|
398
|
-
for qubits, error in basic_device_readout_errors(properties):
|
399
|
-
noise_model.add_readout_error(error, qubits)
|
400
|
-
|
401
|
-
# Add gate errors
|
402
|
-
with warnings.catch_warnings():
|
403
|
-
warnings.filterwarnings(
|
404
|
-
"ignore",
|
405
|
-
module="qiskit_aer.noise.device.models",
|
406
|
-
)
|
407
|
-
gate_errors = basic_device_gate_errors(
|
408
|
-
properties,
|
409
|
-
gate_error=gate_error,
|
410
|
-
thermal_relaxation=thermal_relaxation,
|
411
|
-
gate_lengths=gate_lengths,
|
412
|
-
gate_length_units=gate_length_units,
|
413
|
-
temperature=temperature,
|
414
|
-
)
|
415
|
-
for name, qubits, error in gate_errors:
|
416
|
-
noise_model.add_quantum_error(error, name, qubits)
|
417
|
-
|
418
|
-
if thermal_relaxation:
|
419
|
-
# Add delay errors via RelaxationNiose pass
|
420
|
-
try:
|
421
|
-
excited_state_populations = [
|
422
|
-
_excited_population(freq=properties.frequency(q), temperature=temperature)
|
423
|
-
for q in range(num_qubits)
|
424
|
-
]
|
425
|
-
except BackendPropertyError:
|
426
|
-
excited_state_populations = None
|
427
|
-
try:
|
428
|
-
delay_pass = RelaxationNoisePass(
|
429
|
-
t1s=[properties.t1(q) for q in range(num_qubits)],
|
430
|
-
t2s=[properties.t2(q) for q in range(num_qubits)],
|
431
|
-
dt=dt,
|
432
|
-
op_types=Delay,
|
433
|
-
excited_state_populations=excited_state_populations,
|
434
|
-
)
|
435
|
-
noise_model._custom_noise_passes.append(delay_pass)
|
436
|
-
except BackendPropertyError:
|
437
|
-
# Device does not have the required T1 or T2 information
|
438
|
-
# in its properties
|
439
|
-
pass
|
440
|
-
|
441
|
-
return noise_model
|
442
|
-
|
443
|
-
|
444
39
|
class FakeBackend(BackendV1):
|
445
40
|
"""This is a dummy backend just for testing purposes."""
|
446
41
|
|
@@ -48,22 +48,22 @@ from qiskit.utils import optionals as _optionals
|
|
48
48
|
# if the defaults are ranges.
|
49
49
|
# - (duration, error), if the defaults are fixed values.
|
50
50
|
_NOISE_DEFAULTS = {
|
51
|
-
"cx": (
|
52
|
-
"ecr": (
|
53
|
-
"cz": (
|
54
|
-
"id": (
|
51
|
+
"cx": (7.992e-08, 8.99988e-07, 1e-5, 5e-3),
|
52
|
+
"ecr": (7.992e-08, 8.99988e-07, 1e-5, 5e-3),
|
53
|
+
"cz": (7.992e-08, 8.99988e-07, 1e-5, 5e-3),
|
54
|
+
"id": (2.997e-08, 5.994e-08, 9e-5, 1e-4),
|
55
55
|
"rz": (0.0, 0.0),
|
56
|
-
"sx": (
|
57
|
-
"x": (
|
58
|
-
"measure": (
|
56
|
+
"sx": (2.997e-08, 5.994e-08, 9e-5, 1e-4),
|
57
|
+
"x": (2.997e-08, 5.994e-08, 9e-5, 1e-4),
|
58
|
+
"measure": (6.99966e-07, 1.500054e-06, 1e-5, 5e-3),
|
59
59
|
"delay": (None, None),
|
60
60
|
"reset": (None, None),
|
61
61
|
}
|
62
62
|
|
63
63
|
# Fallback values for gates with unknown noise default ranges.
|
64
64
|
_NOISE_DEFAULTS_FALLBACK = {
|
65
|
-
"1-q": (
|
66
|
-
"multi-q": (
|
65
|
+
"1-q": (2.997e-08, 5.994e-08, 9e-5, 1e-4),
|
66
|
+
"multi-q": (7.992e-08, 8.99988e-07, 5e-3),
|
67
67
|
}
|
68
68
|
|
69
69
|
# Ranges to sample qubit properties from.
|
@@ -424,6 +424,12 @@ class GenericBackendV2(BackendV2):
|
|
424
424
|
)
|
425
425
|
else:
|
426
426
|
calibration_entry = None
|
427
|
+
if duration is not None and len(noise_params) > 2:
|
428
|
+
# Ensure exact conversion of duration from seconds to dt
|
429
|
+
dt = _QUBIT_PROPERTIES["dt"]
|
430
|
+
rounded_duration = round(duration / dt) * dt
|
431
|
+
# Clamp rounded duration to be between min and max values
|
432
|
+
duration = max(noise_params[0], min(rounded_duration, noise_params[1]))
|
427
433
|
props.update({qargs: InstructionProperties(duration, error, calibration_entry)})
|
428
434
|
self._target.add_instruction(instruction, props)
|
429
435
|
|
@@ -520,12 +526,18 @@ class GenericBackendV2(BackendV2):
|
|
520
526
|
|
521
527
|
@classmethod
|
522
528
|
def _default_options(cls) -> Options:
|
523
|
-
|
524
|
-
|
529
|
+
with warnings.catch_warnings(): # TODO remove catch once aer release without Provider ABC
|
530
|
+
warnings.filterwarnings(
|
531
|
+
"ignore",
|
532
|
+
category=DeprecationWarning,
|
533
|
+
message=".+abstract Provider and ProviderV1.+",
|
534
|
+
)
|
535
|
+
if _optionals.HAS_AER:
|
536
|
+
from qiskit_aer import AerSimulator
|
525
537
|
|
526
|
-
|
527
|
-
|
528
|
-
|
538
|
+
return AerSimulator._default_options()
|
539
|
+
else:
|
540
|
+
return BasicSimulator._default_options()
|
529
541
|
|
530
542
|
def drive_channel(self, qubit: int):
|
531
543
|
drive_channels_map = getattr(self, "channels_map", {}).get("drive", {})
|
qiskit/providers/provider.py
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
from abc import ABC, abstractmethod
|
16
16
|
|
17
17
|
from qiskit.providers.exceptions import QiskitBackendNotFoundError
|
18
|
+
from qiskit.utils import deprecate_func
|
18
19
|
|
19
20
|
|
20
21
|
class Provider:
|
@@ -28,12 +29,27 @@ class Provider:
|
|
28
29
|
|
29
30
|
version = 0
|
30
31
|
|
32
|
+
@deprecate_func(
|
33
|
+
since=1.1,
|
34
|
+
additional_msg="The abstract Provider and ProviderV1 classes are deprecated and will be "
|
35
|
+
"removed in 2.0. You can just remove it as the parent class and a `get_backend` "
|
36
|
+
"method that returns the backends from `self.backend`.",
|
37
|
+
)
|
38
|
+
def __init__(self):
|
39
|
+
pass
|
40
|
+
|
31
41
|
|
32
42
|
class ProviderV1(Provider, ABC):
|
33
43
|
"""Base class for a Backend Provider."""
|
34
44
|
|
35
45
|
version = 1
|
36
46
|
|
47
|
+
@deprecate_func(
|
48
|
+
since=1.1,
|
49
|
+
additional_msg="The abstract Provider and ProviderV1 classes are deprecated and will be "
|
50
|
+
"removed in 2.0. You can just remove it as the parent class and a `get_backend` "
|
51
|
+
"method that returns the backends from `self.backend`.",
|
52
|
+
)
|
37
53
|
def get_backend(self, name=None, **kwargs):
|
38
54
|
"""Return a single backend matching the specified filtering.
|
39
55
|
|
qiskit/pulse/builder.py
CHANGED
@@ -531,7 +531,10 @@ class _PulseBuilder:
|
|
531
531
|
self._context_stack.append(root_block)
|
532
532
|
|
533
533
|
# Set default alignment context
|
534
|
-
|
534
|
+
if isinstance(default_alignment, AlignmentKind): # AlignmentKind instance
|
535
|
+
alignment = default_alignment
|
536
|
+
else: # str identifier
|
537
|
+
alignment = _PulseBuilder.__alignment_kinds__.get(default_alignment, default_alignment)
|
535
538
|
if not isinstance(alignment, AlignmentKind):
|
536
539
|
raise exceptions.PulseError(
|
537
540
|
f"Given `default_alignment` {repr(default_alignment)} is "
|
@@ -52,8 +52,9 @@ and thus this parameter framework gives greater scalability to the pulse module.
|
|
52
52
|
"""
|
53
53
|
from __future__ import annotations
|
54
54
|
from copy import copy
|
55
|
-
from typing import Any
|
55
|
+
from typing import Any, Mapping, Sequence
|
56
56
|
|
57
|
+
from qiskit.circuit.parametervector import ParameterVector, ParameterVectorElement
|
57
58
|
from qiskit.circuit.parameter import Parameter
|
58
59
|
from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
|
59
60
|
from qiskit.pulse import instructions, channels
|
@@ -61,7 +62,11 @@ from qiskit.pulse.exceptions import PulseError
|
|
61
62
|
from qiskit.pulse.library import SymbolicPulse, Waveform
|
62
63
|
from qiskit.pulse.schedule import Schedule, ScheduleBlock
|
63
64
|
from qiskit.pulse.transforms.alignments import AlignmentKind
|
64
|
-
from qiskit.pulse.utils import
|
65
|
+
from qiskit.pulse.utils import (
|
66
|
+
format_parameter_value,
|
67
|
+
_validate_parameter_vector,
|
68
|
+
_validate_parameter_value,
|
69
|
+
)
|
65
70
|
|
66
71
|
|
67
72
|
class NodeVisitor:
|
@@ -360,7 +365,10 @@ class ParameterManager:
|
|
360
365
|
def assign_parameters(
|
361
366
|
self,
|
362
367
|
pulse_program: Any,
|
363
|
-
value_dict: dict[
|
368
|
+
value_dict: dict[
|
369
|
+
ParameterExpression | ParameterVector | str,
|
370
|
+
ParameterValueType | Sequence[ParameterValueType],
|
371
|
+
],
|
364
372
|
) -> Any:
|
365
373
|
"""Modify and return program data with parameters assigned according to the input.
|
366
374
|
|
@@ -372,7 +380,10 @@ class ParameterManager:
|
|
372
380
|
Returns:
|
373
381
|
Updated program data.
|
374
382
|
"""
|
375
|
-
|
383
|
+
unrolled_value_dict = self._unroll_param_dict(value_dict)
|
384
|
+
valid_map = {
|
385
|
+
k: unrolled_value_dict[k] for k in unrolled_value_dict.keys() & self._parameters
|
386
|
+
}
|
376
387
|
if valid_map:
|
377
388
|
visitor = ParameterSetter(param_map=valid_map)
|
378
389
|
return visitor.visit(pulse_program)
|
@@ -387,3 +398,48 @@ class ParameterManager:
|
|
387
398
|
visitor = ParameterGetter()
|
388
399
|
visitor.visit(new_node)
|
389
400
|
self._parameters |= visitor.parameters
|
401
|
+
|
402
|
+
def _unroll_param_dict(
|
403
|
+
self,
|
404
|
+
parameter_binds: Mapping[
|
405
|
+
Parameter | ParameterVector | str, ParameterValueType | Sequence[ParameterValueType]
|
406
|
+
],
|
407
|
+
) -> Mapping[Parameter, ParameterValueType]:
|
408
|
+
"""
|
409
|
+
Unroll parameter dictionary to a map from parameter to value.
|
410
|
+
|
411
|
+
Args:
|
412
|
+
parameter_binds: A dictionary from parameter to value or a list of values.
|
413
|
+
|
414
|
+
Returns:
|
415
|
+
A dictionary from parameter to value.
|
416
|
+
"""
|
417
|
+
out = {}
|
418
|
+
param_name_dict = {param.name: [] for param in self.parameters}
|
419
|
+
for param in self.parameters:
|
420
|
+
param_name_dict[param.name].append(param)
|
421
|
+
param_vec_dict = {
|
422
|
+
param.vector.name: param.vector
|
423
|
+
for param in self.parameters
|
424
|
+
if isinstance(param, ParameterVectorElement)
|
425
|
+
}
|
426
|
+
for name in param_vec_dict.keys():
|
427
|
+
if name in param_name_dict:
|
428
|
+
param_name_dict[name].append(param_vec_dict[name])
|
429
|
+
else:
|
430
|
+
param_name_dict[name] = [param_vec_dict[name]]
|
431
|
+
|
432
|
+
for parameter, value in parameter_binds.items():
|
433
|
+
if isinstance(parameter, ParameterVector):
|
434
|
+
_validate_parameter_vector(parameter, value)
|
435
|
+
out.update(zip(parameter, value))
|
436
|
+
elif isinstance(parameter, str):
|
437
|
+
for param in param_name_dict[parameter]:
|
438
|
+
is_vec = _validate_parameter_value(param, value)
|
439
|
+
if is_vec:
|
440
|
+
out.update(zip(param, value))
|
441
|
+
else:
|
442
|
+
out[param] = value
|
443
|
+
else:
|
444
|
+
out[parameter] = value
|
445
|
+
return out
|