Skip to content

ECO: Add C++ Graph Edit Distance implementation with MCS optimization - #3813

Open
alirezazd wants to merge 37 commits into
google:mainfrom
alirezazd:mcs_ged
Open

alirezazd wants to merge 37 commits into
google:mainfrom
alirezazd:mcs_ged

Conversation

@alirezazd

@alirezazd alirezazd commented Feb 9, 2026 •

Copy link
Copy Markdown

This PR adds a C++ implementation of Graph Edit Distance (GED) for the ECO system, replacing the existing Python/NetworkX approach.

What's included

  • Core GED algorithm with LAP solver integration
  • MCS (Maximum Common Subgraph) preprocessing for performance (~10-100x speedup)
  • Graph data structures for representing XLS IR
  • CLI tool (ged_main) and IR patch generation
  • Bazel build rules and integration tests
  • Third-party dependencies organized in libs/ (tinyxml2, scipy_lap)

Regarding the new C++ GED

The Python version works but is slow on large graphs. This C++ implementation is faster, integrates directly with XLS IR APIs, and supports advanced features like pinned nodes and MCS optimization.

Migration

Python tools (ir_diff_main.py, ir2gxl.py) are marked for deprecation but still functional. They'll be removed in a future PR once the C++ version is proven stable.

Testing

Builds cleanly and includes tests with real DSLX examples (crc32, apfloat_fmac, riscv_simple, etc).

@grebe Please consider reviewing this PR. I tried to organize it into separate commits for convenience.

@google-cla

google-cla Bot commented Feb 9, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@alirezazd
alirezazd force-pushed the mcs_ged branch 2 times, most recently from 167e123 to 24d50c2 Compare February 9, 2026 18:44
@erinzmoore
erinzmoore requested a review from grebe February 11, 2026 15:04

@grebe grebe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

First of all: thank you! This is exciting to see. Looks like a lot of good work and a big improvement.

Here's some initial feedback, I'm still working my way through. I think I have enough here to get the ball rolling, though, so I'm sending it out. Feel free to reach out directly or go back and forth here if anything I said was unclear or if you disagree.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deps shouldn't be under xls/, they should be managed from dependency_support/ or (ideally) BCR. tinyxml2 looks like it's in BCR. scipy_lsap.cpp is a bit trickier b/c our python deps aren't super well integrated into bazel (it's essentially pip installed, which afaik largely hides the internals). We typically try to avoid holding on to third_party/ source in here. I believe OR-tools has some implementations of linear assignment stuff and we already pull it in as a dep - is a pain to move to using it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I initially used OR-tools LASP solver but the performance took a hit. I'll do more experiments and will try to replace the external LSAP solver with something more convenient.

Regarding TinyXML, I think it would be nice to get rid custom parses (ir2nx, ir2gxl) and solely use XLS IR and generate graph directly from it before we merge this PR and after the current code is stable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re: using XLS IR, I think it's fine to land this w/ tinyxml as long as you use the BCR version, but agree it would be better not to have custom parsing.

Comment thread xls/eco/test/BUILD Outdated
Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/ged.h Outdated
Comment thread xls/eco/ged_main.cc Outdated
Comment thread xls/eco/ged_main.cc Outdated
Comment thread xls/eco/ged_main.cc Outdated
Comment thread xls/eco/ged_main.cc Outdated
Comment thread xls/eco/graph.cc Outdated
@alirezazd

Copy link
Copy Markdown
Author

@grebe Ready for next round of review. I addressed most of the comments but the cost functions are still in a separate header, if you prefer them to live inside ged header, I can move them in a follow-up commit.

@proppy
proppy requested a review from grebe March 3, 2026 07:07

@grebe grebe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice!

Comment thread xls/dev_tools/check_ir_equivalence_main.cc Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re: using XLS IR, I think it's fine to land this w/ tinyxml as long as you use the BCR version, but agree it would be better not to have custom parsing.

Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/ged.h Outdated
Comment thread xls/eco/ged_cost_functions.h Outdated
Comment thread xls/contrib/eco/ged_main.cc Outdated
Comment thread xls/eco/graph.h Outdated
@alirezazd

alirezazd commented Mar 6, 2026 •

Copy link
Copy Markdown
Author

@grebe comments applied, ready for more :)
@proppy previous CI issues (unavailble build targets) should be fixed now.

@grebe grebe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for the long wait.

Hopefully this isn't too annoying, but... I think it would be good to move this into contrib (xls/contrib/eco).

We're getting close!

Comment thread xls/eco/eco_build_defs.bzl Outdated
Comment thread xls/eco/graph.cc Outdated
Comment thread xls/eco/ir2nx.py Outdated
Comment thread xls/eco/ir_patch_gen.cc Outdated
Comment thread xls/contrib/eco/mcs.h
@alirezazd

alirezazd commented Apr 13, 2026 •

Copy link
Copy Markdown
Author

@grebe Sorry for late response I was busy with some academic tasks. I applied most of the recent comments, currently working on moving the xls/eco to xls/contrib/eco. Please consider reviewing again.

