Skip to content

[Bug]: Multiple crash sites when running passes on Tket2 circuit from guppy #1632

@IlanIwumbwe

Description

@IlanIwumbwe

Description

  • Panic in commutation.rs, index error
  • Panic in badger.rs, optimisation failed
  • Semantics change when running FullPeepholeOptimise followed by RebasePass

Steps to Reproduce

Run the code below

import collections
import json

import hugr
from guppylang.decorator import guppy
from guppylang.emulator import EmulatorBuilder
from guppylang.std.builtins import array, result
from guppylang.std.quantum import h, measure_array, qubit
from pytket.circuit import OpType
from pytket.passes import AutoRebase, FullPeepholeOptimise, SequencePass
from tket._tket.passes import greedy_depth_reduce, normalize_guppy, tket1_pass
from tket.circuit import Tk2Circuit
from tket.optimiser import BadgerOptimiser
from tket.rewrite import default_ecc_rewriter


class guppyTesting:
    def __init__(self, circuit, circuit_name: str, _n_qubits: int) -> None:
        self.n_qubits = _n_qubits
        self.pkg = circuit.compile()
        self.hugr_envelope = self.pkg.modules[0].to_bytes()
        self.circuit_name = circuit_name

    def _get_counts(self, opt_level: int):
        tk2_circuit = Tk2Circuit.from_bytes(
            self.hugr_envelope, function_name=f"__main__.{self.circuit_name}"
        )

        tk2_circuit = normalize_guppy(tk2_circuit)

        if opt_level == 1:
            opt_circ, _ = greedy_depth_reduce(tk2_circuit)

        elif opt_level == 2:
            combined = SequencePass(
                [
                    FullPeepholeOptimise(),
                    AutoRebase({OpType.CX, OpType.H, OpType.Rz, OpType.Rx, OpType.Ry}),
                ]
            )
            # opt_circ = tket1_pass(tk2_circuit, json.dumps(FullPeepholeOptimise().to_dict()))
            opt_circ = tket1_pass(tk2_circuit, json.dumps(combined.to_dict()))
            opt_circ, _ = greedy_depth_reduce(opt_circ)

        elif opt_level >= 2:
            optimiser = BadgerOptimiser(default_ecc_rewriter())
            opt_circ = optimiser.optimise(tk2_circuit)

        else:
            opt_circ = tk2_circuit

        opt_hugr = hugr.Hugr().from_bytes(opt_circ.to_bytes())
        self.pkg.modules[0] = opt_hugr

        builder = EmulatorBuilder()
        instance = builder.build(self.pkg, self.n_qubits)
        run_job = instance.with_shots(100).run()

        counts = collections.Counter()

        for shot in run_job.results:
            # .as_dict() returns something like {'q1': 1, 'q2': 0} for each qubit
            shot_dict = shot.as_dict()
            ordered_keys = sorted(shot_dict.keys())

            binary_string = ""
            for key in ordered_keys:
                val = shot_dict[key]
                binary_string += str(val)

            counts[binary_string] += 1

        print(counts)


@guppy
def main_circuit() -> None:
    reg_236 = array(qubit() for _ in range(1))
    h(
        reg_236[0],
    )
    mz = measure_array(reg_236)
    result("res", mz[0])


gt = guppyTesting(main_circuit, "main_circuit", 1)
print(gt._get_counts(3))
  • get_counts(0): works fine, returns expected result Counter({'0': 51, '1': 49})
  • get_counts(1):
thread '<unnamed>' (263755) panicked at tket/src/passes/commutation.rs:84:39:
index out of bounds: the len is 0 but the index is 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/ilan/programming/QFpp/test.py", line 87, in <module>
    print(gt._get_counts(1))
          ^^^^^^^^^^^^^^^^^
  File "/home/ilan/programming/QFpp/test.py", line 32, in _get_counts
    opt_circ, _ = greedy_depth_reduce(tk2_circuit)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pyo3_runtime.PanicException: index out of bounds: the len is 0 but the index is 1
  • commenting the normalize_guppy call returns expected result Counter({'1': 52, '0': 48})

  • get_counts(2) with normalize_guppy returns the same index out of bounds error as above. Commenting out normalize_guppy seems to remove the H gate. Result obtained is Counter({'0':100}):

  • get_counts(3) with or without normalise_guppy returns

thread '<unnamed>' (265048) panicked at /home/runner/work/tket2/tket2/tket/src/optimiser/badger.rs:219:14:
optimisation failed
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/ilan/programming/QFpp/test.py", line 87, in <module>
    print(gt._get_counts(3))
          ^^^^^^^^^^^^^^^^^
  File "/home/ilan/programming/QFpp/test.py", line 47, in _get_counts
    opt_circ = optimiser.optimise(tk2_circuit)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pyo3_runtime.PanicException: optimisation failed

Expected Behaviour

No response

Actual Behaviour

No response

Component

No response

Environment

- tket version: 0.12.16
- OS: Ubuntu 24.03
- Python version: 3.12.3

Additional Context

Some of these may be because I am doing some unprincipled steps. Please me know if this is the case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugfixCategory: PR with bug fixS-needs-triageStatus: Needs to be labelled

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions