Circuits and Gates

Construct and manipulate circuits. Refer to these Jupyter Notebook tutorials on Forge:

  • GettingStarted/Examples/Circuits/quasar_circuit_composition.ipynb

  • GettingStarted/Examples/Circuits/quasar_gate_library.ipynb

  • GettingStarted/Examples/Circuits/quasar_parameters.ipynb

Classes

Class Circuit

Circuit Attributes

Circuit Composition

Circuit Parameter Manipulation

Gates

Other

Class CompositeGate

Class ControlledGate

Class Gate

Explicit 1-Body Gates

Explicit 2-Body Gates

Explicit 3-Body Gates

Parameterized 1-Body Gates

  • iRBS()

  • u1()

  • u2()

  • u3()

Parameterized 2-Body Gates

  • SO4()

  • SO42()

Special Explicit Gates

Gate Attributes

Other

Class Matrix

class quasar.circuit.Circuit

Class Circuit represents a sequence of quantum gate operations.

CCX(qubitA, qubitB, qubitC, **kwargs)

Add a CCX gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control1 qubit index in self to add the gate into.

  • qubitB (int) – control2 qubit index in self to add the gate into.

  • qubitC (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CF(qubitA, qubitB, theta=0.0, **kwargs)

Add a CF gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CS(qubitA, qubitB, **kwargs)

Add a CS gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CST(qubitA, qubitB, **kwargs)

Add a CS^+ gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CSWAP(qubitA, qubitB, qubitC, **kwargs)

Add a CSWAP gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – swap1 qubit index in self to add the gate into.

  • qubitC (int) – swap2 qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CX(qubitA, qubitB, **kwargs)

Add a CX gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CY(qubitA, qubitB, **kwargs)

Add a CY gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

CZ(qubitA, qubitB, **kwargs)

Add a CZ gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

G(qubitA, qubitB, theta=0.0, **kwargs)
Add a Givens gate to self at specified qubits and time,

updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

Params:

qubitA (int) - qubit index in self to add the gate into. qubitB (int) - qubit index in self to add the gate into. theta (float) - the angle parameter of the gate (default - 0.0). time (int) - time moment in self to add the gate into. If None, the

time_placement argument will be considered next.

time_placement (str - ‘early’, ‘late’, or ‘next’) - recipe to

determine time moment in self to add the gate into. The rules are:

‘early’ - add the gate as early as possible, just after

any existing gates on self’s qubit wires.

‘late’ - add the gate in the last open time moment in self,

unless a conflict arises, in which case, add the gate in the next (new) time moment.

‘next’ - add the gate in the next (new) time moment.

Result:
self is updated with the added gate. Checks are

performed to ensure that the addition is valid.

Returns

self - for chaining

H(qubit, **kwargs)

Add an H (Hadamard) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are

performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

I(qubit, **kwargs)

Add an I (Identity) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

PX(qubitA, qubitB, qubitC, qubitD, theta=0.0, **kwargs)
Add a Pair exchange gate to self at specified qubits and time,

updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

Params:

qubitA (int) - qubit index in self to add the gate into. qubitB (int) - qubit index in self to add the gate into. qubitC (int) - qubit index in self to add the gate into. qubitD (int) - qubit index in self to add the gate into. theta (float) - the angle parameter of the gate (default - 0.0). time (int) - time moment in self to add the gate into. If None, the

time_placement argument will be considered next.

time_placement (str - ‘early’, ‘late’, or ‘next’) - recipe to

determine time moment in self to add the gate into. The rules are:

‘early’ - add the gate as early as possible, just after

any existing gates on self’s qubit wires.

‘late’ - add the gate in the last open time moment in self,

unless a conflict arises, in which case, add the gate in the next (new) time moment.

‘next’ - add the gate in the next (new) time moment.

Result:
self is updated with the added gate. Checks are

performed to ensure that the addition is valid.

Returns

self - for chaining

R_ion(qubit, theta=0.0, phi=0.0, **kwargs)

Add an R_ion gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • phi (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rx(qubit, theta=0.0, **kwargs)

Add an Rx (X-rotation) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rx2(qubit, **kwargs)

Add an Rx2 (Z -> Y basis) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rx2T(qubit, **kwargs)

Add an Rx2T (Y -> Z basis) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rx_ion(qubit, theta=0.0, **kwargs)

Add an Rx_ion gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Ry(qubit, theta=0.0, **kwargs)

Add an Ry (Y-rotation) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Ry_ion(qubit, theta=0.0, **kwargs)

Add an Ry_ion gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rz(qubit, theta=0.0, **kwargs)

Add an Rz (Z-rotation) gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Rz_ion(qubit, theta=0.0, **kwargs)

Add an Rz_ion gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

S(qubit, **kwargs)

Add an S gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

SO4(qubitA, qubitB, A=0.0, B=0.0, C=0.0, D=0.0, E=0.0, F=0.0, **kwargs)

Add an SO4 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • A (float) – SO4 A parameter (default - 0.0)

  • B (float) – SO4 B parameter (default - 0.0)

  • C (float) – SO4 C parameter (default - 0.0)

  • D (float) – SO4 D parameter (default - 0.0)

  • E (float) – SO4 E parameter (default - 0.0)

  • F (float) – SO4 F parameter (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Result

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Returns

self - for chaining

SO42(qubitA, qubitB, thetaIY=0.0, thetaYI=0.0, thetaYX=0.0, thetaXY=0.0, thetaZY=0.0, thetaYZ=0.0, **kwargs)

Add an SO4 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • thetaIY (float) – SO4 thetaIY parameter (default - 0.0)

  • thetaYI (float) – SO4 thetaYI parameter (default - 0.0)

  • thetaYX (float) – SO4 thetaYX parameter (default - 0.0)

  • thetaXY (float) – SO4 thetaXY parameter (default - 0.0)

  • thetaZY (float) – SO4 thetaZY parameter (default - 0.0)

  • thetaYZ (float) – SO4 thetaYZ parameter (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

ST(qubit, **kwargs)

Add an S^+ gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

SWAP(qubitA, qubitB, **kwargs)

Add a SWAP gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

T(qubit, **kwargs)

Add a T gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

TT(qubit, **kwargs)

Add a T^+ gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

U1(qubitA, U, **kwargs)

Add a U1 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • U (np.ndarray) – 2 x 2 unitary to construct the U1 gate from.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

U2(qubitA, qubitB, U, **kwargs)

Add a U2 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • U (np.ndarray) – 4 x 4 unitary to construct the U1 gate from.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

U4(qubitA, qubitB, qubitC, qubitD, U, **kwargs)
Add a user defined 4-qubit gate to self at specified qubits and time,

updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

Params:

qubitA (int) - qubit index in self to add the gate into. qubitB (int) - qubit index in self to add the gate into. qubitC (int) - qubit index in self to add the gate into. qubitD (int) - qubit index in self to add the gate into. U (np.ndarray) - 16 x 16 unitary to construct the U4 gate from. time (int) - time moment in self to add the gate into. If None, the

time_placement argument will be considered next.

time_placement (str - ‘early’, ‘late’, or ‘next’) - recipe to

determine time moment in self to add the gate into. The rules are:

‘early’ - add the gate as early as possible, just after

any existing gates on self’s qubit wires.

‘late’ - add the gate in the last open time moment in self,

unless a conflict arises, in which case, add the gate in the next (new) time moment.

‘next’ - add the gate in the next (new) time moment.

Result:
self is updated with the added gate. Checks are

performed to ensure that the addition is valid.

Returns

self - for chaining

X(qubit, **kwargs)

Add an X gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

XX_ion(qubitA, qubitB, chi=0.0, **kwargs)

Add an XX_ion gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubitA (int) – control qubit index in self to add the gate into.

  • qubitB (int) – target qubit index in self to add the gate into.

  • chi (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Y(qubit, **kwargs)

Add an Y gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

Z(qubit, **kwargs)

Add an Z gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

add_gate(gate, qubits, times=None, time_start=None, time_placement='early', copy=True, name=None, ascii_symbols=None, return_key=False)

Add a gate to self at specified qubits and times, updating self. The qubits to add gate to are always explicitly specified. The times to add the gate to may be explicitly specified in the times argumet (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • gate (Gate or Circuit) – the gate to add into self. If gate is a Circuit, gate will be cast to a CompositeGate and then added into self.

  • qubits (int or tuple of int) – ordered qubit indices in self to add the qubit indices of circuit into. If a single int is provided (for one-qubit gate addition), it is converted to a tuple with a single int entry.

  • times (int or tuple of int or None) – time moments in self to add the gate into. If default value None, the time_start argument will be considered next.

  • time_start (int or None) – starting time moment in self to add the gate into (often used with ntime > 1 gates). If default value None, the time_placement argument will be considered next.

  • (str (time_placement) –

    ‘early’, ‘late’, or ‘next’): recipe to determine time moment in self to add gate into. The rules are:

    • early (default) - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

  • copy (bool) – copy the gate or not? (default - True)

  • name (str) – name of the gate for use in CompositeGate (default value None indicates default name)

  • ascii_symbols (list of str or None) – ASCII symbols for use in CompositeGate (default value None indicates default symbols)

  • return_key (bool) – return self for chaining (default - False) or (times, qubits) key (True) to determine gate placement.

  • Returnsself - for chaining

add_gates(circuit, qubits, times=None, time_start=None, time_placement='early', copy=True)

Add the gates of another circuit to self at specified qubits and times, updating self. Essentially a composite version of add_gate. The qubits to add circuit to are always explicitly specified. The times to add circuit to may be explicitly specified in the time argument (1st priority), the starting time moment may be explicitly specified and then the circuit added in a time-contiguous manner from that point using the time_start argument (2nd priority), or a recipe for determining the time-contiguous placement can be specified using the time_placement argument (3rd priority).

self is updated with the added gates from circuit. Checks are performed to ensure that the addition is valid.

Parameters
  • circuit (Circuit) – the circuit containing the gates to add into self.

  • qubits (tuple of int) – ordered qubit indices in self to add the qubit indices of circuit into.

  • times (tuple of int) – ordered time moments in self to add the time moments of circuit into. If default value None, the time argument will be considered next.

  • time_start (int) – starting time moment in self to add the time moments of circuit into. If default value None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine starting time moment in self to add the time moments of circuit into. The rules are:

    • early (default) - start adding the circuit as early as possible, just after any existing gates on self’s qubit wires.

    • late - start adding the circuit in the last open time moment in self, unless a conflict arises, in which case, start adding the circuit in the next (new) time moment

    • next - start adding the circuit in the next (new) time moment.

  • copy (bool) – copy Gate elements to remove parameter dependencies between circuit and updated self (default - True) or not (False).

Returns

self - for chaining

center(center_in_qubits=True, center_in_times=True, origin_in_qubits=0, origin_in_time=0, copy=True)

Reset the origin of the circuit in qubit and/or time space.

Parameters
  • center_in_qubits (bool) – to reset the origin of the circuit in qubit space or not? (default - True)

  • center_in_times (bool) – to reset the origin of the circuit in time space or not? (default - True)

  • origin_in_qubits (int) – the origin around which to center the qubit indices. (default - 0.0)

  • origin_in_time (int) – the origin around which to center the time indices. (default - 0.0)

  • copy (bool) – to copy the gates in the cirucit

  • not? (or) –

Returns

self for chaining

copy()

Return a copy of circuit self so that parameter modifications in the copy do not affect self.

Returns

copy of self with all Gate objects copied deeply enough to remove parameter dependencies between self and returned Circuit.

Return type

Circuit

property is_composite

Does this circuit contain any CompositeGate objects?

Type

bool

property is_controlled

Does this circuit contain any ControlledGate objects?

Type

bool

static join_in_qubits(circuits, copy=True)

Join two or more circuits in qubit space.

Parameters
  • circuits (list of Circuit objects) – circuits to join in qubit space

  • copy (bool) – copy the gates in the circuit or not? (default - True)

Returns

circuit composed of connected Circuit objects in circuits

Return type

Circuit

static join_in_time(circuits, copy=True)

Join two or more circuits in time.

Parameters
  • circuits (list of Circuit objects) – circuits to join in time

  • copy (bool) – copy the gates in the circuit or not? (default - True)

Returns

circuit composed of connected Circuit objects in circuits

Return type

Circuit

property max_gate_nqubit

Maximum number of qubits in any gate in the circuit.

Type

int

property max_gate_ntime

Maximum number of times in any gate in the circuit.

Type

int

property max_qubit

The maximum occupied qubit index (or -1 if no occupied qubits)

Type

int

property max_time

The maximum occupied time index (or -1 if no occupied times)

Type

int

property min_qubit

The minimum occupied qubit index (or 0 if no occupied qubits)

Type

int

property min_time

The minimum occupied time index (or 0 if no occupied times)

Type

int

property ngate

The total number of gates in the circuit.

Type

int

property ngate1

The total number of 1-qubit gates in the circuit.

Type

int

property ngate2

The total number of 2-qubit gates in the circuit.

Type

int

property ngate3

The total number of 3-qubit gates in the circuit.

Type

int

property ngate4

The total number of 4-qubit gates in the circuit.

Type

int

ngate_nqubit(nqubit)

The total number of nqubit-qubit gates in the circuit.

Parameters

nqubit (int) – number of qubits to screen on.

Returns

Return type

int

property nparameter

Total number of parameters in Circuit.

Type

int

property nqubit

The total number of qubit indices in the circuit (including empty qubit indices).

Type

int

property nqubit_sparse

The total number of occupied qubit indices in the circuit (excluding empty qubit indices).

Type

int

property ntime

The total number of time indices in the circuit (including empty time indices).

Type

int

property ntime_sparse

The total number of occupied time indices in the circuit (excluding empty time indices).

Type

int

property parameter_indices

A map from all circuit Gate keys to parameter indices.

Useful as a utility to determine the absolute parameter indices of a Gate, given knowledge of its Gate key.

Returns

map from all circuit Gate keys to absolute parameter indices. For each Gate key, a tuple of absolute parameter indices is supplied - there may be no parameter indices, one parameter index, or multiple parameter indices in each value, depending on the number of parameters of the underlying Gate.

Return type

OrderedDict

property parameter_keys

All keys in the parameters OrderedDict. Each key is a tuple in the form (times, qubits, parameter_key).

Type

list of tuples

property parameter_str

A human-readable string describing the circuit coordinates, parameter names, gate names, and values of all mutable parameters in this circuit.

Returns

human-readable string describing parameters in order specified by param_keys.

Return type

str

property parameter_values

All values in the parameters OrderedDict.

Type

list of tuples

property parameters

An OrderedDict of parameter (times, qubits, parameter_key) keys to parameter values.

Type

OrderedDict

remove_gate(qubits, times)

Remove a gate from self at specified qubits and times, updating self. The qubits and times to remove gate from are always explicitly specified.

self is updated with gates removed from circuit.

Parameters
  • qubits (int or tuple of int) – ordered qubit indices in self to remove the qubit indices of circuit from. If a single int is provided (for one-qubit gate addition), it is converted to a tuple with a single int entry.

  • times (int or tuple of int or None) – time moments in self to remove the gate from.

Returns

self - for chaining

replace_gate(gate, qubits, times, name=None, ascii_symbols=None)

Replace the gate of a circuit at specified qubits and times with gate, updating self. The qubits and times at which to replace gate are always explicitly specified.

Parameters
  • gate (Gate or Circuit) – the gate to add into self to replace the gate at qubits and times. If gate is a Circuit, gate will be cast to a CompositeGate and then added into self.

  • qubits (int or tuple of int) – ordered qubit indices in self at which the gate to be replaced is located. If a single int is provided (for one-qubit gate addition), it is converted to a tuple with a single int entry.

  • times (int or tuple of int or None) – time moments in self at which the gate to be replaced is located.

  • name (str) – name of gate for use in CompositeGate (default value None indicates default name)

  • ascii_symbols (list of str or None) – ASCII symbols for use in CompositeGate (default value None indicates default symbols)

reverse(copy=True)

Obtain the time-reversed ordering of the circuit (gate time order reversed, but no gate adjoints taken).

Parameters

copy (bool) – copy the gates in the circuit or not? (default -True)

Returns

self for chaining

set_parameter(key, value)

Set value of a self parameter corresponding to the specified key.

Parameters
  • key (tuple) – parameter key in the format (times, qubits, parameter_keys)

  • value (float) – parameter value

Returns

self for chaining

set_parameter_values(parameter_values, parameter_indices=None)

Set parameter values for parameter corresponding to the given parameter_indices.

Parameters
  • parameter_values (list of floats) – values at which to set parameters.

  • parameter_indices (list of ints) – indices corresponding to parameters whose values are being set. If default value None, set all parameter values.

Returns

self for chaining

set_parameters(parameters)

Set values of multiple parameters corresponding to specified keys.

Parameters

parameters (OrderedDict) – OrderedDict with key-value pairs for each parameter. Keys should be tuples in the format (times, qubits, parameter_keys) and values should be floats.

Returns

self for chaining

slice(qubits=None, times=None, qubits_to=None, times_to=None, circuit_to=None, copy=True)

Extract a subset of qubit indices and/or time indices from the source circuit self and map them to the target qubit indices and/or time indices in the returned circuit.

Parameters
  • qubits (list of ints) – source keys indicating which qubit indices to slice from the source circuit self. If default value None, the qubit dimension of the circuit does not change.

  • times (list of ints) – source keys indicating which time indices to slice from the source circuit self. If default value None,the time dimension of the circuit does not change.

  • qubits_to (list of ints) – target keys indicating which qubit indices the source qubit keys will map to in the returned circuit. If default value None, but qubits is specified, the target indices are inferred to start at zero and increase sequentially.

  • times_to (list of ints) – target keys indicating which time indices the source time keys will map to in the returned circuit. If default value None, but times is specified, the target indices are inferred to start at zero and increase sequentially.

  • circuit_to (Circuit) – the circuit to which the sliced subset of qubit indices and/or time indices are mapped. If default value None, None, a new Circuit object is instantiated.

  • copy (bool) – copy the sliced gates added to circuit_to or not? (default - True)

Raises

RuntimeError – if qubits_to is specified but qubits is not specified or if times_to is specified but times is not specified.

Returns

circuit_to modified with the subset of sliced qubit and/or time indices. Validity checks are performed on circuit_to.

Return type

Circuit

sparse(sparse_in_qubits=True, sparse_in_time=True, copy=True)

Remove empty time and/or qubit indices from the circuit.

Parameters
  • sparse_in_qubits (bool) – does the circuit have empty qubit indices? (default - True)

  • sparse_in_time (bool) – does the circuit have empty time indices? (default - True)

  • copy (bool) – to copy the gates in the circuit or not? (default - True)

Returns

self for chaining

static test_equivalence(circuit1, circuit2, operator_tolerance=1e-12)

Test logical circuit equivalence at the level of geographic locations of Gate objects and operator equivalence of Gate objects.

Note that this can be conceptually considered to be an intermediate level definition of equivalence. At the lowest level (not this case), one could define equivalence to be in terms of the overall unitary matrix of the circuits - many different gate layouts and definitions would provide equivalence under this definitions. At the highest level (not this case), one could define equivalence to require identical geographic locations of Gate object, and identical Gate objects (e.g., in terms of Gate/ControlledGate/CompositeGate class, parameters, names, etc). Here, we define circuit equivalence to the intermediate level of identical geographic locations of Gate objects, and numerically identical Gate operators, but do not check the specific recipe of each Gate’s definition.

Parameters
  • circuit1 (Circuit) – first circuit to compare

  • circuit2 (Circuit) – second circuit to compare

  • operator_tolerance (float) – maximum absolute deviation threshold for declaring Gate operator matrices to be identical. (default - 1.0E-12)

Returns

True if the circuits are equivalent under the definition above, else False.

Return type

bool

u1(qubit, lam=0.0, **kwargs)

Add a u1 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • lam (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

u2(qubit, phi=0.0, lam=0.0, **kwargs)

Add a u3 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • phi (float) – the angle parameter of the gate (default - 0.0)

  • lam (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

u3(qubit, theta=0.0, phi=0.0, lam=0.0, **kwargs)

Add a u3 gate to self at specified qubits and time, updating self. The qubits to add gate to are always explicitly specified. The time to add gate to may be explicitly specified in the time argument (1st priority), or a recipe for determining the time placement can be specified using the time_placement argument (2nd priority).

self is updated with the added gate. Checks are performed to ensure that the addition is valid.

Parameters
  • qubit (int) – qubit index in self to add the gate into.

  • theta (float) – the angle parameter of the gate (default - 0.0)

  • phi (float) – the angle parameter of the gate (default - 0.0)

  • lam (float) – the angle parameter of the gate (default - 0.0)

  • time (int) – time moment in self to add the gate into. If None, the time_placement argument will be considered next.

  • time_placement (str - 'early', 'late', or 'next') –

    recipe to determine time moment in self to add the gate into. The rules are:

    • early - add the gate as early as possible, just after any existing gates on self’s qubit wires.

    • late - add the gate in the last open time moment in self, unless a conflict arises, in which case, add the gate in the next (new) time moment.

    • next - add the gate in the next (new) time moment.

Returns

self - for chaining

class quasar.circuit.CompositeGate(circuit, name=None, ascii_symbols=None)

Class CompositeGate represents a gate containing subgates.

adjoint()

Make the adjoint of the current Gate (always a copy).

Returns

a Gate representing the adjoint of the current Gate

  • If self.involuntary is True, a copy of self is returned.

  • Else if self.adjoint_function is not None, self.adjoint_function(self.parameters) is called and used to return the desired Gate.

  • Else an extended copy of the current Gate with property dressed adjoint operator_function and ‘^+’ added to name and ascii_symbols is returned (always works correctly, but ‘^+^+^+’ runs build up under repeated calls to adjoint).

Return type

(Gate)

apply_to_statevector(statevector1, statevector2, qubits, dtype=<class 'numpy.complex128'>)

Apply this gate to statevector1, acting on qubit indices in qubits, and return the result, along with a scratch statevector. Ideally, no statevector allocations will be performed in the course of this operation - a scratch statevector is provided as input to help with this.

Either or both of statevector1 and statevector2 may be modified. One of them is modified to contain the resultant statevector, and then this output statevector and the new scratch statevector are returned.

Parameters
  • statevector1 (np.ndarray, shape 2**N) – input statevector

  • statevector2 (np.ndarray, shape 2**N) – scratch statevector

  • qubits (iterable of ints, size self.nqubit) – qubit indices to apply this gate to

  • dtype (real or complex dtype) – the dtype to perform the computation at. The gate operator will be cast to this dtype. Note that using real dtypes (float64 or float32) can reduce storage and runtime, but the imaginary parts of the input wfn and all gate unitary operators will be discarded without checking. In these cases, the user is responsible for ensuring that the circuit works on O(2^N) rather than U(2^N) and that the output is valid. (default - np.complex128)

Returns

output, scratch - output statevector, then scratch statevector

Return type

np.ndarray, shape 2**N

copy()

Make a deep copy of the current Gate.

Returns

a copy of this Gate whose parameters may be modified without modifying the parameters of self.

Return type

Gate

property is_composite

Is this Gate quasar.circuit.CompositeGate (containing subgates) (always False)

Type

bool

property is_controlled

Is this Gate quasar.circuit.ControlledGate (containing controls + Gate) (always False)

Type

bool

property ntime

Number of time indices occupied by this Gate (always 1)

Type

int

set_parameter(key, value)

Set the value of a parameter of this Gate. The result is self.parameters[key] = value.

Parameters
  • key (str) – the key of the parameter

  • value (float) – the value of the parameter

Raises

RuntimeError – if the Gate does not have a parameter corresponding to key.

set_parameters(parameters)

Set the values of multiple parameters of this Gate. self.parameters is updated with the contents of parameters by calling self.set_parameter for each key/value pair.

Parameters

(dict of str (parameters) – float): dict of parameter values

class quasar.circuit.ControlledGate(gate, controls=None)

Class ControlledGate represents a gate containing controls.

adjoint()

Make the adjoint of the current Gate (always a copy).

Returns

a Gate representing the adjoint of the current Gate

  • If self.involuntary is True, a copy of self is returned.

  • Else if self.adjoint_function is not None, self.adjoint_function(self.parameters) is called and used to return the desired Gate.

  • Else an extended copy of the current Gate with property dressed adjoint operator_function and ‘^+’ added to name and ascii_symbols is returned (always works correctly, but ‘^+^+^+’ runs build up under repeated calls to adjoint).

Return type

(Gate)

copy()

Make a deep copy of the current Gate.

Returns

a copy of this Gate whose parameters may be modified without modifying the parameters of self.

Return type

Gate

property is_composite

Is this Gate quasar.circuit.CompositeGate (containing subgates) (always False)

Type

bool

property is_controlled

Is this Gate quasar.circuit.ControlledGate (containing controls + Gate) (always False)

Type

bool

property ntime

Number of time indices occupied by this Gate (always 1)

Type

int

set_parameter(key, value)

Set the value of a parameter of this Gate. The result is self.parameters[key] = value.

Parameters
  • key (str) – the key of the parameter

  • value (float) – the value of the parameter

Raises

RuntimeError – if the Gate does not have a parameter corresponding to key.

set_parameters(parameters)

Set the values of multiple parameters of this Gate. self.parameters is updated with the contents of parameters by calling self.set_parameter for each key/value pair.

Parameters

(dict of str (parameters) – float): dict of parameter values

class quasar.circuit.Gate(nqubit, operator_function, parameters, name, ascii_symbols, involutary=False, adjoint_function=None)

Class Gate represents a quantum gate operation, i.e., a (usually) unitary operator acting on a specific number of qubits.

This specific Gate class represents a “primitive” gate with an explicitly defined operator that occupies a single time index. Primitive Gate objects do not contain any subsidiary Gate or quasar.circuit.Circuit objects.

I

Static attribute representing the I (identity) gate.

X

Static attribute representing the X (NOT) gate.

Y

Static attribute representing the Y gate.

Z

Static attribute representing the Z gate.

H

Static attribute representing the H gate.

S

Static attribute representing the S gate.

ST

Static attribute representing the S^+ gate.

T

Static attribute representing the T gate.

TT

Static attribute representing the T^+ gate.

Rx2

Static attribute representing the Rx2 gate.

Rx2T

Static attribute representing the Rx2T gate.

CX

Static attribute representing the CX (CNOT) gate.

CY

Static attribute representing the CY gate.

CZ

Static attribute representing the CZ gate.

CS

Static attribute representing the CS gate.

CST

Static attribute representing the CS^T+ gate.

SWAP

Static attribute representing the SWAP gate.

CCX

Static attribute representing the CCX (Toffoli) gate.

CSWAP

Static attribute representing the CSWAP (Toffoli) gate.

static CF(theta=0.0)

Controlled F gate

static G(theta=0.0)

Givens Gate defined as

[ 1 0 0 0 ] [ 0 cos(theta) sin(theta) 0 ] [ 0 -sin(theta) cos(theta) 0 ] [ 0 0 0 1 ]

static PX(theta=0.0)

Pair exchange gate (4-qubit Givens gate).

static RBS(theta=0.0)

Reconfigurable Beam Splitter gate; defined as

[ 1  0           0           0 ]
[ 0  cos(theta)  sin(theta)  0 ]
[ 0  -sin(theta) cos(theta)  0 ]
[ 0  0           0           1 ]
static Rx(theta=0.0)

Rx (theta) = exp(-i * theta * x)

static Ry(theta=0.0)

Ry (theta) = exp(-i * theta * Y)

static Rz(theta=0.0)

Rz (theta) = exp(-i * theta * Z)

static U1(U)

An explicit 1-body gate that is specified by the user.

static U2(U)

An explicit 2-body gate that is specified by the user.

static U4(U)

An explicit 4-body gate that is specified by the user.

adjoint()

Make the adjoint of the current Gate (always a copy).

Returns

a Gate representing the adjoint of the current Gate

  • If self.involuntary is True, a copy of self is returned.

  • Else if self.adjoint_function is not None, self.adjoint_function(self.parameters) is called and used to return the desired Gate.

  • Else an extended copy of the current Gate with property dressed adjoint operator_function and ‘^+’ added to name and ascii_symbols is returned (always works correctly, but ‘^+^+^+’ runs build up under repeated calls to adjoint).

Return type

(Gate)

apply_to_statevector(statevector1, statevector2, qubits, dtype=<class 'numpy.complex128'>)

Apply this gate to statevector1, acting on qubit indices in qubits, and return the result, along with a scratch statevector. Ideally, no statevector allocations will be performed in the course of this operation - a scratch statevector is provided as input to help with this.

Either or both of statevector1 and statevector2 may be modified. One of them is modified to contain the resultant statevector, and then this output statevector and the new scratch statevector are returned.

Parameters
  • statevector1 (np.ndarray, shape 2**N) – input statevector

  • statevector2 (np.ndarray, shape 2**N) – scratch statevector

  • qubits (iterable of ints, size self.nqubit) – qubit indices to apply this gate to

  • dtype (real or complex dtype) – the dtype to perform the computation at. The gate operator will be cast to this dtype. Note that using real dtypes (float64 or float32) can reduce storage and runtime, but the imaginary parts of the input wfn and all gate unitary operators will be discarded without checking. In these cases, the user is responsible for ensuring that the circuit works on O(2^N) rather than U(2^N) and that the output is valid. (default - np.complex128)

Returns

output, scratch - output statevector, then scratch statevector

Return type

np.ndarray, shape 2**N

copy()

Make a deep copy of the current Gate.

Returns

a copy of this Gate whose parameters may be modified without modifying the parameters of self.

Return type

Gate

property is_composite

Is this Gate quasar.circuit.CompositeGate (containing subgates) (always False)

Type

bool

property is_controlled

Is this Gate quasar.circuit.ControlledGate (containing controls + Gate) (always False)

Type

bool

property nparameter

Total number of parameters in this Gate

Type

int

property ntime

Number of time indices occupied by this Gate (always 1)

Type

int

property operator

The (2**N,)*2 operator (unitary) matrix underlying this Gate, built from the current parameter state.

The action of the gate on a given state is given graphically as,

\[| \Psi > -G- | \Psi' >\]

and mathematically as,

\[| \Psi_I' > = \sum_J U_IJ | \Psi_J >\]
Type

np.ndarray, shape (2**N,)*2

set_parameter(key, value)

Set the value of a parameter of this Gate. The result is self.parameters[key] = value.

Parameters
  • key (str) – the key of the parameter

  • value (float) – the value of the parameter

Raises

RuntimeError – if the Gate does not have a parameter corresponding to key.

set_parameters(parameters)

Set the values of multiple parameters of this Gate. self.parameters is updated with the contents of parameters by calling self.set_parameter for each key/value pair.

Parameters

(dict of str (parameters) – float): dict of parameter values

test_operator_equivalence(gate2, operator_tolerance=1e-12)

Test if the operator matrices of two gates are numerically equivalent to within a maximum absolute derivation of operator_tolerance.

Note that the gates might still have different recipes, but produce the same operator. Therefore, this definition should be considered to be an intermediate level of equivalence.

Parameters
  • gate1 (Gate) – first gate to compare

  • gate2 (Gate) – second gate to compare

  • operator_tolerance (float) – maximum absolute deviation threshold for declaring Gate operator matrices to be identical. (default - 1.0E-12)

Returns

True` if the gates are equivalent under the definition above, else False.

Return type

bool

classmethod unchecked_gate(nqubit, operator_function, parameters, name, ascii_symbols, involutary=False, adjoint_function=None)

Creates a gate by forcibly bypassing all validation checks, to increase performance in cases where the gate is known to be valid (for example, creation of “stock” gates or serialization)

class quasar.circuit.Matrix

Class Matrix holds several common matrices encountered in quantum circuits.

These matrices are stored in np.ndarray with dtype=np.complex128.

The naming/ordering of the matrices in Quasar follows that of Nielsen and Chuang, except that rotation matrices are specfied in full turns:

Rz(theta) = exp(-i*theta*Z)

whereas Nielsen and Chuang define these in half turns:

Rz^NC(theta) = exp(-i*theta*Z/2)

CCX = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]])

The 3-qubit CCX (Toffoli) matrix

CS = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+1.j]])

The 2-qubit CS (controlled-S) matrix

CST = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 0.+0.j, -0.-1.j]])

The 2-qubit CS^+ (controlled-S-adjoint) matrix

CSWAP = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

The 3-qubit CSWAP (Fredkin) matrix

CX = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]])

The 2-qubit CX (controlled-X) matrix

CY = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 0.+0.j, -0.-1.j], [ 0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]])

The 2-qubit CY (controlled-Y) matrix

CZ = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j]])

The 2-qubit CZ (controlled-Z) matrix

static G(theta=0.0)

The 2-qubit Givens matrix

Params:

theta (float) - rotation angle.

Returns

(np.ndarray) - G matrix for the specified value of theta.

H = array([[ 0.70710678+0.j, 0.70710678+0.j], [ 0.70710678+0.j, -0.70710678+0.j]])

The 1-qubit H (Hadamard) matrix

I = array([[1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j]])

The 1-qubit I (identity) matrix

II = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

The 2-qubit I \(\otimes\) I matrix

IX = array([[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]])

The 2-qubit I \(\otimes\) X matrix

IY = array([[0.+0.j, 0.-1.j, 0.+0.j, 0.-0.j], [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.-0.j, 0.+0.j, 0.-1.j], [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]])

The 2-qubit I \(\otimes\) Y matrix

IZ = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j], [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, -0.+0.j, 0.+0.j, -1.+0.j]])

The 2-qubit I \(\otimes\) Z matrix

static PX(theta=0.0)

The 4-qubit pair-exchange gate.

4-qubit Givens rotation.

Params:

theta (float) - rotation angle.

Returns

(np.ndarray) - PX matrix for the specified value of theta.

static Rx(theta=0.0)

The 1-qubit Rx (rotation about X) matrix

Defined as,

U = exp(-i*theta*X)

Parameters

theta (float) – rotation angle (default - 0.0)

Returns

Rx matrix for the specified value of theta

Return type

np.ndarray

Rx2 = array([[0.70710678+0.j , 0. +0.70710678j], [0. +0.70710678j, 0.70710678+0.j ]])

The 1-qubit Z -> Y basis transformation matrix (a specific Rx matrix)

Rx2T = array([[0.70710678+0.j , 0. -0.70710678j], [0. -0.70710678j, 0.70710678+0.j ]])

The 1-qubit Y -> Z basis transformation matrix (a specific Rx matrix)

static Ry(theta=0.0)

The 1-qubit Ry (rotation about Y) matrix

Defined as,

U = exp(-i*theta*Y)

Parameters

theta (float) – rotation angle (default - 0.0)

Returns

Ry matrix for the specified value of theta

Return type

np.ndarray

static Rz(theta=0.0)

The 1-qubit Rz (rotation about Z) matrix

Defined as,

U = exp(-i*theta*Z)

Parameters

theta (float) – rotation angle (default - 0.0)

Returns

Rz matrix for the specified value of theta

Return type

np.ndarray

S = array([[1.+0.j, 0.+0.j], [0.+0.j, 0.+1.j]])

The 1-qubit S (Phase) matrix

ST = array([[ 1.+0.j, 0.+0.j], [ 0.+0.j, -0.-1.j]])

The 1-qubit S^+ (Phase adjoint) matrix

SWAP = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])

The 2-qubit SWAP matrix

T = array([[1. +0.j , 0. +0.j ], [0. +0.j , 0.70710678+0.70710678j]])

The 1-qubit T (sqrt-S) matrix

TT = array([[1. +0.j , 0. +0.j ], [0. +0.j , 0.70710678-0.70710678j]])

The 1-qubit T (sqrt-S-adjoint) matrix

X = array([[0.+0.j, 1.+0.j], [1.+0.j, 0.+0.j]])

The 1-qubit X (NOT) matrix

XI = array([[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]])

The 2-qubit X \(\otimes\) I matrix

XX = array([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

The 2-qubit X \(\otimes\) X matrix

XY = array([[0.+0.j, 0.-0.j, 0.+0.j, 0.-1.j], [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j], [0.+0.j, 0.-1.j, 0.+0.j, 0.-0.j], [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j]])

The 2-qubit X \(\otimes\) Y matrix

XZ = array([[ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, -0.+0.j, 0.+0.j, -1.+0.j], [ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j]])

The 2-qubit X \(\otimes\) Z matrix

Y = array([[ 0.+0.j, -0.-1.j], [ 0.+1.j, 0.+0.j]])

The 1-qubit Y matrix

YI = array([[0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j], [0.+0.j, 0.+0.j, 0.-0.j, 0.-1.j], [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j]])

The 2-qubit Y \(\otimes\) I matrix

YX = array([[0.+0.j, 0.+0.j, 0.-0.j, 0.-1.j], [0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j], [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j], [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j]])

The 2-qubit Y \(\otimes\) X matrix

YY = array([[ 0.+0.j, 0.-0.j, 0.-0.j, -1.+0.j], [ 0.+0.j, 0.+0.j, 1.-0.j, 0.-0.j], [ 0.+0.j, 1.-0.j, 0.+0.j, 0.-0.j], [-1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])

The 2-qubit Y \(\otimes\) Y matrix

YZ = array([[ 0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j], [ 0.+0.j, -0.+0.j, 0.-0.j, 0.+1.j], [ 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, -0.-1.j, 0.+0.j, -0.+0.j]])

The 2-qubit Y \(\otimes\) Z matrix

Z = array([[ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j]])

The 1-qubit Z matrix

ZI = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j], [ 0.+0.j, 0.+0.j, -0.+0.j, -1.+0.j]])

The 2-qubit Z \(\otimes\) I matrix

ZX = array([[ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, -0.+0.j, -1.+0.j], [ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j]])

The 2-qubit Z \(\otimes\) X matrix

ZY = array([[ 0.+0.j, 0.-1.j, 0.+0.j, 0.-0.j], [ 0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.-0.j, -0.+0.j, 0.+1.j], [ 0.+0.j, 0.+0.j, -0.-1.j, -0.+0.j]])

The 2-qubit Z \(\otimes\) Y matrix

ZZ = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j, 0.+0.j, -0.+0.j], [ 0.+0.j, 0.+0.j, -1.+0.j, -0.+0.j], [ 0.+0.j, -0.+0.j, -0.+0.j, 1.-0.j]])

The 2-qubit Z \(\otimes\) Z matrix