P.S. The test //xls/contrib/eco/test:vector_core_patched_opt_ir (~1k nodes) now completes in under 4 seconds with <220 MB RAM when MCS is enabled. :)

@alirezazd
alirezazd requested a review from grebe April 13, 2026 04:28

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should use BCR rather than checking this in

Comment thread xls/contrib/eco/codegen_scheduled_main.cc Outdated
@alirezazd

Copy link
Copy Markdown
Author

@grebe Do you have a preference here:

  1. Keep TinyXML and the existing Python tooling (parser, GED, patch generation, NetworkX), or
  2. Deprecate that stack in favor of xls/contrib/eco/xls_ir_to_cytoscape.cc?

Happy to go either way,

Comment thread xls/contrib/eco/lap_solver.cc
@grebe

grebe commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

@grebe Do you have a preference here:

  1. Keep TinyXML and the existing Python tooling (parser, GED, patch generation, NetworkX), or
  2. Deprecate that stack in favor of xls/contrib/eco/xls_ir_to_cytoscape.cc?

Happy to go either way,

I don't think xls_ir_to_cytoscape obviates the entire set of python tools, just the parser. Right? I weakly prefer to move to xls_ir_to_cytoscape, but don't think it needs to be a huge priority. Using TinyXML is fine, we just generally don't check in third-party code as it's easier to manage through bzlmod/BCR. It's possible you won't even need to update the include paths when switching to BCR.

@alirezazd

alirezazd commented Apr 25, 2026 •

Copy link
Copy Markdown
Author

@grebe Do you have a preference here:

  1. Keep TinyXML and the existing Python tooling (parser, GED, patch generation, NetworkX), or
  2. Deprecate that stack in favor of xls/contrib/eco/xls_ir_to_cytoscape.cc?

Happy to go either way,

I don't think xls_ir_to_cytoscape obviates the entire set of python tools, just the parser. Right? I weakly prefer to move to xls_ir_to_cytoscape, but don't think it needs to be a huge priority. Using TinyXML is fine, we just generally don't check in third-party code as it's easier to manage through bzlmod/BCR. It's possible you won't even need to update the include paths when switching to BCR.

actually the whole py part is now implemented in cpp, although getting rid of ir2gxl and the python parser (ir2nx) requires some work. I'll move TinyXML to BCR, for now but I highly recommend depreciating the Python side. I can do it in this PR or in a future PR.

FYI:

Python file Current role C++ counterpart / replacement status
ir_diff.py NetworkX GED algorithm ged.cc, ged_cost_functions.cc, lap_solver.cc, mcs.cc
ir_diff_main.py Old Python diff CLI ged_main.cc
ir_patch_gen.py Python patch proto generator ir_patch_gen.cc; patch application is patch_ir.cc / patch_ir_main.cc
ir2nx.py Regex IR parser to NetworkX Partially replaced by xls_ir_to_networkx.py + xls_ir_to_cytoscape.cc; still required by ir2gxl.py
ir2gxl.py IR-to-GXL exporter No complete C++ replacement yet; gxl_parser.cc parses GXL but does not export it
xls_ir_to_networkx.py C++ cytoscape JSON to NetworkX bridge Uses xls_ir_to_cytoscape.cc; only needed for old Python flow
xls_types.py Python regex type parser/proto conversion Replaced in C++ patch generation by XLS parser APIs in ir_patch_gen.cc
xls_values.py Python value parser/proto conversion Replaced in C++ by Parser::ParseTypedValue in ir_patch_gen.cc
ir_diff_utils.py Python visualization/report helpers No full C++ equivalent; ged_main.cc --report covers reporting only
*_test.py Python tests Remove/update with the Python targets they cover

@alirezazd

Copy link
Copy Markdown
Author

@grebe I went ahead and added direct XLS IR -> ECO graph conversion for the C++ GED flow.

The graph now carries typed XLS attributes (Op, TypeProto, ValueProto, NodeAttributes, etc.) instead of the previous string/GXL-derived attribute encoding, so diff and patch generation can consume XLS IR data directly without the ir2nx/irgxl compatibility path.

I can deprecate and remove the Python side completely in the next commit. If complete removal is not preferred, please let me know how you’d like to keep it.

@alirezazd
alirezazd requested a review from grebe May 5, 2026 11:17
@alirezazd
alirezazd force-pushed the mcs_ged branch 2 times, most recently from a369e65 to ceed0d3 Compare May 5, 2026 17:12
@alirezazd

Copy link
Copy Markdown
Author

@proppy could you please trigger the CI tests? Thanks!

@grebe grebe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, and sorry for the slow response. Yeah, if it's not too much work to remove the python, feel free.

Comment thread xls/contrib/eco/lap_solver.h Outdated
@grebe

grebe commented May 15, 2026

Copy link
Copy Markdown
Contributor

Some other feedback after chatting with @proppy:

  • Would you mind adding a readme?
  • Did you ever look at using a library for the graph data structures? I think or-tools has stuff there. It's ok if not, but I'm curious if you considered it.

@alirezazd

alirezazd commented May 28, 2026 •

Copy link
Copy Markdown
Author

