Skip to content
Pasqal Documentation

Operations

Operations are common PrimitiveBlocks, these are often called gates elsewhere.

Bases: PrimitiveBlock

The X gate.

Source code in qadence/operations/primitive.py
35
36def __init__(self, target: int, noise: NoiseHandler | None = None) -> None:
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The Y gate.

Source code in qadence/operations/primitive.py
56
57def __init__(self, target: int, noise: NoiseHandler | None = None) -> None:
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The Z gate.

Source code in qadence/operations/primitive.py
77
78def __init__(self, target: int, noise: NoiseHandler | None = None) -> None:
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The identity gate.

Source code in qadence/operations/primitive.py
98
99def __init__(self, target: int, noise: NoiseHandler | None = None) -> None:
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The Hadamard or H gate.

Source code in qadence/operations/primitive.py
235
236
237
238
239
240
241def __init__(
self,
target: int,
noise: NoiseHandler | None = None,
) -> None:
self.generator = (1 / np.sqrt(2)) * (X(target) + Z(target) - np.sqrt(2) * I(target))
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The S / Phase gate.

Source code in qadence/operations/primitive.py
185
186
187
188
189
190
191def __init__(
self,
target: int,
noise: NoiseHandler | None = None,
) -> None:
self.generator = I(target) - Z(target)
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The Hermitian adjoint/conjugate transpose of the S / Phase gate.

Source code in qadence/operations/primitive.py
210
211
212
213
214
215
216def __init__(
self,
target: int,
noise: NoiseHandler | None = None,
) -> None:
self.generator = I(target) - Z(target)
super().__init__((target,), noise=noise)

Bases: PrimitiveBlock

The SWAP gate.

Source code in qadence/operations/primitive.py
356
357
358
359
360
361
362
363
364
365
366
367
368
369def __init__(
self,
control: int,
target: int,
noise: NoiseHandler | None = None,
) -> None:
a11 = 0.5 * (Z(control) - I(control))
a22 = -0.5 * (Z(target) + I(target))
a12 = 0.5 * (chain(X(control), Z(control)) + X(control))
a21 = 0.5 * (chain(Z(target), X(target)) + X(target))
self.generator = (
kron(-1.0 * a22, a11) + kron(-1.0 * a11, a22) + kron(a12, a21) + kron(a21, a12)
)
super().__init__((control, target), noise=noise)

Bases: PrimitiveBlock

The T gate.

Source code in qadence/operations/primitive.py
297
298
299
300
301
302
303def __init__(
self,
target: int,
noise: NoiseHandler | None = None,
) -> None:
self.generator = I(target) - Z(target)
super().__init__((target,), noise)

Bases: PrimitiveBlock

The Hermitian adjoint/conjugate transpose of the T gate.

Source code in qadence/operations/primitive.py
327
328
329
330
331
332
333def __init__(
self,
target: int,
noise: NoiseHandler | None = None,
) -> None:
self.generator = I(target) - Z(target)
super().__init__((target,), noise)

Bases: ControlBlock

The CNot, or CX, gate.

Source code in qadence/operations/control_ops.py
39
40
41def __init__(self, control: int, target: int, noise: NoiseHandler | None = None) -> None:
self.generator = kron(N(control), X(target) - I(target))
super().__init__((control,), X(target), noise=noise)

Bases: MCZ

The CZ gate.

Source code in qadence/operations/control_ops.py
99
100def __init__(self, control: int, target: int, noise: NoiseHandler | None = None) -> None:
super().__init__((control,), target, noise=noise)

CPHASE(control, target, parameter, noise=None)

Section titled “ CPHASE(control, target, parameter, noise=None) ”

Bases: MCPHASE

The CPHASE gate.

Source code in qadence/operations/control_ops.py
274
275
276
277
278
279
280
281def __init__(
self,
control: int,
target: int,
parameter: Parameter | TNumber | sympy.Expr | str,
noise: NoiseHandler | None = None,
):
super().__init__((control,), target, parameter, noise=noise)

Bases: ParametricBlock

