I’ve reviewed the Qermit-based mitigation module and identified several key issues and clean-ups

Open
#280 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
python

Research direction

Start with the label_gates, str_to_pauli_op, wrap_frame_gates, and clifford_canonical_F functions, plus the place_with_map and add_circuit call sites described in the issue. Apply the listed corrections and run the unit tests around label_gates, wrapping logic, and QubitPauliString expectations; done means those tests pass with the proposed behavior.

Written by the indexing model from the issue text.

Description

Here are the proposed corrections—each illustrated with the minimal changed snippet—so you can integrate them directly.

Fixes by Jesus Carrasco

1. Fixing the “TK1” membership test in label_gates

Problem:

if labelled_command["op"]["type"] in ("TK1"):

This checks membership in the string "TK1" (i.e. {"T","K","1"}) rather than the OpType.

Correction:

from pytket.circuit import OpType

# …

if labelled_command["op"]["type"] == OpType.TK1:
    labelled_command["opgroup"] = f"Computing {comp_count}"
    comp_count += 1
elif labelled_command["op"]["type"] == OpType.CX:
    labelled_command["opgroup"] = f"Frame {frame_count}"
    frame_count += 1
else:
    raise RuntimeError(
        'Expected only TK1 or CX gates—please rebase first with PECRebase.'
    )

2. Consistent “noop” creation for identity Pauli

Problem:
In str_to_pauli_op and in wrapping frames, raw dicts and "noop" strings are used.

Correction:

def str_to_pauli_op(pauli_str: str) -> Op:
    assert pauli_str in ["I", "X", "Y", "Z"]
    mapping = {
        "I": OpType.Noop,
        "X": OpType.X,
        "Y": OpType.Y,
        "Z": OpType.Z,
    }
    return Op.create(mapping[pauli_str])

And in wrap_frame_gates, replace the manual dict with:

identity_op = Op.create(OpType.Noop)
# …
labelled_EM_command = {
    "op": identity_op.to_dict()["op"],
    "args": [arg],
    "opgroup": f"pre Pauli {frame_number} {qubit_i}"
}

3. Mapping qubits correctly (use Qubit, not Node)

Problem:

n_q_map[cc_qns[i]] = Node("q", i)

tket’s place_with_map expects Qubit-to-Qubit maps, not architecture Nodes.

Correction:

from pytket.unit_id import Qubit

# …

n_q_map = { old_q: Qubit(i) for i, old_q in enumerate(rand_cliff_circ.qubits) }
# Then use place_with_map(rand_cliff_circ, n_q_map)

4. Avoid reassigning circ.add_circuit (it returns None)

Problem:

circ = circ.add_circuit(cliff_circ, [...], [])

add_circuit mutates in place and returns None.

Correction:

circ.add_circuit(cliff_circ, list(range(n_qubits)), [])

5. Ensure full Pauli mapping in clifford_canonical_F

Problem: The doc said pauli_layer in {0,1,2,3}, but the code only handled 0,1,2.

Correction:

for i, gate in enumerate(pauli_layer):
    if gate == 1:        circ.X(i, opgroup="Clifford 1")
    elif gate == 2:      circ.Y(i, opgroup="Clifford 1")
    elif gate == 3:      circ.Z(i, opgroup="Clifford 1")
    # gate == 0: identity—no action

Next Steps

  1. Apply these patches into your module where indicated.
  2. Run your unit tests (especially around label_gates, wrapping logic, and your QubitPauliString expectations).
  3. Let me know if you encounter any lingering errors or need further refinements—happy to dive deeper.
Dominant language
Python
Stars
49
Forks
12
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Quantinuum/Qermit

All issues in Quantinuum/Qermit

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.