tangelo.linq package

Subpackages

Submodules

tangelo.linq.circuit module

This abstract quantum circuit class allows to represent a quantum circuit, described by successive abstract quantum gate operations, without tying it to a particular backend. It also provides methods to compute some of its characteristics (width, size …).

class tangelo.linq.circuit.Circuit(gates: List[Gate] | None = None, n_qubits=None, name='no_name', cmeasure_control=None)

Bases: object

An abstract quantum circuit class, represented by a list of abstract gate operations acting on qubits indices. From this list of gates, the gate counts, width and other properties can be computed. In the future, this information allows for finding unentangled registers or qubits only left in a classical state.

The attributes of the Circuit class should not be modified by the user: the add_gate method will ensure their value is correct as gates are added to the circuit object.

It is however ok to modify the value of the parameters for variational gate operations in a sub-class of Circuit, as this does not impact the quantum circuit information. An example of how to do this to engineer a parameterized ansatz to be used in a variational algorithm in available in the example folder.

add_gate(g)

Add a new gate to a circuit object and update other fields of the circuit object to gradually keep track of its properties (gate count, qubit indices…).

property applied_gates

Returns the list of gates applied during the latest simulation of the circuit.

If a CMEASURE gate is applied, the resulting circuit can be different from the _gates, The CMEASURE or MEASURE gate will store its measurement result as the parameter.

Example: circuit = Circuit([Gate(“H”, 0), Gate(“CMEASURE”, 0, {“0”: Gate(“X”, 0) “1”: []})]) will have circuit.applied_gates = [Gate(“H”, 0), Gate(“CMEASURE”, 0, parameter=”0”), Gate(“X”, 1)] or

circuit.applied_gates = [Gate(“H”, 0), Gate(“CMEASURE”, 0, parameter=”1”)]

controlled_measurement_op(measure)

Call the object self._cmeasure_control and return the next circuit to apply.

copy()

Return a deepcopy of circuit

property counts

Return the counts for all gate types included in the circuit.

property counts_n_qubit

Return the number of 1-qubit gates, 2-qubit gates, and so on.

depth()

Return the depth of the quantum circuit, by computing the number of moments. Does not count qubit initialization as a moment (unlike Cirq, for example). Compute from scratch.

draw()

Method to output a prettier version of the circuit for use in jupyter notebooks that uses cirq SVGCircuit

finalize_cmeasure_control()

Call the finalize method in cmeasure_control

get_entangled_indices()

Return a list of unentangled sets of qubit indices. Each set includes indices of qubits that form an entangled subset.

inverse()

Return the inverse (adjoint) of a circuit

This is performed by reversing the Gate order and applying the inverse to each Gate.

Returns:

Circuit – the inverted circuit

property is_mixed_state

Assume circuit leads to a mixed state due to mid-circuit measurement if any MEASURE or CMEASURE gate was explicitly added by the user.

property is_variational

Returns true if the circuit holds any variational gate.

merge_rotations()

Convenience method to merge compatible rotations applied successively on identical qubits indices. The operation is done in-place and alters the input circuit.

reindex_qubits(new_indices)

Reindex qubit indices according to users labels / new indices. The new indices are set according to [new_index_for_qubit0, nex_index_for_qubit1, …, new_index_for_qubit_N] where new_index < N.

remove_redundant_gates(remove_qubits=False)

Convenience method to remove redundant gates from the circuit. See separate remove_redundant_gates function.

Parameters:

remove_qubits (bool) – Optional, remove qubit with no operations assigned left

Returns:

Circuit – The circuit without redundant gates.

remove_small_rotations(param_threshold=0.001, remove_qubits=False)

Convenience method to remove small rotations from the circuit. See separate remove_small_rotations function.

Parameters:
  • param_threshold (float) – Optional, max absolute value to consider a rotation as small enough to be discarded

  • remove_qubits (bool) – Optional, remove qubit with no operations assigned left

Returns:

Circuit – The circuit without small rotations.

serialize()
simplify(max_cycles=100, param_threshold=0.001, remove_qubits=False)