The Rx gate.

Source code in qadence/operations/parametric.py
65
66
67
68
69
70
71
72
73
74
75
76def __init__(
self,
target: int,
parameter: Parameter | TParameter | ParamMap,
noise: NoiseHandler | None = None,
) -> None:
# TODO: should we give them more meaningful names? like 'angle'?
self.parameters = (
parameter if isinstance(parameter, ParamMap) else ParamMap(parameter=parameter)
)
self.generator = X(target)
super().__init__((target,), noise=noise)

Bases: ParametricBlock

The Ry gate.

Source code in qadence/operations/parametric.py
98
99
100
101
102
103
104
105
106
107
108def __init__(
self,
target: int,
parameter: Parameter | TParameter | ParamMap,
noise: NoiseHandler | None = None,
) -> None:
self.parameters = (
parameter if isinstance(parameter, ParamMap) else ParamMap(parameter=parameter)
)
self.generator = Y(target)
super().__init__((target,), noise=noise)

Bases: ParametricBlock

The Rz gate.

Source code in qadence/operations/parametric.py
130
131
132
133
134
135
136
137
138
139
140def __init__(
self,
target: int,
parameter: Parameter | TParameter | ParamMap,
noise: NoiseHandler | None = None,
) -> None:
self.parameters = (
parameter if isinstance(parameter, ParamMap) else ParamMap(parameter=parameter)
)
self.generator = Z(target)
super().__init__((target,), noise=noise)

CRX(control, target, parameter, noise=None)

Section titled “ CRX(control, target, parameter, noise=None) ”

Bases: MCRX

The CRX gate.

Source code in qadence/operations/control_ops.py
136
137
138
139
140
141
142
143def __init__(
self,
control: int,
target: int,
parameter: Parameter | TNumber | sympy.Expr | str,
noise: NoiseHandler | None = None,
):
super().__init__((control,), target, parameter, noise=noise)

CRY(control, target, parameter, noise=None)

Section titled “ CRY(control, target, parameter, noise=None) ”

Bases: MCRY

The CRY gate.

Source code in qadence/operations/control_ops.py
179
180
181
182def __init__(
self, control: int, target: int, parameter: TParameter, noise: NoiseHandler | None = None
):
super().__init__((control,), target, parameter, noise=noise)

CRZ(control, target, parameter, noise=None)

Section titled “ CRZ(control, target, parameter, noise=None) ”

Bases: MCRZ

The CRZ gate.

Source code in qadence/operations/control_ops.py
218
219
220
221
222
223
224
225def __init__(
self,
control: int,
target: int,
parameter: Parameter | TNumber | sympy.Expr | str,
noise: NoiseHandler | None = None,
):
super().__init__((control,), target, parameter, noise=noise)

Bases: ParametricBlock

The Parametric Phase / S gate.

Source code in qadence/operations/parametric.py
36
37
38
39
40
41
42
43
44def __init__(
self,
target: int,
parameter: Parameter | TNumber | sympy.Expr | str,
noise: NoiseHandler | None = None,
) -> None:
self.parameters = ParamMap(parameter=parameter)
self.generator = I(target) - Z(target)
super().__init__((target,), noise=noise)

HamEvo(generator, parameter, qubit_support=None, duration=None, noise_operators=list())

Section titled “ HamEvo(generator, parameter, qubit_support=None, duration=None, noise_operators=list()) ”

Bases: TimeEvolutionBlock

The Hamiltonian evolution operator U(t).

For time-independent Hamiltonians the solution is exact:

U(t) = exp(-iGt)

where G represents an Hermitian generator, or Hamiltonian and t represents the time parameter. For time-dependent Hamiltonians, the solution is obtained by numerical integration of the Schrodinger equation.

PARAMETER DESCRIPTION
generator

Hamiltonian generator, either symbolic as an AbstractBlock, or as a torch.Tensor or numpy.ndarray.

TYPE: Union[TGenerator, AbstractBlock]

parameter

