Qx.Operations (Qx - Quantum Computing Simulator v0.8.0)
View SourceQuantum gate operations for quantum circuits.
This module provides functions for applying quantum gates to quantum circuits,
including single-qubit gates (H, X, Y, Z, S, S†, T, Rx, Ry, Rz, phase, U),
basis-explicit measurement (measure_x/3, measure_y/3, measure_z/3),
two-qubit gates (CNOT, CY, CZ, CP, CRx, CRy, CRz, SWAP, iSWAP), and
three-qubit gates (CCNOT/Toffoli, CSWAP/Fredkin).
For composite "apply to every qubit" / "CNOT chain" patterns, see
Qx.Patterns.
Summary
Functions
Adds a barrier to the circuit for visualization purposes.
Applies gates conditionally based on a classical bit value.
Applies a controlled-controlled-X (CCNOT/Toffoli) gate.
Applies a controlled-phase (CP) gate.
Applies a controlled rotation about the X-axis (CRx) gate.
Applies a controlled rotation about the Y-axis (CRy) gate.
Applies a controlled rotation about the Z-axis (CRz) gate.
Applies a Fredkin (controlled-SWAP) gate.
Applies a controlled-X (CNOT) gate.
Applies a controlled-Y (CY) gate.
Applies a controlled-Z (CZ) gate.
Applies a Hadamard gate to the specified qubit.
Applies an iSWAP gate, exchanging qubit states while applying an i phase factor to the swapped components.
Adds a measurement operation to the circuit.
Performs an X-basis measurement of qubit, storing the outcome in
classical_bit (0 ↔ |+⟩, 1 ↔ |−⟩).
Performs a Y-basis measurement of qubit, storing the outcome in
classical_bit (0 ↔ |+i⟩, 1 ↔ |−i⟩).
Performs a Z-basis (computational basis) measurement of qubit, storing
the outcome in classical_bit.
Applies a phase gate with the specified phase.
Applies a rotation around the X-axis by the specified angle.
Applies a rotation around the Y-axis by the specified angle.
Applies a rotation around the Z-axis by the specified angle.
Applies an S gate (phase gate with π/2 phase).
Applies an S† (S-dagger) gate (-π/2 phase on |1⟩).
Applies a SWAP gate, exchanging the quantum states of two qubits.
Applies a T gate (phase gate with π/4 phase).
Inspects the circuit without breaking the pipeline.
Inspects measurement probabilities without breaking the pipeline.
Inspects the current quantum state without breaking the pipeline.
Applies the general single-qubit unitary gate U(θ,φ,λ).
Applies a Pauli-X gate (bit flip) to the specified qubit.
Applies a Pauli-Y gate to the specified qubit.
Applies a Pauli-Z gate (phase flip) to the specified qubit.
Functions
Adds a barrier to the circuit for visualization purposes.
Barriers are used to group operations and improve circuit readability. They do not affect the quantum state.
Parameters
circuit- The quantum circuitqubits- List of qubit indices the barrier spans
Examples
iex> qc = Qx.QuantumCircuit.new(3, 0)
iex> qc = Qx.Operations.barrier(qc, [0, 1, 2])
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:barrier, [0, 1, 2]}
Applies gates conditionally based on a classical bit value.
The conditional block executes during simulation only if the specified classical bit equals the given value at runtime.
Parameters
circuit- The quantum circuitclassical_bit- Classical bit index to check (0-based)value- Value to compare (0 or 1)gate_fn- Function that applies gates: (circuit -> circuit)
Examples
iex> qc = Qx.QuantumCircuit.new(2, 2)
iex> qc = qc |> Qx.Operations.h(0) |> Qx.Operations.measure(0, 0)
iex> qc = Qx.Operations.c_if(qc, 0, 1, fn c -> Qx.Operations.x(c, 1) end)
iex> instructions = Qx.QuantumCircuit.get_instructions(qc)
iex> length(instructions)
2Constraints
- Classical bit must be valid for the circuit
- Value must be 0 or 1
- Gates in conditional block cannot contain measurements
- No nesting of conditional blocks
Applies a controlled-controlled-X (CCNOT/Toffoli) gate.
The CCNOT gate flips the target qubit if and only if both control qubits are |1⟩.
Parameters
circuit- The quantum circuitcontrol1- First control qubit indexcontrol2- Second control qubit indextarget- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(3, 0)
iex> qc = Qx.Operations.ccx(qc, 0, 1, 2)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:ccx, [0, 1, 2]}
Applies a controlled-phase (CP) gate.
The CP gate applies a phase of e^(i*theta) to the |11⟩ basis state only. All other basis states are unchanged.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit indextheta- Phase angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.cp(qc, 0, 1, :math.pi())
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:cp, [0, 1]}Raises
Qx.QubitIndexError- If qubit indices are out of range or equalArgumentError- If theta is not a number
Applies a controlled rotation about the X-axis (CRx) gate.
Applies Rx(theta) to the target qubit if and only if the control qubit
is |1⟩. Maps directly to QAAL CRx(α) q, t and OpenQASM 3 crx(θ) q[c], q[t];.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.crx(qc, 0, 1, :math.pi() / 2)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:crx, [0, 1], 1}Raises
Qx.QubitIndexError- If qubit indices are out of range or equalArgumentError- Ifthetais not a number
Applies a controlled rotation about the Y-axis (CRy) gate.
Applies Ry(theta) to the target qubit if and only if the control qubit
is |1⟩. Maps directly to QAAL CRy(α) q, t and OpenQASM 3 cry(θ) q[c], q[t];.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.cry(qc, 0, 1, :math.pi() / 2)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:cry, [0, 1], 1}Raises
Qx.QubitIndexError- If qubit indices are out of range or equalArgumentError- Ifthetais not a number
Applies a controlled rotation about the Z-axis (CRz) gate.
Applies Rz(theta) to the target qubit if and only if the control qubit
is |1⟩. Maps directly to QAAL CRz(α) q, t and OpenQASM 3 crz(θ) q[c], q[t];.
Note that Qx.Operations.cp/4 (controlled-phase) is a closely-related
gate that differs from crz/4 by a global phase on the controlled
subspace — they are not interchangeable for arbitrary theta.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.crz(qc, 0, 1, :math.pi() / 2)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:crz, [0, 1], 1}Raises
Qx.QubitIndexError- If qubit indices are out of range or equalArgumentError- Ifthetais not a number
Applies a Fredkin (controlled-SWAP) gate.
Swaps the quantum states of target_a and target_b when the control qubit is |1⟩.
When the control qubit is |0⟩, the targets are left unchanged.
Parameters
circuit- The quantum circuitcontrol- Control qubit indextarget_a- First target qubit indextarget_b- Second target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(3, 0)
iex> qc = Qx.Operations.cswap(qc, 0, 1, 2)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:cswap, [0, 1, 2]}Raises
Qx.QubitIndexError- If any two qubit indices are equal or any index is out of range
Applies a controlled-X (CNOT) gate.
The CNOT gate flips the target qubit if and only if the control qubit is |1⟩.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.cx(qc, 0, 1)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:cx, [0, 1]}
Applies a controlled-Y (CY) gate.
The CY gate applies a Pauli-Y operation to the target qubit if and only if
the control qubit is |1⟩. Maps directly to QAAL CY q, t and OpenQASM 3
cy q[c], q[t];.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.cy(qc, 0, 1)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:cy, [0, 1]}Raises
Qx.QubitIndexError- If qubit indices are out of range or equal
Applies a controlled-Z (CZ) gate.
The CZ gate applies a phase of -1 if and only if both qubits are |1⟩.
Parameters
circuit- The quantum circuitcontrol_qubit- Control qubit indextarget_qubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.cz(qc, 0, 1)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:cz, [0, 1]}
Applies a Hadamard gate to the specified qubit.
The Hadamard gate creates superposition, transforming |0⟩ to (|0⟩ + |1⟩)/√2 and |1⟩ to (|0⟩ - |1⟩)/√2.
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.h(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:h, [0]}
Applies an iSWAP gate, exchanging qubit states while applying an i phase factor to the swapped components.
Parameters
circuit- The quantum circuitqubit_a- Index of the first qubitqubit_b- Index of the second qubit
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.iswap(qc, 0, 1)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:iswap, [0, 1]}Raises
Qx.QubitIndexError- If qubit indices are out of range or equal
Adds a measurement operation to the circuit.
Parameters
circuit- The quantum circuitqubit- Qubit index to measureclassical_bit- Classical bit index to store the result
Examples
iex> qc = Qx.QuantumCircuit.new(2, 2)
iex> qc = Qx.Operations.measure(qc, 0, 0)
iex> [{qubit, classical_bit}] = Qx.QuantumCircuit.get_measurements(qc)
iex> {qubit, classical_bit}
{0, 0}
Performs an X-basis measurement of qubit, storing the outcome in
classical_bit (0 ↔ |+⟩, 1 ↔ |−⟩).
Lowers to H q ; Mz q -> r. The classical outcome matches QAAL
Mx q -> r, but note Qx's simulator samples in the computational
basis at end-of-circuit, so the post-measurement quantum state stays
Z-basis-aligned (i.e. |0⟩ if the classical outcome was 0, |1⟩
if 1) — it is not rotated back into the X-basis eigenstate. For
algorithmic transcription of QAAL programs this is observationally
indistinguishable as long as q is not used after the X-basis
measurement (the common case).
Parameters
circuit- The quantum circuitqubit- Qubit index to measureclassical_bit- Classical bit index to store the result
Examples
iex> qc = Qx.QuantumCircuit.new(1, 1) |> Qx.Operations.measure_x(0, 0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
2Raises
Qx.QubitIndexError- If qubit index is out of rangeQx.ClassicalBitError- If classical bit index is out of range
Performs a Y-basis measurement of qubit, storing the outcome in
classical_bit (0 ↔ |+i⟩, 1 ↔ |−i⟩).
Lowers to Sdg q ; H q ; Mz q -> r. Same deferred-sample caveat as
measure_x/3: the post-measurement state is |0⟩/|1⟩ aligned, not
rotated back into the Y-basis eigenstate. The classical outcome is
what QAAL My q -> r produces.
Parameters
circuit- The quantum circuitqubit- Qubit index to measureclassical_bit- Classical bit index to store the result
Examples
iex> qc = Qx.QuantumCircuit.new(1, 1) |> Qx.Operations.measure_y(0, 0)
iex> length(Qx.QuantumCircuit.get_instructions(qc))
3Raises
Qx.QubitIndexError- If qubit index is out of rangeQx.ClassicalBitError- If classical bit index is out of range
Performs a Z-basis (computational basis) measurement of qubit, storing
the outcome in classical_bit.
This is an alias of measure/3 provided for symmetry with measure_x/3
and measure_y/3. Maps directly to QAAL Mz q -> r.
Examples
iex> qc = Qx.QuantumCircuit.new(1, 1) |> Qx.Operations.measure_z(0, 0)
iex> Qx.QuantumCircuit.get_measurements(qc)
[{0, 0}]
Applies a phase gate with the specified phase.
Parameters
circuit- The quantum circuitqubit- Target qubit indexphi- Phase angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.phase(qc, 0, :math.pi/4)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:phase, [0], 1}
Applies a rotation around the X-axis by the specified angle.
Parameters
circuit- The quantum circuitqubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.rx(qc, 0, :math.pi/2)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:rx, [0], 1}
Applies a rotation around the Y-axis by the specified angle.
Parameters
circuit- The quantum circuitqubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.ry(qc, 0, :math.pi/2)
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:ry, [0], 1}
Applies a rotation around the Z-axis by the specified angle.
Parameters
circuit- The quantum circuitqubit- Target qubit indextheta- Rotation angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0) iex> qc = Qx.Operations.rz(qc, 0, :math.pi/2) iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc) iex> {gate, qubits, length(params)}
Applies an S gate (phase gate with π/2 phase).
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.s(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:s, [0]}
Applies an S† (S-dagger) gate (-π/2 phase on |1⟩).
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.sdg(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:sdg, [0]}
Applies a SWAP gate, exchanging the quantum states of two qubits.
Parameters
circuit- The quantum circuitqubit_a- Index of the first qubitqubit_b- Index of the second qubit
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.swap(qc, 0, 1)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:swap, [0, 1]}Raises
Qx.QubitIndexError- If qubit indices are out of range or equal
Applies a T gate (phase gate with π/4 phase).
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.t(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:t, [0]}
@spec tap_circuit(Qx.QuantumCircuit.t(), (Qx.QuantumCircuit.t() -> any())) :: Qx.QuantumCircuit.t()
Inspects the circuit without breaking the pipeline.
The provided function receives the circuit and can perform any side-effect (logging, printing, assertions), but the return value is ignored and the original circuit is returned.
Parameters
circuit- The quantum circuitfun- Function to execute:(circuit -> any())
Examples
iex> circuit = Qx.QuantumCircuit.new(2, 0)
...> |> Qx.Operations.h(0)
...> |> Qx.Operations.tap_circuit(&IO.inspect(&1.instructions, label: "After H"))
...> |> Qx.Operations.cx(0, 1)
After H: [{:h, [0], []}]
%Qx.QuantumCircuit{...}
# Create circuit and inspect depth/qubits
circuit = Qx.QuantumCircuit.new(3, 0)
|> Qx.Operations.h(0)
|> Qx.Operations.tap_circuit(fn circ ->
IO.puts("Depth: #{Qx.QuantumCircuit.depth(circ)}")
IO.puts("Qubits: #{circ.num_qubits}")
end)
|> Qx.Operations.x(1)
# Outputs:
# Depth: 1
# Qubits: 3See Also
tap_state/2- Inspect quantum statetap_probabilities/2- Inspect measurement probabilities
@spec tap_probabilities(Qx.QuantumCircuit.t(), (Nx.Tensor.t() -> any())) :: Qx.QuantumCircuit.t()
Inspects measurement probabilities without breaking the pipeline.
Convenience function that computes probabilities and passes them to your inspection function.
Parameters
circuit- The quantum circuitfun- Function to execute:(Nx.Tensor.t() -> any())
Examples
iex> circuit = Qx.QuantumCircuit.new(2, 2)
...> |> Qx.Operations.h(0)
...> |> Qx.Operations.cx(0, 1)
...> |> Qx.Operations.tap_probabilities(&IO.inspect/1)
...> |> Qx.Operations.measure(0, 0)
#Nx.Tensor<
f32[4]
[0.5, 0.0, 0.0, 0.5]
>
%Qx.QuantumCircuit{...}
# Create circuit and inspect probabilities
circuit = Qx.QuantumCircuit.new(1, 0)
|> Qx.Operations.h(0)
|> Qx.Operations.tap_probabilities(fn probs ->
prob_list = Nx.to_list(probs)
IO.puts("P(|0⟩) = #{Enum.at(prob_list, 0)}")
IO.puts("P(|1⟩) = #{Enum.at(prob_list, 1)}")
end)
# Outputs:
# P(|0⟩) = 0.5
# P(|1⟩) = 0.5See Also
tap_state/2- Inspect full quantum statetap_circuit/2- Inspect circuit metadata
@spec tap_state(Qx.QuantumCircuit.t(), (Nx.Tensor.t() -> any())) :: Qx.QuantumCircuit.t()
Inspects the current quantum state without breaking the pipeline.
Important: This executes all instructions so far to get the current state. Use sparingly in performance-critical code.
Parameters
circuit- The quantum circuitfun- Function to execute:(Nx.Tensor.t() -> any())
Examples
iex> circuit = Qx.QuantumCircuit.new(1, 0)
...> |> Qx.Operations.h(0)
...> |> Qx.Operations.tap_state(&IO.inspect(&1, label: "After H gate"))
...> |> Qx.Operations.z(0)
After H gate: #Nx.Tensor<...>
%Qx.QuantumCircuit{...}
iex> circuit = Qx.QuantumCircuit.new(2, 0)
...> |> Qx.Operations.h(0)
...> |> Qx.Operations.tap_state(fn state ->
...> probs = Qx.Math.probabilities(state)
...> IO.inspect(Nx.to_list(probs), label: "Probabilities")
...> end)
...> |> Qx.Operations.cx(0, 1)
Probabilities: [0.5, 0.5, 0.0, 0.0]
%Qx.QuantumCircuit{...}See Also
tap_circuit/2- Inspect circuit metadatatap_probabilities/2- Inspect measurement probabilities directly
Applies the general single-qubit unitary gate U(θ,φ,λ).
U(θ,φ,λ) = [[cos(θ/2), -e^(iλ)·sin(θ/2) ],
[e^(iφ)·sin(θ/2), e^(i(φ+λ))·cos(θ/2) ]]Follows the OpenQASM 3.0 specification built-in U gate /
Qiskit qiskit.circuit.library.UGate convention.
Decomposition identity: U(θ,φ,λ) = RZ(φ)·RY(θ)·RZ(λ) up to the
global phase e^{i(φ+λ)/2}. For the X/H/I/Y special cases below the
result is exact — Qiskit's UGate carries no extra global phase.
Special cases:
- U(π, 0, π) = X gate
- U(π/2, 0, π) = H gate
- U(0, 0, 0) = I gate
- U(π, π/2, π/2) = Y gate (up to global phase)
Parameters
circuit- The quantum circuitqubit- Target qubit indextheta(θ) - Polar rotation angle in radiansphi(φ) - Phase angle in radianslambda(λ) - Phase angle in radians
Examples
iex> qc = Qx.QuantumCircuit.new(1, 0)
iex> qc = Qx.Operations.u(qc, 0, :math.pi(), 0, :math.pi())
iex> [{gate, qubits, params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits, length(params)}
{:u, [0], 3}Raises
ArgumentError- if theta, phi, or lambda is not a numberFunctionClauseError- if qubit index is out of range
Applies a Pauli-X gate (bit flip) to the specified qubit.
The X gate flips |0⟩ to |1⟩ and |1⟩ to |0⟩.
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.x(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:x, [0]}
Applies a Pauli-Y gate to the specified qubit.
The Y gate applies both bit flip and phase flip transformations.
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.y(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:y, [0]}
Applies a Pauli-Z gate (phase flip) to the specified qubit.
The Z gate leaves |0⟩ unchanged and applies a phase of -1 to |1⟩.
Parameters
circuit- The quantum circuitqubit- Target qubit index
Examples
iex> qc = Qx.QuantumCircuit.new(2, 0)
iex> qc = Qx.Operations.z(qc, 0)
iex> [{gate, qubits, _params}] = Qx.QuantumCircuit.get_instructions(qc)
iex> {gate, qubits}
{:z, [0]}