expand_fragment_tapes_mc(tapes, communication_graph, shots)[source]

Expands fragment tapes into a sequence of random configurations of the contained pairs of MeasureNode and PrepareNode operations.

For each pair, a measurement is sampled from the Pauli basis and a state preparation is sampled from the corresponding pair of eigenstates. A settings array is also given which tracks the configuration pairs. Since each of the 4 measurements has 2 possible eigenvectors, all configurations can be uniquely identified by 8 values. The number of rows is determined by the number of cuts and the number of columns is determined by the number of shots.


This function is designed for use as part of the sampling-based circuit cutting workflow. Check out the cut_circuit_mc() transform for more details.

  • tapes (Sequence[QuantumTape]) – the fragment tapes containing MeasureNode and PrepareNode operations to be expanded

  • communication_graph (nx.MultiDiGraph) – the communication (quotient) graph of the fragmented full graph

  • shots (int) – number of shots


the tapes corresponding to each configuration and the settings that track each configuration pair

Return type

Tuple[List[QuantumTape], np.ndarray]


Consider the following circuit that contains a sample measurement:

ops = [
    qml.CNOT(wires=[0, 1]),
    qml.CNOT(wires=[1, 2]),
measurements = [qml.sample(wires=[0, 1, 2])]
tape = qml.tape.QuantumTape(ops, measurements)

We can generate the fragment tapes using the following workflow:

>>> g = qml.transforms.qcut.tape_to_graph(tape)
>>> qml.transforms.qcut.replace_wire_cut_nodes(g)
>>> subgraphs, communication_graph = qml.transforms.qcut.fragment_graph(g)
>>> tapes = [qml.transforms.qcut.graph_to_tape(sg) for sg in subgraphs]

We can then expand over the measurement and preparation nodes to generate random configurations using:

>>> configs, settings = qml.transforms.qcut.expand_fragment_tapes_mc(tapes, communication_graph, 3)
>>> print(settings)
[[1 6 2]]
>>> for i, (c1, c2) in enumerate(zip(configs[0], configs[1])):
...     print(f"config {i}:")
...     print(c1.draw())
...     print("")
...     print(c2.draw())
...     print("")

config 0:
0: ──H─╭●─┤  Sample[|1⟩⟨1|]
1: ────╰X─┤  Sample[Z]

1: ──I─╭●─┤  Sample[|1⟩⟨1|]
2: ────╰X─┤  Sample[|1⟩⟨1|]

config 1:
0: ──H─╭●─┤  Sample[|1⟩⟨1|]
1: ────╰X─┤  Sample[Y]

1: ──H──S─╭●─┤  Sample[|1⟩⟨1|]
2: ───────╰X─┤  Sample[|1⟩⟨1|]

config 2:
0: ──H─╭●─┤  Sample[|1⟩⟨1|]
1: ────╰X─┤  Sample[Y]

1: ──X──H──S─╭●─┤  Sample[|1⟩⟨1|]
2: ──────────╰X─┤  Sample[|1⟩⟨1|]