The time parameter for evolution operator. For the time-independent case, it represents the actual value for which the evolution will be evaluated. For the time-dependent case, it should be an instance of TimeParameter to signal the solver the variable that will be integrated over.

TYPE: TParameter

qubit_support

The qubits on which the evolution will be performed on. Only required for generators that are not a composition of blocks.

TYPE: tuple[int, ...] DEFAULT: None

duration

(optional) duration of the evolution in case of time-dependent generator. By default, a FeatureParameter with tag "duration" will be initialized, and the value will then be required in the values dict.

TYPE: TParameter | None DEFAULT: None

noise_operators

(optional) the list of jump operators to use when using a shrodinger solver, allowing to perform noisy simulations.

TYPE: list[AbstractBlock] DEFAULT: list()

Examples:

from qadence import X, HamEvo, PI, add, run
from qadence import FeatureParameter, TimeParameter
import torch
n_qubits = 3
# Hamiltonian as a block composition
hamiltonian = add(X(i) for i in range(n_qubits))
hevo = HamEvo(hamiltonian, parameter=torch.rand(2))
state = run(hevo)
# Hamiltonian as a random matrix
hamiltonian = torch.rand(2, 2, dtype=torch.complex128)
hevo = HamEvo(hamiltonian, parameter=torch.rand(2), qubit_support=(0,))
state = run(hevo)
# Time-dependent Hamiltonian
t = TimeParameter("t")
hamiltonian = t * add(X(i) for i in range(n_qubits))
hevo = HamEvo(hamiltonian, parameter=t)
state = run(hevo, values = {"duration": torch.tensor(1.0)})
# Adding noise operators
noise_ops = [X(0)]
hevo = HamEvo(hamiltonian, parameter=t, noise_operators=noise_ops)
Source code in qadence/operations/ham_evo.py
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170def __init__(
self,
generator: Union[TGenerator, AbstractBlock],
parameter: TParameter,
qubit_support: tuple[int, ...] = None,
duration: TParameter | None = None,
noise_operators: list[AbstractBlock] = list(),
):
params = {}
if qubit_support is None and not isinstance(generator, AbstractBlock):
raise ValueError("You have to supply a qubit support for non-block generators.")
super().__init__(qubit_support if qubit_support else generator.qubit_support)
if isinstance(generator, AbstractBlock):
qubit_support = generator.qubit_support
if generator.is_parametric:
params = {str(e): e for e in expressions(generator)}
if generator.is_time_dependent:
if isinstance(duration, str):
duration = Parameter(duration, trainable=False)
elif duration is None:
duration = Parameter("duration", trainable=False)
if not generator.is_time_dependent and duration is not None:
raise TypeError(
"Duration argument is only supported for time-dependent generators."
)
elif isinstance(generator, torch.Tensor):
if duration is not None:
raise TypeError(
"Duration argument is only supported for time-dependent generators."
)
msg = "Please provide a square generator."
if len(generator.shape) == 2:
assert generator.shape[0] == generator.shape[1], msg
elif len(generator.shape) == 3:
assert generator.shape[1] == generator.shape[2], msg
assert generator.shape[0] == 1, "Qadence doesnt support batched generators."
else:
raise TypeError(
"Only 2D or 3D generators are supported.\
In case of a 3D generator, the batch dim\
is expected to be at dim 0."
)
params = {str(generator.__hash__()): generator}
elif isinstance(generator, (sympy.Basic, sympy.Array)):
if duration is not None:
raise TypeError(
"Duration argument is only supported for time-dependent generators."
)
params = {str(generator): generator}
else:
raise TypeError(
f"Generator of type {type(generator)} not supported.\
If you're using a numpy.ndarray, please cast it to a torch tensor."
)
if duration is not None:
params = {"duration": Parameter(duration), **params}
params = {"parameter": Parameter(parameter), **params}
self.parameters = ParamMap(**params)
self.time_param = parameter
self.generator = generator
self.duration = duration
if len(noise_operators) > 0:
if not all(
[
len(set(op.qubit_support + self.qubit_support) - set(self.qubit_support)) == 0
for op in noise_operators
]
):
raise ValueError(
"Noise operators should be defined"
" over the same or a subset of the qubit support"
)
if True in [op.is_parametric for op in noise_operators]:
raise ValueError("Parametric operators are not supported")
self.noise_operators = noise_operators

digital_decomposition(approximation=LTSOrder.ST4)

Section titled “ digital_decomposition(approximation=LTSOrder.ST4) ”

Decompose the Hamiltonian evolution into digital gates.

PARAMETER DESCRIPTION
approximation

Choose the type of decomposition. Defaults to "st4". Available types are: * 'basic' = apply first-order Trotter formula and decompose each term of the exponential into digital gates. It is exact only if applied to an operator whose terms are mutually commuting. * 'st2' = Trotter-Suzuki 2nd order formula for approximating non-commuting Hamiltonians. * 'st4' = Trotter-Suzuki 4th order formula for approximating non-commuting Hamiltonians.

TYPE: str DEFAULT: ST4

RETURNS DESCRIPTION
AbstractBlock

a block with the digital decomposition

TYPE: AbstractBlock

Source code in qadence/operations/ham_evo.py
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268def digital_decomposition(self, approximation: LTSOrder = LTSOrder.ST4) -> AbstractBlock:
"""Decompose the Hamiltonian evolution into digital gates.
Args:
approximation (str, optional): Choose the type of decomposition. Defaults to "st4".
Available types are:
* 'basic' = apply first-order Trotter formula and decompose each term of
the exponential into digital gates. It is exact only if applied to an
operator whose terms are mutually commuting.
* 'st2' = Trotter-Suzuki 2nd order formula for approximating non-commuting
Hamiltonians.
* 'st4' = Trotter-Suzuki 4th order formula for approximating non-commuting
Hamiltonians.
Returns:
AbstractBlock: a block with the digital decomposition
"""
# psi(t) = exp(-i * H * t * psi0)
# psi(t) = exp(-i * lambda * t * psi0)
# H = sum(Paulin) + sum(Pauli1*Pauli2)
logger.info("Quantum simulation of the time-independent Schrödinger equation.")
blocks = []
# how to change the type/dict to enum effectively
# when there is a term including non-commuting matrices use st2 or st4
# 1) should check that the given generator respects the constraints
# single-qubit gates
assert isinstance(
self.generator, AbstractBlock
), "Only a generator represented as a block can be decomposed"
if block_is_qubit_hamiltonian(self.generator):
try:
block_is_commuting_hamiltonian(self.generator)
approximation = LTSOrder.BASIC # use the simpler approach if the H is commuting
except TypeError:
logger.warning(
"""Non-commuting terms in the Pauli operator.
The Suzuki-Trotter approximation is applied."""
)
blocks.extend(
lie_trotter_suzuki(
block=self.generator,
parameter=self.parameters.parameter,
order=LTSOrder[approximation],
)
)
# 2) return an AbstractBlock instance with the set of gates
# resulting from the decomposition
return chain(*blocks)
else:
raise NotImplementedError(
"The current digital decomposition can be applied only to Pauli Hamiltonians."
)

AnalogSWAP(control, target, parameter=3 * PI / 4)

Section titled “ AnalogSWAP(control, target, parameter=3 * PI / 4) ”

Bases: HamEvo

Single time-independent Hamiltonian evolution over a Rydberg Ising.

hamiltonian yielding a SWAP (up to global phase).

Derived from Bapat et al. (external) where it is applied to XX-type Hamiltonian

Source code in qadence/operations/analog.py
48
49
50
51
52
53
54
55
56def __init__(self, control: int, target: int, parameter: TParameter = 3 * PI / 4):
rydberg_ising_hamiltonian_generator = (
4.0 * kron((I(control) - Z(control)) / 2.0, (I(target) - Z(target)) / 2.0)
+ (2.0 / 3.0) * np.sqrt(2.0) * X(control)
+ (2.0 / 3.0) * np.sqrt(2.0) * X(target)
+ (1.0 + np.sqrt(5.0) / 3) * Z(control)
+ (1.0 + np.sqrt(5.0) / 3) * Z(target)
)
super().__init__(rydberg_ising_hamiltonian_generator, parameter, (control, target))

AnalogRX(angle, qubit_support='global', add_pattern=True)

Section titled “ AnalogRX(angle, qubit_support='global', add_pattern=True) ”

Analog X rotation.

Shorthand for AnalogRot:

φ=2.4; Ω=π; t = φ/Ω * 1000
AnalogRot(duration=t, omega=Ω)
PARAMETER DESCRIPTION
angle

Rotation angle [rad]

TYPE: float | str | Parameter

qubit_support

Defines the (local/global) qubit support

TYPE: str | QubitSupport | Tuple DEFAULT: 'global'

RETURNS DESCRIPTION
ConstantAnalogRotation

ConstantAnalogRotation

Source code in qadence/operations/analog.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196def AnalogRX(
angle: float | str | Parameter,
qubit_support: str | QubitSupport | Tuple = "global",
add_pattern: bool = True,
) -> ConstantAnalogRotation:
"""Analog X rotation.
Shorthand for [`AnalogRot`][qadence.operations.AnalogRot]:
```python
φ=2.4; Ω=π; t = φ/Ω * 1000
AnalogRot(duration=t, omega=Ω)
```
Arguments:
angle: Rotation angle [rad]
qubit_support: Defines the (local/global) qubit support
Returns:
ConstantAnalogRotation
"""
return _analog_rot(angle, qubit_support, phase=0, add_pattern=add_pattern)

AnalogRY(angle, qubit_support='global', add_pattern=True)

Section titled “ AnalogRY(angle, qubit_support='global', add_pattern=True) ”

Analog Y rotation.

Shorthand for AnalogRot:

φ=2.4; Ω=π; t = φ/Ω * 1000
AnalogRot(duration=t, omega=Ω, phase=-π/2)
Arguments: angle: Rotation angle [rad] qubit_support: Defines the (local/global) qubit support
RETURNS DESCRIPTION
ConstantAnalogRotation

ConstantAnalogRotation

Source code in qadence/operations/analog.py
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219def AnalogRY(
angle: float | str | Parameter,
qubit_support: str | QubitSupport | Tuple = "global",
add_pattern: bool = True,
) -> ConstantAnalogRotation:
"""Analog Y rotation.
Shorthand for [`AnalogRot`][qadence.operations.AnalogRot]:
```python
φ=2.4; Ω=π; t = φ/Ω * 1000
AnalogRot(duration=t, omega=Ω, phase=-π/2)
```
Arguments:
angle: Rotation angle [rad]
qubit_support: Defines the (local/global) qubit support
Returns:
ConstantAnalogRotation
"""
return _analog_rot(angle, qubit_support, phase=-PI / 2, add_pattern=add_pattern)

AnalogRZ(angle, qubit_support='global', add_pattern=True)

Section titled “ AnalogRZ(angle, qubit_support='global', add_pattern=True) ”

Analog Z rotation. Shorthand for AnalogRot:

φ=2.4; δ=π; t = φ/δ * 100)
AnalogRot(duration=t, delta=δ, phase=π/2)
Source code in qadence/operations/analog.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242def AnalogRZ(
angle: float | str | Parameter,
qubit_support: str | QubitSupport | Tuple = "global",
add_pattern: bool = True,
) -> ConstantAnalogRotation:
"""Analog Z rotation. Shorthand for [`AnalogRot`][qadence.operations.AnalogRot]:
```
φ=2.4; δ=π; t = φ/δ * 100)
AnalogRot(duration=t, delta=δ, phase=π/2)
```
"""
q = _cast(QubitSupport, qubit_support)
alpha = _cast(Parameter, angle)
delta = PI
omega = 0
duration = alpha / delta * 1000
h_norm = sympy.sqrt(omega**2 + delta**2)
ps = ParamMap(
alpha=alpha, duration=duration, omega=omega, delta=delta, phase=0.0, h_norm=h_norm
)
return ConstantAnalogRotation(qubit_support=q, parameters=ps, add_pattern=add_pattern)

