Register Operations

A library of vectorial operations that can be applied to quantum registers.

Operations can be applied directly between registers, for example a bitwise XOR or an addition. This is similar to how registers work on classical computers. Rotations, and permutations in general, can be made without using any quantum gate because they just return a new view on the qubits, i.e. a new QuantumRegister that has the same logical qubits but in a different order.

The aim of this library is to be able to implement classical algorithms on quantum computers, to benefit from the speedup given by methods such as Grover’s algorithm.

pyqrypto.register_operations.FEYNMAN_QC: Final[int] = 1

The quantum cost of the Feynman gate (CNOT).

class pyqrypto.register_operations.RegisterCircuit(*inputs: QuantumRegister, **kwargs: Any)[source]

Bases: QuantumCircuit

A wrapper around QuantumCircuit.

It implements the logic needed to chain operations on quantum registers.

It supports new operations that operate on whole quantum registers and handles rotations without using any gate by rewiring the circuit when needed. This being also a fully valid QuantumCircuit, it is also possible to apply operations on single qubits as it is normally done in Qiskit.

Parameters:
  • inputs – The quantum registers to use as the circuit inputs.

  • kwargs – Other parameters to pass to the underlying QuantumCircuit object.

add(X: QuantumRegister, Y: QuantumRegister | int, ancillas: AncillaRegister | None = None, mode: str = 'ripple') QuantumRegister[source]

Add modulo \(2^n\) two registers of size n or a register of size n and a constant.

The adder can be implemented using different techniques:

  • ripple: requires 0 ancilla qubits, uses the ripple-carry method from [TTK2009].

  • lookahead: requires \(2n-w(n-1)-\lfloor \log(n-1) \rfloor-2\) ancilla qubits, uses the carry-lookahead method from [DKRS2004].

Parameters:
  • X – First register to add (the result will be stored in this register, overwriting its previous value).

  • Y – Second register to add or a constant.

  • ancillas – The anquilla register needed in lookahead mode.

Mode:

The type of adder to use.

Returns:

The output register \(X\).

Operation:

\(X \leftarrow X+Y \bmod 2^n\)

Note

If Y is a QuantumRegister, this operation is an addition between two registers, but if Y is an integer it becomes an addition between a register and a constant. In the latter case, the mode is always lookahead.

neg(X: QuantumRegister) QuantumRegister[source]

Apply a bitwise NOT on a register.

Parameters:

X – The register to apply the NOT to.

Returns:

The output register \(X\).

Operation:

\(X \leftarrow \neg X\)

rol(X: QuantumRegister, r: int) QuantumRegister[source]

Rotate left a register by a specified amount of qubits.

Parameters:
  • X – The register to rotate.

  • r – The number of qubits by which X should be rotated.

Returns:

The rotated register \(X'\).

Operation:

\(X' \leftarrow \mathrm{rol}(X, r)\)

ror(X: QuantumRegister, r: int) QuantumRegister[source]

Rotate right a register by a specified amount of qubits.

Parameters:
  • X – The register to rotate.

  • r – The number of qubits by which X should be rotated.

Returns:

The rotated register \(X'\).

Operation:

\(X' \leftarrow \mathrm{ror}(X, r)\)

property stats: dict

Some statistics about the circuit.

  • quantum_cost: The quantum cost of the circuit as defined by [FoM2009].

  • depth: The circuit depth when register operations are decomposed into NOT, CNOT and CCNOT gates.

  • gate_counts: The number of basic gates in the circuit.

Warning

Quantum cost computation only works if the circuit contains only register operations or NOT, CNOT, and CCNOT gates.

[FoM2009]

Mohammadi, M., & Eshghi, M. (2009). On figures of merit in reversible and quantum logic designs. Quantum Information Processing, 8, 297-318.

xor(X: QuantumRegister, Y: QuantumRegister | int) QuantumRegister[source]

Apply a bitwise XOR between two registers or between one register and a constant.

Parameters:
  • X – The first register to XOR (the result will be stored in this register, overwriting its previous value).

  • Y – The second register to XOR or a constant.

Returns:

The output register \(X\).

Operation:

\(X \leftarrow X \oplus Y\)

Note

If Y is a QuantumRegister, this operation is a XOR between two registers, but if Y is an integer it becomes a XOR between a register and a constant.

class pyqrypto.register_operations.RegisterConstantDKRSCarryLookaheadAdder(A: QuantumRegister, c: int, ancillas: AncillaRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

Addition modulo \(2^n\) between a quantum register and a constant.

Parameters:
  • X – The register of size n to add c to.

  • c – The constant to add to X.

  • label – An optional label for the gate.

Operation:

\(X \leftarrow X + c\)

static get_num_ancilla_qubits(n: int) int[source]

Get the number of required ancilla qubits without instantiating the class.

Parameters:

n – The number of qubits of the vectors to add.

Returns:

The number of ancilla qubits needed for the computation.

class pyqrypto.register_operations.RegisterConstantXOR(X: QuantumRegister, c: int, label: str | None = None)[source]

Bases: Gate, RegisterOperation

Bitwise XOR between a quantum register and a constant.

Parameters:
  • X – The register to XOR with c.

  • c – The constant to XOR with X.

  • label – An optional label for the gate.

Operation:

\(X \leftarrow X \oplus c\)

class pyqrypto.register_operations.RegisterDKRSCarryLookaheadAdder(A: QuantumRegister, B: QuantumRegister, ancillas: AncillaRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

A n qubits carry-lookahead adder modulo \(2^n\).

It implements the adder described in [DKRS2004] but skips the output carry compution.

Parameters:
  • A – First register of size n to add.

  • B – Second register of size n to add.

  • ancillas – The ancilla qubits used for the computation. They must be set to 0 before the circuit and will be reset to 0.

  • label – An optional label for the gate.

Raises:

CircuitError – If A and B have a different size or if there is not the correct number of ancilla qubits.

Operation:

\(X \leftarrow X+Y \bmod 2^n\)

[DKRS2004] (1,2,3)

Draper, T. G., Kutin, S. A., Rains, E. M., & Svore, K. M. (2004). A logarithmic-depth quantum carry-lookahead adder. arXiv preprint quant-ph/0406142.

static get_num_ancilla_qubits(n: int) int[source]

Get the number of required ancilla qubits without instantiating the class.

Parameters:

n – The number of qubits of the vectors to add.

Returns:

The number of ancilla qubits needed for the computation.

class pyqrypto.register_operations.RegisterDKRSComputeCarry(P0: Sequence[QuantumRegister], G: Sequence[QuantumRegister], ancillas: AncillaRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

Carry computation as described in [DKRS2004].

The last carry is not computed.

Parameters:
  • P0 – Represents \(P_0[i] = p[i, i+1]\), which is 1 if and only if carry propagages from bit \(i\) to bit \(i+1\).

  • G – Represents \(G[i] = g[i-1, i]\), which is 1 if and only if a carry is generated between bit \(i-1\) and bit \(i\).

  • ancillas – The ancilla qubits used for the computation. They must be set to 0 before the circuit and will be reset to 0.

class pyqrypto.register_operations.RegisterNOT(X: QuantumRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

Bitwise NOT on a quantum register.

Parameters:
  • X – The register to apply NOT on.

  • label – An optional label for the gate.

Oopoeration:

\(X \leftarrow \neg X\)

class pyqrypto.register_operations.RegisterOperation[source]

Bases: object

An operation on registers of qubits.

Variables:
  • inputs – The inputs registers of the operation.

  • outputs – The outputs registers of the operation.

property inputs: Sequence[QuantumRegister]

Get the inputs of the operation.

Returns:

A list containing the input quantum registers of the operation.

property outputs: Sequence[QuantumRegister]

Get the outputs of the operation.

Returns:

A list containing the output quantum registers of the operation.

class pyqrypto.register_operations.RegisterPrepare(X: QuantumRegister, value: int)[source]

Bases: QuantumCircuit, RegisterOperation

A circuit preparing a QuantumRegister to an initial classical integer value.

Parameters:
  • X – The register to prepare.

  • value – The value to prepare the register to.

Operation:

\(X \leftarrow \mathrm{value}\)

class pyqrypto.register_operations.RegisterROL(X: QuantumRegister, r: int)[source]

Bases: RegisterOperation

Defines the left rotation operation on a quantum register.

Parameters:
  • X – The register to rotate.

  • r – The number of qubits by which X should be rotated.

Raises:

CircuitError – If r is negative.

Operation:

\(X' \leftarrow \mathrm{rol}(X, r)\)

Warning

The result will be stored in register self.outputs[0].

class pyqrypto.register_operations.RegisterROR(X: QuantumRegister, r: int)[source]

Bases: RegisterOperation

Defines the right rotation operation on a quantum register.

Parameters:
  • X – The register to rotate.

  • r – The number of qubits by which X should be rotated.

Raises:

CircuitError – If r is negative.

Operation:

\(X' \leftarrow \mathrm{ror}(X, r)\)

Warning

The result will be stored in register self.outputs[0].

class pyqrypto.register_operations.RegisterTTKRippleCarryAdder(X: QuantumRegister, Y: QuantumRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

A gate implementing the n qubits ripple-carry adder modulo \(2^n\).

It implements the adder described in [TTK2009] but skips the output carry compution.

Parameters:
  • X – First register of size n to add.

  • Y – Second register of size n to add.

  • label – An optional label for the gate.

Raises:

CircuitError – If X and Y have a different size.

Operation:

\(X \leftarrow X+Y \bmod 2^n\)

[TTK2009] (1,2)

Takahashi, Y., Tani, S., & Kunihiro, N. (2009). Quantum addition circuits and unbounded fan-out. arXiv preprint arXiv:0910.2530.

class pyqrypto.register_operations.RegisterXOR(X: QuantumRegister, Y: QuantumRegister, label: str | None = None)[source]

Bases: Gate, RegisterOperation

Bitwise XOR operation between two quantum registers.

Parameters:
  • X – The first register to XOR.

  • Y – The second register to XOR.

  • label – An optional label for the gate.

Raises:

CircuitError – If X and Y have a different size.

Operation:

\(X \leftarrow X \oplus Y\)

pyqrypto.register_operations.SINGLE_QC: Final[int] = 1

The quantum cost of a single qubit gate.

pyqrypto.register_operations.TOFFOLI_QC: Final[int] = 5

The quantum cost of the Toffoli gate (CCNOT).

pyqrypto.register_operations.make_circuit(circuit: QuantumCircuit, inputs: Sequence[int], input_registers: Sequence[QuantumRegister], output_registers: Sequence[QuantumRegister]) QuantumCircuit[source]

Make a circuit with registers as input and measurement operations for the output registers.

Also prepare the initial values of the input registers.

Parameters:
  • circuit – The base circuit that will be expanded with measurement operations and preparation operations.

  • inputs – A list of the initial values to assign to the input registers.

  • inputs_registers – A list of the input registers.

  • output_registers – A list of the output registers.

Returns:

The final circuit containing the preparation step, the base circuit and the measurement step.

pyqrypto.register_operations.run_circuit(circuit: QuantumCircuit, method: str = 'automatic', device: str = 'CPU', shots: int = 1024) Sequence[int][source]

Simulate a circuit and retrieve the integer values of the classical registers.

Parameters:
  • circuit – The circuit to run.

  • method – The method to use for the simulator.

  • device – The device to run the simulation on (CPU or GPU).

  • shots – The number of times to run the simulation.

Returns:

A list of the integers stored in the classical registers of the circuit after the circuit has been simulated. It takes into account only the most frequent result.

Note

This function needs the qiskit_aer extra dependency.

pyqrypto.register_operations.simulate(circuit: QuantumCircuit, method: str = 'automatic', device: str = 'CPU', shots: int = 1024) Counts[source]

Simulate the given circuit and returns the results.

Parameters:
  • circuit – The circuit to simulate.

  • method – The method to use for the simulator.

  • device – The device to run the simulation on (CPU or GPU).

  • shots – The number of times to run the simulation.

Returns:

The result counts of the simulation.

Note

This function needs the qiskit_aer extra dependency.