Skip to content

Highlight graph changes per rewrite step in proof view #190#448

Open
dorakingx wants to merge 9 commits intozxcalc:masterfrom
dorakingx:feature/issue-190-highlight-rewrites
Open

Highlight graph changes per rewrite step in proof view #190#448
dorakingx wants to merge 9 commits intozxcalc:masterfrom
dorakingx:feature/issue-190-highlight-rewrites

Conversation

@dorakingx
Copy link

This PR introduces visual highlighting of nodes and edges that change between consecutive proof steps, making it easier to see what each rewrite did.

  • Rewrite diff highlighting

    • When a proof step is selected, the app now computes a GraphDiff between that step’s graph and the previous one (ProofStepView.move_to_step in proof.py).
    • Newly added or modified vertices (new_verts, changed_vertex_types, changed_phases, changed_vdata, changed_pos) and edges (new_edges, changed_edata, changed_edge_types) are collected and passed to the scene as “highlight sets”.
  • Rendering changes

    • GraphScene now maintains sets of highlighted vertices and edges and exposes:
      • set_rewrite_highlight(verts, edges)
      • clear_rewrite_highlight()
      • is_vertex_highlighted(v) / is_edge_highlighted(e)
    • VItem.refresh uses these flags to draw highlighted vertices with a thicker, accent-colored outline (different colors for light/dark mode).
    • EItem.refresh similarly draws highlighted edges with a thicker, accent-colored pen while preserving existing styling (e.g. Hadamard dash patterns).
  • Behavior

    • Selecting the first step (START) clears all highlighting.
    • Selecting a later step highlights exactly the changes between that step and the previous one.
    • As new rewrite steps are added or the user navigates through the proof, the highlight automatically updates to match the currently selected step.

You can verify the behavior by opening a proof, applying a few rewrite steps, and moving up and down the step list: only the nodes and edges affected by the selected rewrite should be emphasized.

@boldar99
Copy link
Collaborator

Thanks for the PR,
I have done some basic testing and this doesn't seem to be working properly; see the video below.
Also the lint checks are failing.

Screen.Recording.2026-02-26.at.17.47.29.mov

@dorakingx
Copy link
Author

Thanks for the detailed feedback and the video! It was incredibly helpful.
I have thoroughly investigated the issues and made the following updates to ensure the highlighting works perfectly:

  1. Fixed the Undo bug:
    The highlights now clear immediately and correctly when performing an Undo. I explicitly wired the undo stack to trigger the UI refresh (move_to_step), ensuring the visual state always matches the internal proof state.

  2. Fixed semantic highlighting (Option C: wrong nodes lighting up):
    Previously, pyzx aggressively shuffled vertex IDs during rewrites, which tricked the naive ID-based diffing into highlighting unrelated wires. To fix this, I abandoned ID diffing and implemented a robust coordinate-based tracking (qubit, row).
    Now, ONLY the semantically changed nodes and their incident edges light up. I have ensured this robust logic is applied across all interaction paths:

    • Manual rule application from the menu
    • Drag-and-drop operations
    • The Magic Wand tool
  3. Fixed lint checks:
    All linting and formatting errors have been fully resolved.

Note on the temporary layout overlap (Drag-and-Drop):
During testing, I noticed that immediately after applying a complex rewrite (like Pivot) via drag-and-drop, the nodes temporarily overlap. However, if you trigger an Undo and Redo, the graph layout is restored perfectly. Based on the logs, the underlying graph state is completely correct; the UI just isn't fully recalculating the layout immediately after the initial drag action. Since this seems to be a pre-existing structural issue with how the scene refreshes after complex rewrites, I left it as-is to avoid expanding the scope of Issue #190. I'd be happy to look into this in a separate PR if needed!

I have attached a new video showing the corrected highlighting behavior across different operations. Could you please take another look when you have time?

Screen.Recording.2026-02-28.at.3.32.50.mov

@lia-approves
Copy link
Collaborator

First, we would like the rewrites to highlight the next change in each proof step, rather than the previous. This is because the person doing the proof knows what they've just changed, but looking back at the proof it's helpful to see what was changed between proof steps.

Instead of highlighting all edges of spiders involved in the latest rewrite rule, the intended behavior is to only highlighted the subset of those spiders' edges that were changed. For example, for spider fusion, the only edge highlighted should be the edge between the two spiders being fused, not their other edges.

Lastly, it should be possible to toggle the highlighting on and off in the GUI settings.

…dent_edges

- Add highlight_match_pairs to Rewrite/AddRewriteStep for MATCH_DOUBLE rules
- In move_to_step, when match pairs exist, find fusion edge via incident_edges(v1) instead of g.edges(v1,v2)
- Pass match pairs from rewrite_action (tree) and proof_panel (drag-drop) for fuse
- Add highlight toggle in settings; update test for next-change semantics

Made-with: Cursor
…tices

- Add highlight_unfuse_verts to Rewrite and AddRewriteStep for unfuse steps
- Unfuse branch: highlight vertices from highlight_unfuse_verts that exist in current graph
- When both split vertices exist (viewing after unfuse), highlight edge between them
- Avoid coordinate-based path for unfuse so extra vertices at same coords are not highlighted

Made-with: Cursor
@dorakingx
Copy link
Author

Thanks again for the excellent feedback and the survey! The guidance on forward-looking highlights and precise edge selection was incredibly helpful and greatly improved the feature.

I have pushed a new update that fully implements your requested design changes, along with a final fix for the Magic Wand tool. Here is a summary of the latest updates:

  1. Forward Highlighting (Next Change): As requested, the UI now previews the next rewrite. When viewing step i (e.g., START), the graph now highlights the specific vertices and edges that will be modified or consumed in the transition to step i+1.

  2. Precise Edge & Vertex Highlighting: I updated the logic to strictly highlight the affected spiders AND ONLY the subset of edges actually involved in the rewrite. For example, during a Spider Fusion, only the two spiders and the single edge connecting them are highlighted. All external incident edges are left untouched.

  3. GUI Toggle Setting: I have added a checkable action to the application's top menu bar (e.g., under the View menu). Users can now easily toggle the rewrite highlighting on and off whenever they want.

  4. Magic Wand (Unfuse) Fix: I fixed a lingering issue where using the Magic Wand for unfusion occasionally highlighted unrelated nodes due to pyzx vertex ID shuffling. It now accurately tracks and highlights only the selected/split vertices and their specific edges.

I have attached a short video/screenshots demonstrating the refined highlighting across manual operations, drag-and-drop, the Magic Wand, and the new toggle setting in action.

Could you please take another look when you have a chance? Let me know if there's anything else you'd like me to adjust!

Screen.Recording.2026-02-28.at.10.10.58.mov

@RazinShaikh
Copy link
Collaborator

Thanks, it looks better. Before we go ahead and review this further, could you please make your PR as minimal as possible and it changes only what's necessary? Currently it has over 800 new lines and I am not sure if all of those are necessary. Such big PRs are hard to review especially since we are reaching the end of the hackathon.

… comp/remove id; optimize (merge unfuse into highlight_verts, add _edges_between)

Made-with: Cursor
@dorakingx
Copy link
Author

dorakingx commented Feb 28, 2026

Thanks for the feedback. I've reduced the PR so it only includes what's needed for the feature.

What I changed:

  • Removed all coordinate-based tracking (highlight_coords), the GraphDiff-based fallback, and any layout_coords logic.
  • Removed all temporary debug print/logging used during development.
  • Simplified the data model: dropped highlight_unfuse_verts and now use a single highlight_verts path for unfuse, color change, strong complementarity, remove identity, etc. Match-based rules (e.g. Spider Fusion) still use highlight_match_pairs only.
  • Refactored duplicate "edges between two vertices" logic into a single _edges_between helper and removed an unused g_next graph copy.

Current size:

The branch is now ~455 insertions and ~61 deletions vs master (net +394 lines), not 800+. The diff is limited to the files that need to change for forward-looking highlights, the GUI toggle, and the above cleanups.

If you’d like it even smaller, I can trim further (e.g. fewer comments or a more minimal test). Tell me which parts you’d prefer to see reduced and I’ll adjust.

@RazinShaikh
Copy link
Collaborator

Thanks, the size looks more reasonable now. Will have a look at it soon

@RazinShaikh
Copy link
Collaborator

RazinShaikh commented Feb 28, 2026

@dorakingx I am still finding it difficult to understand the changes you have made in the code. Can you explain and summarize what you did? And the lint check is failing right now; can you please fix that?