Convenience method to simplify gates in a circuit, by repeating a set of simple passes until no further changes occurs, or a maximum number of cycles has been reached.

Parameters:
  • max_cycles (int) – Optional, maximum number of cycles to perform

  • param_threshold (float) – Optional, max absolute value to consider a rotation as small enough to be discarded

  • remove_qubits (bool) – Optional, remove qubit with no operations assigned left

property size

The size is the number of gates in the circuit. It is different from the depth.

split(trim_qubits=True)

Split a circuit featuring unentangled qubit subsets into as many circuit objects. Each circuit only contains the gate operations targeting the qubit indices in its subsets.

Parameters:

trim_qubits (bool) – Trim qubits on each circuit object and reindex to lowest value, Default: True

Returns:

list of Circuit – list of resulting circuits

stack(*other_circuits)

Convenience method to stack other circuits on top of this one. See separate stack function.

Parameters:

*other_circuits (Circuit) – one or several circuit objects to stack

Returns:

Circuit – the stacked circuit

property success_probabilities

Returns the dictionary of probabilities populated by simulating with different desired_meas_result.

The keys of the dictionary are bit strings, corresponding to the desired outcomes in the order the measurement gates arise in the circuit.

Each bit string must be simulated using a backend with n_shots=None and desired_meas_result=bitstring in order to populate the corresponding probability.

trim_qubits()

Trim unnecessary qubits and update indices with the lowest values possible.

property width

Return the number of qubits required by this circuit. Assume all qubits are needed, even those who do not appear in a gate instruction. Qubit indexing starts at 0.

class tangelo.linq.circuit.ClassicalControl

Bases: ABC

abstract finalize()

Called from simulator after all gates have been called.

Can be used to reinitialize variables for the next run and store results.

abstract return_gates(measurement) List[Gate]

Return the list of gates based on the measurement outcome.

Parameters:
  • measurement (str) – “1” or “0”

  • qubit (int) – The qubit index

Returns:

List[Gate] – The next gates to apply to the circuit

tangelo.linq.circuit.generate_applied_gates(source_circuit: Circuit, desired_meas_result=None) List[Gate]

Generate the applied gates of a Circuit without explicitly simulating.

Useful to determine the resources required for a circuit with measurement controlled operations given certain measurement outcomes.

Note: Measurement outcomes with zero probability can not be screened.

Parameters:
  • source_circuit (Circuit) – A circuit in the abstract format to be simulated with the classical control function called.

  • desired_meas_result (str) – The binary string of the desired measurement. Must have the same length as the number of CMEASURE+MEASURE gates in source_circuit

tangelo.linq.circuit.get_unitary_circuit_pieces(circuit: Circuit) Tuple[List[Circuit], List[int]]

Split circuit into the unitary circuits between mid-circuit non-unitary MEASURE gates.

Parameters:

circuit (Circuit) – the circuit to split

Returns:
  • List[Circuit] – The list of unitary circuits with a terminal non-unitary operation.

  • List[int] – The qubits that the “MEASURE” operation is applied to.

tangelo.linq.circuit.merge_rotations(circuit: Circuit)

Merge rotation gates successively applied to the same qubits (targets, controls), into a single equivalent rotation gate. If one of the gates involved is labeled variational, the merged rotation is as well.

Agglomerating non-numerical values for parameters is currently unsupported.

Parameters:

circuit (Circuit) – Input quantum circuit

Returns:

Circuit – circuit with merged rotations

tangelo.linq.circuit.remove_redundant_gates(circuit, remove_qubits=False)

Remove redundant gates in a circuit. Redundant gates are adjacent gates that can be cancelled as their global effect is the identity. This function also works with many-qubit gates. However, it does not perform reordering of commutating gates to perform additional cancellations.

Parameters:
  • circuit (Circuit) – the circuits to remove redundant gates.

  • remove_qubits (bool) – Optional, remove qubit with no operations assigned left

Returns:

Circuit – The circuit without redundant gates.

tangelo.linq.circuit.remove_small_rotations(circuit, param_threshold=0.001, remove_qubits=False)

Remove small rotation gates, up to a parameter threshold, from the circuit. Rotations from the set {“RX”, “RY”, “RZ”, “CRX”, “CRY”, “CRZ”} are considered.

Parameters:
  • circuit (Circuit) – the circuits to trim and stack into a single one

  • param_threshold (float) – Optional, Max absolute value to consider a rotation small enough to be discarded

  • remove_qubits (bool) – Optional, remove qubit with no operations assigned left

Returns:

Circuit – The circuit without small-rotation gates.

tangelo.linq.circuit.simplify(circuit, max_cycles=100, param_threshold=0.001, remove_qubits=False)

Convenience function to simplify gates in a circuit, by repeating a set of simple passes until no further changes occurs, or a maximum number of cycles has been reached (out of place operation).

Parameters:
  • circuit (Circuit) – the input circuit

  • max_cycles (int) – Optional, maximum number of cycles to perform

  • param_threshold (float) – Optional, max absolute value to consider a rotation as small enough to be discarded

  • remove_qubits (bool) – Optional, remove qubit with no operations assigned left

Returns:

Circuit – The simplified circuit

tangelo.linq.circuit.stack(*circuits)

Take list of circuits as input, and stack them (e.g concatenate them along the width (qubits)) to form a single wider circuit, which allows users to run all of these circuits at once on a quantum device.

Stacking provides a way to “fill up” a device if many qubits would be unused otherwise, therefore reducing cost / duration of a hardware experiment. However, depending on the device, this may amplify some sources of errors or make qubit placement more challenging.

Parameters:

*circuits (Circuit) – the circuits to trim and stack into a single one

Returns:

Circuit – the stacked circuit

tangelo.linq.gate module

Define an abstract quantum gate class holding information about a quantum gate operation, without tying it to a particular backend or an underlying mathematical operation.

class tangelo.linq.gate.Gate(name: str, target: int | integer | list | ndarray, control: int | integer | list | ndarray | None = None, parameter='', is_variational: bool = False)

Bases: dict

An abstract gate class that exposes all the gate information such as gate name, control and target qubit indices, parameter values. Assumes qubit indexation starts at index 0.

name

the gate name,

Type:

str

target

A positive integer denoting the index of the target qubit,

Type:

int

control

A positive integer denoting the index of the control qubit,

Type:

int

parameter

A floating-point number or symbolic expression that will resolve at runtime. Can hold anything.

is_variational

a boolean indicating if the gate operation is variational or not.

Type:

bool

inverse()

Return the inverse (adjoint) of a gate.

Returns:

the inverse of the gate.

Return type:

Gate

is_clifford(abs_tol=0.0001)

Check if a quantum gate is a Clifford gate.

Parameters:

abs_tol (float) – Optional, Absolute tolerance for the difference between gate parameter clifford parameter values

Returns:

bool – True if the gate is in Clifford gate list or has a parameter corresponding to Clifford points, False otherwise.

serialize()

tangelo.linq.qdk_template module

This python module stores template Q# strings that can be used to have Q# code files ready to be shared with collaborators, submitted to a remote compute backend through Microsoft services or compiled by the local QDK simulator.

tangelo.linq.simulator module

Factory function acting as a unified interface able to instantiate any simulator object associated to a specific target (qulacs, qiskit, cirq, user-defined…). Some built-in target simulators support features such as noisy simulation, the ability to run noiseless simulation with shots, or particular emulation techniques. Target backends can also be implemented using APIs to quantum devices.

tangelo.linq.simulator.get_backend(target: None | str | Type[Backend] = 'qulacs', n_shots: None | int = None, noise_model=None, **kwargs)

Return requested target backend object.

Parameters:
  • target (string or Type[Backend] or None) – Supported string identifiers can be found in target_dict (from tangelo.linq.target). Can also provide a user-defined backend (child to Backend class)

  • n_shots (int) – Number of shots if using a shot-based simulator.

  • noise_model – A noise model object assumed to be in the format expected from the target backend.

  • kwargs – Other arguments that could be passed to a target. Examples are qubits_to_use for a QPU, transpiler optimization level, error mitigation flags etc.

Module contents