AnalogRot(duration, omega=0, delta=0, phase=0, qubit_support='global', add_pattern=True)

Section titled “ AnalogRot(duration, omega=0, delta=0, phase=0, qubit_support='global', add_pattern=True) ”

General analog rotation operation.

PARAMETER DESCRIPTION
duration

Duration of the rotation [ns].

TYPE: float | str | Parameter

omega

Rotation frequency [rad/μs]

TYPE: float | str | Parameter DEFAULT: 0

delta

Rotation frequency [rad/μs]

TYPE: float | str | Parameter DEFAULT: 0

phase

Phase angle [rad]

TYPE: float | str | Parameter DEFAULT: 0

qubit_support

Defines the (local/global) qubit support

TYPE: str | QubitSupport | Tuple DEFAULT: 'global'

add_pattern

False disables the semi-local addressing pattern for the execution of this specific block.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
ConstantAnalogRotation

ConstantAnalogRotation

Source code in qadence/operations/analog.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147def AnalogRot(
duration: float | str | Parameter,
omega: float | str | Parameter = 0,
delta: float | str | Parameter = 0,
phase: float | str | Parameter = 0,
qubit_support: str | QubitSupport | Tuple = "global",
add_pattern: bool = True,
) -> ConstantAnalogRotation:
"""General analog rotation operation.
Arguments:
duration: Duration of the rotation [ns].
omega: Rotation frequency [rad/μs]
delta: Rotation frequency [rad/μs]
phase: Phase angle [rad]
qubit_support: Defines the (local/global) qubit support
add_pattern: False disables the semi-local addressing pattern
for the execution of this specific block.
Returns:
ConstantAnalogRotation
"""
if omega == 0 and delta == 0:
raise ValueError("Parameters omega and delta cannot both be 0.")
q = _cast(QubitSupport, qubit_support)
duration = Parameter(duration)
omega = Parameter(omega)
delta = Parameter(delta)
phase = Parameter(phase)
h_norm = sympy.sqrt(omega**2 + delta**2)
alpha = duration * h_norm / 1000
ps = ParamMap(
alpha=alpha, duration=duration, omega=omega, delta=delta, phase=phase, h_norm=h_norm
)
return ConstantAnalogRotation(parameters=ps, qubit_support=q, add_pattern=add_pattern)

AnalogInteraction(duration, qubit_support='global', add_pattern=True)

Section titled “ AnalogInteraction(duration, qubit_support='global', add_pattern=True) ”

Evolution of the interaction term for a register of qubits.

Constructs a InteractionBlock.

PARAMETER DESCRIPTION
duration

Time to evolve the interaction for in nanoseconds.

TYPE: TNumber | Basic

qubit_support

Qubits the InteractionBlock is applied to. Can be either "global" to evolve the interaction block to all qubits or a tuple of integers.

TYPE: str | QubitSupport | tuple DEFAULT: 'global'

add_pattern

False disables the semi-local addressing pattern for the execution of this specific block.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
InteractionBlock

a InteractionBlock

Source code in qadence/operations/analog.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84def AnalogInteraction(
duration: TNumber | sympy.Basic,
qubit_support: str | QubitSupport | tuple = "global",
add_pattern: bool = True,
) -> InteractionBlock:
"""Evolution of the interaction term for a register of qubits.
Constructs a [`InteractionBlock`][qadence.blocks.analog.InteractionBlock].
Arguments:
duration: Time to evolve the interaction for in nanoseconds.
qubit_support: Qubits the `InteractionBlock` is applied to. Can be either
`"global"` to evolve the interaction block to all qubits or a tuple of integers.
add_pattern: False disables the semi-local addressing pattern
for the execution of this specific block.
Returns:
a `InteractionBlock`
"""
q = _cast(QubitSupport, qubit_support)
ps = ParamMap(duration=duration)
return InteractionBlock(parameters=ps, qubit_support=q, add_pattern=add_pattern)