@grebe @proppy

Sorry for the long delay, I was bogged down with academic tasks. Python side is now removed and everything is cpp. I also added a README.md. regarding the graph data structure choice:

no, didn't really look at or-tools for this.

XLSGraph isn't really a generic graph. Each node carries cost_attributes (op, type, literal, state info) plus a hash label that both the MCS candidate partitioning and the GED cost function read directly. Edges carry operand-position indices because Sub(a, b) ≠ Sub(b, a). And the MCS→GED handoff mutates the graph; boundary pairs get pinned, interior matches get cut, with an original↔current index map kept around. or-tools' fast graphs are CSR-style, immutable, and indexed by (source, target) only, so we'd be carrying all the payload in side-arrays and reimplementing the mutation API. At that point the wrapper is the graph.

summary: or-tools is not MCS or GED aware and I wanted minimal and controllable overhead so I opted in with a custom graph data structure.

- Replace requirement() with @xls_pip_deps// for old Python tools
- Update Receive node construction to match new upstream API signature
- Add payload_type parameter required by new Receive constructor
This commit contains two types of changes:
1. Upstream updates to ir2nx.py merged during rebase (large diff)
2. Our deprecation TODOs added to Python GED toolchain:
   - ir_diff.py: NetworkX GED → ged.h/cc (10-100x faster)
   - ir_diff_main.py: Python tool → ged_main.cc CLI
   - ir_patch_gen.py: Python patcher → patch_ir.h/cc
   - ir2nx.py: NetworkX converter → xls_ir_to_cytoscape.cc
   - ir2gxl.py: GXL exporter → gxl_parser.h/cc (from upstream)
Replace the SciPy LSAP path with a native C++ LSAP solver.
Switch GED cost construction from sparse-style handling to dense matrix paths.

Add C++ ECO components for GED, MCS, graph modeling, GXL parsing, and patch generation.
Introduce eco-specific Starlark build defs and wire patching plus equivalence validation targets.

Standardize main-flag handling and add optional execution statistics reporting.

Add ECO regression fixtures and test targets for crc32, riscv, apfloat, fir, histogram, and vector_core flows.
Use path-based equivalence report flag and write reports for mismatch results
Replace run_shell wrapper with direct Bazel run
Remove short flag aliases from patch_ir_main
Normalize ECO build rule args/report handling and clean stale target references
 Fixed  init parsing bug in IrParser
 Fixed a critical  bug  in MakePruneFunction
Relocate the ECO package from xls/eco to xls/contrib/eco and update references.

This includes Bazel labels, Starlark loads, C++ include paths, Python imports, runfiles paths, and tooling path filters.
- Updated `ir_diff_main.py` to reflect direct XLS IR parsing.
- Extended `ir_patch.proto` with new fields: message, label, format, and verbosity.
- Modified `ir_patch_gen.cc` to handle new attributes for assert and trace operations.
- Enhanced `ir_patch_gen.py` to merge node attributes and parse additional fields.
- Implemented `xls_ir_to_graph.cc` and `xls_ir_to_graph.h` for converting XLS IR to graph representation.
- Added tests in `xls_ir_to_graph_test.cc` to validate graph conversion and debug node inclusion.
- Cleaned up `patch_ir.cc` to handle assert and trace nodes directly in the IR graph.
- Introduced NodeCostAttributes and EdgeCostAttributes structs to encapsulate node and edge cost attributes, replacing string-based representations.
- Updated XLSNode and XLSEdge to use the new attribute structs.
- Modified the IR patch generation code to populate and utilize the new cost attribute structures.
- Enhanced the xls_ir_to_graph conversion to construct NodeCostAttributes directly from IR nodes.
- Updated tests to validate the new structure and ensure correct attribute handling.
The Python diff/patch tools (ir_diff*, ir_patch_gen.py, xls_ir_to_*, etc.)
and the Cytoscape exporter are superseded by the C++ MCS+GED pipeline;
delete them and prune the BUILD file. Add README.md describing the
diff -> apply -> verify chain, MCS/GED flags, logging, and references.

Also rename linear_sum_assignment -> LinearSumAssignment to follow the
Google C++ style for free functions.
Replace the ad-hoc std::chrono elapsed-time measurements in the GED and MCS
pipeline with xls::Stopwatch (xls/common/stopwatch.h), which wraps a steady
clock behind a single shared utility. Timing behaviour is unchanged.

  - Convert always-on VLOG(0) statements to LOG(INFO), matching the rest of
    XLS; VLOG levels 1-3 remain as verbosity tiers.
  - Drop "using namespace xls" from patch_ir_main.cc in favour of explicit
    xls:: qualification.
  - Restore the lap_solver.h include guard (missing #endif).
  - Record planned residual pruning, channel-aware patching, RTL build
    automation, and benchmark expansion as TODO(xls-eco) markers at the
    relevant sites.
The parser now uniquifies the state read's node name away from its
state element (st -> st__1), so the hard-coded name no longer matches.
Find the StateRead node in the parsed proc instead.
@alirezazd

Copy link
Copy Markdown
Author

@proppy fixed

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants