Skip to content

workbench_algorithms.subroutines.swap_up

Qubricks for swap network circuits.

SwapUp

SwapUp(permutation_qbk=None, **kwargs)

Bases: Qubrick

Canonical SwapUp circuit that acts on arbitrary input states.

Assuming an already-loaded list of \(n\) items, each \(b\) bits long, this routine "swaps up" item with index \(x\) from the loaded items to the top position, i.e., to the top \(b\) qubits. The other items remain in positions \(1, ..., n - 1\), permuted in some order.

This follows the construction introduced in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954).

Parameters:

Name Type Description Default
permutation_qbk Qubrick

Qubrick to implement the bitonic permutations.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute SwapUp circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits

Register we apply the swap network to.

required
reg_size int

Number of bits in each item in the target register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0

BinaryToUnaryUncomputation

BinaryToUnaryUncomputation(permutation_qbk=None, **kwargs)

Bases: Qubrick

Circuit which undoes a binary to unary conversion.

Suppose we have an index register which encodes some integer \(i\) between zero and \(N - 1\) in binary, but we wish to convert this to unary. One way to do this would be to allocate \(N - 1\) ancillae (starting in the zero state), perform a Pauli X on the topmost ancilla, and "swap it down" to the \(i^{\text{th}}\) position (i.e. perform the dagger of SwapUp). This gives us a unary encoding of \(i\) on the ancillae entangled with a binary encoding of \(i\) on the index reg.

If we are later tasked with uncomputing/disentangling the ancillary register from the index reg, we could simply use SwapUp to bring the ON bit back to the top ancilla qubit, and then turn it back OFF with a Pauli X again. In this situation, by construction, we are returning all the ancillae back to zero. In this situation, we needn't use the canonical SwapUp circuit from ... for the uncomputation; we can instead employ the use of measurement-based uncomputation, which instead uses right elbows and no non-Clifford gates. This method is discussed in Appendix C and depicted in Fig. 10 in arXiv:1902.02134 .

Parameters:

Name Type Description Default
permutation_qbk Qubrick

Qubrick to implement the bitonic permutations..

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute reversal of Binary to Unary conversion.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits

Register we apply the swap network to.

required
reg_size int

Number of bits in each output register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0

InjectOp

InjectOp(swap_up, op, **kwargs)

Bases: Qubrick

Inject operation, defined as SwapUp \(^\dagger\) Op SwapUp.

This follows the construction introduced in Eq. 9 in "Exponentially faster implementations of Select(H) for fermionic Hamiltonians" (arXiv:2004.04170).

Parameters:

Name Type Description Default
swap_up Qubrick

SwapUp implementation.

required
op Qubrick

The unitary to inject.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute Inject circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits or VectorRegister

Register to apply the operation to.

required
reg_size int

Number of bits in each item in the target register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0
Note

For single-qubit unitaries (reg_size = 1), you can pass Qubits as target_reg. For multi-qubit unitaries (reg_size > 1), use VectorRegister as target_reg.