loom.eka.circuit

Copyright (c) Entropica Labs Pte Ltd 2025.

Use, distribution and reproduction of this program in its source or compiled form is prohibited without the express written consent of Entropica Labs Pte Ltd.

class loom.eka.circuit.Circuit(*args, **kwargs)[source]

Bases: object

A serializable, recursive circuit representation. Previously defined circuit structures can be either reused as nested circuit elements or identified by name only for compression

Parameter

name: str

The name of the circuit/operation, identifying its behaviour: e.g. “Hadamard”, “CNOT” or “entangle” for the combination of a Hadamard and a CNOT gate.

circuit: tuple[tuple[Circuit, …], …]

Alternative inputs are: Circuit, list[Circuit], list[list[Circuit]], … Pydantic type conversion accepts all inputs stated here: https://docs.pydantic.dev/latest/concepts/conversion_table/

The list of nested circuit elements. The outer tuple represents the time step (tick) that the enclosed circuits are executed at. The inner tuple contains parallel circuits that are executed at the same time step. So each channel can only operated on by one circuit each tick.

An input of a 1D list/tuple of circuits is interpreted as a sequence of circuits. So each circuit is executed at its own tick and after the execution of the previous circuit is complete.

channels: tuple[Channel, …]

Alternative inputs are: Channel, list[Channel], set[Channel], … Pydantic type conversion accepts all inputs stated in the link above.

The list of channels involved in the circuit

id: str

The unique identifier of the circuit

classmethod adjust_channels(channels, values)[source]

Adjusts the channels of the circuit based on the channels of the nested circuits.

Parameters:
  • channels (Union(list[Channel], Channel)) – The channels of the circuit.

  • values (dict) – Values of other fields of the Circuit object.

Returns:

The adjusted list of channels of the circuit.

Return type:

list[Channel]

classmethod adjust_duration(duration, info)[source]

Sets the duration of the circuit based on the duration of the nested circuits (if any).

Return type:

int

classmethod as_gate(name, nr_qchannels, nr_cchannels=0, duration=1)[source]

Create a base gate by specifying the name and optionally the number of quantum and classical channels and the duration.

Parameters:
  • name (str) – The name of the gate.

  • nr_qchannels (int) – The number of quantum channels it acts on.

  • nr_cchannels (int) – The number of classical channels it acts on.

  • duration (int) – The duration of the base gate.

Returns:

The base gate Circuit object.

Return type:

Circuit

channels: tuple[Channel, ...] = FieldInfo(annotation=tuple[Channel, ...], required=False, default_factory=tuple, validate_default=True)
circuit: tuple[tuple[Circuit, ...], ...] = FieldInfo(annotation=tuple[tuple[Circuit, ...], ...], required=False, default_factory=tuple, validate_default=True)
circuit_seq()[source]

Returns the sequence of sub-circuits in the circuit field.

Returns:

The list of sub-circuits in sequence, disregarding ticks.

Return type:

tuple[Circuit, …]

clone(channels=None)[source]

Convenience method to clone a circuit structure that was defined before.

Parameter

channels: list[Channel]

Channels of the new circuit.

rtype:

Circuit

static construct_padded_circuit_time_sequence(circuit_time_sequence)[source]

Construct a padded circuit time sequence.

The input is a tuple of tuples of circuits, where each tuple of circuits represents a time step. Each time step may be of variable duration. The output is a tuple of tuples of circuits that includes empty tuples which represent time steps where the circuit is busy because of a composite sub-circuit.

Note that the scheduling is done following the time structure of the input, if two composite circuits exist in the same time step, they will start at the same time but may end at different times. If there are conflicts between subsequent circuits, add the minimum amount of padding such that the circuit can be executed. The last composite circuit’s padding will automatically be added since it is the last element in the sequence.

E.g.:

hadamard = Circuit("hadamard", channels=channels[0], duration=1)
cnot = Circuit("cnot", channels=channels[0:2], duration=2)
circuit_time_sequence = (
    (hadamard),
    (cnot,),
)

Constructing the padded circuit time sequence would result in:

padded_circuit_time_sequence = (
    (hadamard,),
    (cnot,),
    (),
)

Similarly, if the input is:

circuit_time_sequence = (
    (cnot),
    (hadamard,),
)

The padded circuit time sequence would be:

padded_circuit_time_sequence = (
    (cnot,),
    (),
    (hadamard,),
)

To illustrate two circuits that are executed at the same time, but of variable duration:

hadamard_2 = Circuit("hadamard_2", channels=channels[2], duration=1)
circuit_time_sequence = (
    (cnot, hadamard_2,)
)

The padded circuit time sequence would be:

padded_circuit_time_sequence = (
    (cnot, hadamard_2,),
    (),
)

where the cnot would span two time steps and hadamard_2 only one.

Parameters:

circuit_time_sequence (tuple[tuple[Circuit, ...], ...]) – The circuit time sequence to be padded.

Returns:

The padded circuit time sequence.

Return type:

tuple[tuple[Circuit, …], …]

detailed_str()[source]

Detailed string representation for a Circuit, displaying the gates and channels per tick.

duration: Optional[int] = None
flatten()[source]

Returns the flattened circuit as a copy where all elements in the circuit list are physical operations, and there is no further nesting.

Returns:

The flattened circuit

Return type:

Circuit

classmethod format_circuit(circuit)[source]

Format the circuit field to be a 2D tuple of circuits.

classmethod from_circuits(name, circuit=None)[source]

Create a Circuit object from a list of circuits with relative qubit indices.

Parameters:
  • name (str) – The name of the circuit.

  • circuit (list[tuple[Circuit, list[int]]], list[list[tuple[Circuit, list[int]]]]) – The list of circuits with relative qubit indices.

Returns:

The Circuit object.

Return type:

Circuit

id: str = FieldInfo(annotation=str, required=False, default_factory=<lambda>)
name: str
nr_of_qubits_in_circuit()[source]

Returns the number of qubits in the circuit.

Parameters:

circuit (Circuit) – recursive graph circuit representation

Returns:

the number of qubits in the circuit

Return type:

int

classmethod unroll(circuit)[source]

Unrolls the circuits within the time slices using a Depth First Search algorithm until the final sequence is composed of only base gates. This method preserves the time structure of the circuit (unlike flatten). Note that this method returns the unrolled circuit sequence, not a new Circuit.

Returns:

The unrolled circuit time sequence

Return type:

tuple[tuple[Circuit, …], …]

classmethod validate_timing(circuit)[source]

Validates, that all time steps and durations are consistent. I.e. that no two gates are scheduled on the same channel at the same time.

Return type:

tuple[tuple[Circuit, ...], ...]