…nds.py, type ignore setColorScheme in app.py

Made-with: Cursor
@dorakingx
Copy link
Author

dorakingx commented Feb 28, 2026

@RazinShaikh Here is the summary. And I fixed the lint check error.

Summary of changes

What this PR does

This PR adds forward-looking rewrite highlighting in proof mode: when you select a proof step, the graph highlights what will change in the next step (the vertices and edges affected by that rewrite), instead of what changed in the previous one. It also adds a GUI toggle to turn this highlighting on or off, and ensures only the relevant vertices/edges are highlighted (no coordinate drift or unrelated nodes).


1. Highlight behaviour

  • Forward-looking: Step i shows the graph at i and highlights the transition to step i+1 (the next rewrite).
  • Semantic, not structural: We no longer use a generic graph diff. We store a small amount of metadata when a rewrite is applied and use that to highlight:
    • Match-based (e.g. Spider Fusion): we store highlight_match_pairs — the vertex pairs (v1, v2) that were matched. When displaying the step, we highlight those two vertices and only the edge between them.
    • Vertex-based (unfuse, color change, strong complementarity, remove identity, etc.): we store highlight_verts — the vertex IDs involved. We highlight those vertices and, if there are exactly two, only the edge between them; otherwise all incident edges.

So the logic is: “when this step was created, we recorded which vertices (and for fuse, which pair) were involved; when we show this step, we highlight those in the current graph.”


2. Where metadata is set

  • Rewrite tree / drag-and-drop
    In rewrite_action.py, when the “Fuse spiders” rule is applied we set highlight_match_pairs from the match (v1, v2).
    In proof_panel.py, drag-and-drop and double-click handlers set highlight_match_pairs or highlight_verts (e.g. “Fuse spiders” → [(v,w)], “Strong complementarity” → [v,w], “Color change” / “Remove identity” → [v], “unfuse” → list of split vertex IDs).

  • Commands
    AddRewriteStep in commands.py takes optional highlight_match_pairs and highlight_verts and passes them into the new Rewrite stored in the proof model.

  • Proof model
    Each Rewrite in proof.py can carry highlight_match_pairs and highlight_verts. When the user selects a step, ProofStepView.move_to_step uses this metadata to compute the sets of vertices and edges to highlight and calls scene.set_rewrite_highlight(verts, edges).


3. GUI toggle

  • View menu: “Show rewrite highlights” checkable action; toggling it turns highlighting on/off and persists the setting.
  • Preferences: “Highlight rewrite steps” in the General tab (same setting).
  • When the setting is off, move_to_step clears the highlight and does not apply any of the above logic. When the setting is changed (from the menu or Preferences), the current step’s highlight is refreshed so the graph updates immediately.

4. Lint fixes (mypy)

  • proof.py: Resolved no-redef for the edge set used in the vertex-based branch by introducing a single edges_highlight variable and assigning it in the two branches (either from _edges_between or by building the set of incident edges).
  • commands.py: AddRewriteStep.step_view is now typed as ProofStepView instead of QListView, so mypy recognizes move_to_step.
  • app.py: Added # type: ignore[attr-defined] for setColorScheme on QStyleHints so that mypy zxlive passes (stubs may not define it yet).

Files touched (overview)

File Role
zxlive/proof.py Rewrite metadata; move_to_step highlight logic; _edges_between helper; settings check.
zxlive/commands.py AddRewriteStep carries and passes highlight metadata; typed as ProofStepView.
zxlive/proof_panel.py Sets highlight_match_pairs / highlight_verts when creating rewrite steps (drag-drop, double-click, Magic Wand, unfuse).
zxlive/rewrite_action.py Sets highlight_match_pairs for “Fuse spiders” from the rewrite tree.
zxlive/graphscene.py set_rewrite_highlight / clear_rewrite_highlight; scene stores and uses highlighted verts/edges.
zxlive/vitem.py / zxlive/eitem.py Drawing uses scene’s highlight state for vertices and edges.
zxlive/mainwindow.py View menu toggle and refresh_rewrite_highlight().
zxlive/settings.py / zxlive/settings_dialog.py “Highlight rewrite steps” setting and persistence.
test/test_highlight.py Test that step selection and toggle affect highlights correctly.

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.

4 participants