Skip to content

Fix #324: use match for better readability and typing#434

Open
thierry-martinez wants to merge 2 commits intoTeamGraphix:masterfrom
thierry-martinez:fix/324_match
Open

Fix #324: use match for better readability and typing#434
thierry-martinez wants to merge 2 commits intoTeamGraphix:masterfrom
thierry-martinez:fix/324_match

Conversation

@thierry-martinez
Copy link
Collaborator

This commit replaces if/elif/else chains with match when the conditions perform equality comparisons on the same subject. These changes improve readibility and avoid mypy shortcomings related to type narrowing.

Before this commit, PLR1714 suggested rewriting code such as:

if cmd.kind == CommandKind.X or cmd.kind == CommandKind.Z: ...

into:

if cmd.kind in {CommandKind.X, CommandKind.Z}: ...

However, mypy does not currently infer that cmd is an instance of X or Z within the if block when set membership is used.

With this commit, the condition is expressed using an or-pattern, and type checking behaves as expected:

match cmd.kind:
    case CommandKind.X | CommandKind.Z: ...

This commit replaces `if`/`elif`/`else` chains with `match` when the
conditions perform equality comparisons on the same subject. These
changes improve readibility and avoid `mypy` shortcomings related to
type narrowing.

Before this commit, PLR1714 suggested rewriting code such as:

```python
if cmd.kind == CommandKind.X or cmd.kind == CommandKind.Z: ...
```

into:

```python
if cmd.kind in {CommandKind.X, CommandKind.Z}: ...
```

However, `mypy` does not currently infer that `cmd` is an instance of
`X` or `Z` within the `if` block when set membership is used.

With this commit, the condition is expressed using an or-pattern, and
type checking behaves as expected:

```python
match cmd.kind:
    case CommandKind.X | CommandKind.Z: ...
```
@codecov
Copy link

codecov bot commented Feb 15, 2026

Codecov Report

❌ Patch coverage is 77.47253% with 164 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.33%. Comparing base (be598e2) to head (93dc830).

Files with missing lines Patch % Lines
graphix/flow/exceptions.py 0.00% 61 Missing ⚠️
graphix/sim/tensornet.py 52.00% 24 Missing ⚠️
graphix/optimization.py 77.01% 20 Missing ⚠️
graphix/pattern.py 86.04% 18 Missing ⚠️
graphix/transpiler.py 92.68% 12 Missing ⚠️
graphix/qasm3_exporter.py 85.29% 10 Missing ⚠️
graphix/graphsim.py 73.68% 5 Missing ⚠️
graphix/simulator.py 76.19% 5 Missing ⚠️
graphix/flow/core.py 87.87% 4 Missing ⚠️
graphix/noise_models/depolarising.py 86.66% 2 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #434      +/-   ##
==========================================
- Coverage   86.72%   86.33%   -0.40%     
==========================================
  Files          44       44              
  Lines        6163     6243      +80     
==========================================
+ Hits         5345     5390      +45     
- Misses        818      853      +35     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@emlynsg emlynsg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've suggested additional places to replace if else with match. Happy to discuss.
I also found a few other locations:

  • ops.py from L221
  • pauli.py from L71 (eigenstate and _repr_impl and _matmul_impl functions).

circuit = Circuit(width=self.width)
for instr in self.instruction:
if instr.kind == InstructionKind.M:
if instr.axis == Axis.X:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor but slight readability improvement:

match instr.axis:
    case Axis.X:
        circuit.h(instr.target)
        circuit.m(instr.target, Axis.Z)
    case Axis.Y:
        circuit.rx(instr.target, ANGLE_PI / 2)
        circuit.m(instr.target, Axis.Z)
    case _:
        circuit.add(instr)

Could possibly do the same to the outer if else.

else:
raise ValueError(f"invalid command {cmd}")
yield f"h q{cmd.node};\n"
if cmd.angle != 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar here:

match cmd.plane:
    case Plane.XY:
        gate = "rx"
        angle = -cmd.angle
    case Plane.XZ:
        gate = "ry"
        angle = -cmd.angle
    case Plane.YZ:
        gate = "rx"
        angle = cmd.angle
    case _:
        assert_never(cmd.plane)

non_pauli_list.append(
command.M(node=cmd.node, angle=cmd.angle, plane=cmd.plane, s_domain=s_domain, t_domain=t_domain)
)
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can change to match here

target = self._find_op_to_be_moved(CommandKind.S, rev=True)
continue
cmd = self.__seq[target + 1]
kind = cmd.kind
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can replace these with match too

pm = PauliMeasurement.try_from(cmd.plane, cmd.angle) # None returned if the measurement is not in Pauli basis
if pm is not None:
# Pauli measurement to be removed
if pm.axis == Axis.X:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace with match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants