Understanding and Evaluating Variants of the McSplit Algorithm for the Maximum Common Subgraph Problem
- Abstract
- Acknowledgements
- Reference Implementations
- User Manual
This repository contains reimplementations of the following algorithms:
- McSplit - C. McCreesh and P. Prosser and J. Trimble. A Partitioning Algorithm for Maximum Common Subgraph Problems. IJCAI 2017.
- McSplit-down - the same top-down ("big-first") search strategy from C. McCreesh and P. Prosser and J. Trimble's paper above, re-implemented as its own algorithm rather than a runtime flag.
- McSplit+RL - Y. Liu and C.-M. Li and H. Jiang and K. He. A Learning Based Branch and Bound for Maximum Common Subgraph Related Problems. AAAI 2020.
- McSplit+RL Pair and McSplit+RL Rate - ablations of McSplit+RL from the same paper above (per-pair scoring and rate-normalised reward respectively); the McSplit-RL reference repository only ships base RL, so these two follow the paper's formulas directly (Section 2.8, 2.9 of the dissertation).
- McSplit+RL-down - McSplit+RL's branching heuristic combined with McSplit-down's search strategy (Section 2.10). This combination has no published paper or reference implementation; it follows the dissertation's own description of the two mechanisms as independent/composable.
- McSplit+LL - J. Zhou and K. He and J. Zheng and C.-M. Li and Y. Liu. A Strengthened Branch and Bound Algorithm for the Maximum Common (Connected) Subgraph Problem. IJCAI 2022.
- McSplit+DAL - Y. Liu and J. Zhao and C.-M. Li and H. Jiang and K. He. Hybrid Learning with New Value Function for the Maximum Common Induced Subgraph Problem. AAAI 2023.
- McSplit+DSB - B. W. Kothalawala and H. Koehler and Q. Wang. Learning to Bound for Maximum Common Subgraph Algorithms. CP 2025.
- RRSplit - K. Yu and K. Wang and C. Long and L.V.S. Lakshmanan and R. Cheng. Fast Maximum Common Subgraph Search: A Redundancy-Reduced Backtracking Approach. ACM. 2024.
- SymSplit - B. W. Kothalawala and H. Koehler and M. Farhan. Accelerating Maximum Common Subgraph Computation by Exploiting Symmetries. ACM 2026.
All implementations were re-written in C++ based on the published papers and validated against the authors' reference binaries. Reference binaries are included in reference/ for validation purposes only and remain the property of their respective authors.
Original author code used for validation (Section 4.1 of the dissertation) was sourced as follows:
| Algorithm | Source |
|---|---|
| McSplit | ijcai2017-partitioning-common-subgraph |
| McSplit+RL | McSplit-RL |
| McSplit+LL | McSplit-LL |
| McSplit+DAL | SIGMOD25-MCSS (./McSplitDAL subfolder) |
| McSplit+DSB | mcsplit-dsb |
| RRSplit | SIGMOD25-MCSS (./RRSplit subfolder) |
| SymSplit | symsplit |
Your local reference/ folder should be laid out as:
reference/
├── mcsplit/
│ └── mcsp # compiled reference binary
├── mcsplit-rl/
│ └── mcsp+RL
├── mcsplit-ll/
│ └── mcsp+ll
├── mcsplit-dal/
│ └── mcspDAL
├── mcsplit-dsb/
│ └── bin/
│ └── run.o
├── rrsplit/
│ └── mcsp
└── symsplit/
└── bin/
└── run.o
These paths match what hpc/run_instance.sh calls in --with-ref mode - if a reference binary isn't at the expected path, that algorithm's ref-mode comparison will silently return empty reference fields rather than erroring, so it's worth checking each path exists after building.
This manual describes how to build and run the unified MCS solver framework. The framework implements seven algorithms (McSplit, McSplit+RL, McSplit+LL, McSplit+DAL, McSplit+DSB, RRSplit, SymSplit) and their ablation variants within a single binary.
- g++ 11.4.1 or later with C++17 support
- The MIVIA/BI/LV instance set, unzipped into
instances/ - GNU Make
- POSIX-compatible shell (bash)
- Boost library (for HPC submission scripts only)
From the project root:
make -C solversThis produces solvers/bin/mcsp. To rebuild from scratch:
rm -f solvers/bin/mcsp
make -C solvers./solvers/bin/mcsp -A <algorithm> -t <timeout> [-l] -q <graph1> <graph2>| Flag | Long form | Description |
|---|---|---|
-q |
--quiet |
Suppress per-instance output; print only the solution size |
-d |
--dimacs |
Read graphs in DIMACS format (default: MIVIA binary) |
-l |
--lad |
Read graphs in LAD format (default: MIVIA binary) |
-i |
--directed |
Treat graphs as directed |
-a |
--labelled |
Use both vertex and edge labels |
-x |
--vertex-labelled |
Use vertex labels only (no edge labels) |
-t <seconds> |
--timeout |
Abort search after this many seconds (0 = no limit) |
-A <algo> |
--algorithm |
Algorithm to run (see algorithm table below) |
| Flag | Algorithm |
|---|---|
mcsplit |
McSplit (baseline) |
down |
McSplit-down (top-down / "big-first" search) |
rl |
McSplit+RL |
rl_pair |
McSplit+RL with per-pair (v,w) scoring instead of per-vertex |
rl_rate |
McSplit+RL with rate-normalised reward |
rl_down |
McSplit+RL branching combined with McSplit-down's search strategy |
ll |
McSplit+LL (full: LSM + LUM) |
ll_lsm |
McSplit+LL with LSM only |
ll_lum |
McSplit+LL with LUM only |
dal |
McSplit+DAL (hybrid alternating policy) |
dal_rl |
McSplit+DAL with RL policy locked |
dal_dal |
McSplit+DAL with DAL policy locked |
dsb |
McSplit+DSB (RL-gated bound) |
dsb_always |
McSplit+DSB with bound always on |
dsb_never |
McSplit+DSB with bound always off |
rrsplit |
RRSplit (all three reductions) |
rrsplit_noveq |
RRSplit without vertex-equivalence reduction |
rrsplit_nomax |
RRSplit without maximality reduction |
rrsplit_nobound |
RRSplit without tighter bound |
symsplit |
SymSplit (variable + value symmetry) |
symsplit_varonly |
SymSplit with variable symmetry only |
symsplit_valonly |
SymSplit with value symmetry only |
MIVIA binary format:
./solvers/bin/mcsp -A mcsplit -t 1000 -q \
instances/MIVIA/mcs10/bvg/b03/mcs10_b03_s40.A00 \
instances/MIVIA/mcs10/bvg/b03/mcs10_b03_s40.B00SIP LAD format (BI - biochemical reactions):
./solvers/bin/mcsp -A rrsplit -t 1000 -l -q \
instances/SIP/biochemicalReactions/001.txt \
instances/SIP/biochemicalReactions/002.txtSIP LAD format (LV):
./solvers/bin/mcsp -A dal_dal -t 0 -l -q \
instances/SIP/LV/g2 \
instances/SIP/LV/g5One line, space-separated:
<unified_size> <unified_edges> <unified_nodes> <unified_time> <unified_aborted> <unified_nodes_to_best> <unified_time_to_best> <unified_cut_branches> <unified_bound_pruned> <unified_sym_pruned>
| Field | Description |
|---|---|
unified_size |
Solution size (MCS vertex count) |
unified_edges |
Edges in the common subgraph |
unified_nodes |
Search tree nodes explored |
unified_time |
Wall-clock time in seconds |
unified_aborted |
1 if timed out before proving optimality, 0 if completed |
unified_nodes_to_best |
Nodes explored before best incumbent found |
unified_time_to_best |
Time at which best incumbent was found (seconds) |
unified_cut_branches |
Total branches pruned |
unified_bound_pruned |
Branches pruned by the algorithm's bound |
unified_sym_pruned |
Branches pruned by symmetry or redundancy reduction |
When run with --with-ref on HPC (see below), four extra fields are appended: ref_size, ref_nodes, ref_time, match (PASS/FAIL/MISSING_DATA).
rsync -avu --progress \
"[source-directory]/" \
[account]@hypatia.st-andrews.ac.uk:work/[target-directory]/ssh [account]@hypatia.st-andrews.ac.ukcd ~/work/[target-directory]/solvers && rm -f bin/mcsp && makeSubmit one algorithm at a time so as not to hit the QOS limits. Each script accepts an optional --with-ref flag to also run the corresponding reference binary and record a PASS/FAIL/MISSING_DATA comparison alongside the unified solver's results.
cd ~/work/[target-directory]
# plain mode
bash hpc/submit_mivia.sh mcsplit
bash hpc/submit_bi.sh dsb
bash hpc/submit_lv.sh symsplit
# with reference comparison
bash hpc/submit_mivia.sh mcsplit --with-ref
bash hpc/submit_bi.sh dsb --with-ref
bash hpc/submit_lv.sh symsplit --with-refWait for each array to finish (squeue -u [account]) before submitting the next, to stay within QOS limits.
squeue -u [account] # job status
ls hpc/results/<algo>_<dataset>/ | wc -l # instances completed (plain mode)
ls hpc/results/<algo>_<dataset>_with_ref/ | wc -l # instances completed (ref mode)
head -5 -q hpc/results/<algo>_<dataset>/*.csv # spot-check outpute.g. ls hpc/results/mcsplit_mivia/ | wc -l or ls hpc/results/dsb_bi_with_ref/ | wc -l.
Per-instance CSVs (one file per instance pair, no header) are merged into a single file with the correct header using hpc/merge_results.sh:
bash hpc/merge_results.sh <algo> <dataset> [--with-ref]e.g.:
bash hpc/merge_results.sh dsb bi # → hpc/results/dsb_bi_all.csv
bash hpc/merge_results.sh symsplit lv --with-ref # → hpc/results/symsplit_lv_with_ref_all.csvPlain-mode header (13 columns):
instance_a,instance_b,algo,unified_size,unified_edges,unified_nodes,unified_time,unified_aborted,unified_nodes_to_best,unified_time_to_best,unified_cut_branches,unified_bound_pruned,unified_sym_pruned
Ref-mode header (17 columns):
instance_a,instance_b,algo,unified_size,unified_edges,unified_nodes,unified_time,unified_aborted,unified_nodes_to_best,unified_time_to_best,unified_cut_branches,unified_bound_pruned,unified_sym_pruned,ref_size,ref_nodes,ref_time,match
scp [account]@hypatia.st-andrews.ac.uk:work/[target-directory]/hpc/results/*_all.csv \
"[source-directory]/"- Implement the algorithm in a new
.cppfile insolvers/src/, following the pattern of existing implementations (entry point returningstd::vector<VtxPair>). - Register the dispatch in
solvers/src/main.cpp- add anelse if (algo == "my_algo")branch. - Add the file to the compiler command in
solvers/Makefile. - If a reference binary exists, add it under
reference/my_algo/(see Reference Implementations for the expected layout) and add a case for it inhpc/run_instance.shunder theWITH_REF=1block. - Rebuild and validate:
make -C solvers
bash hpc/submit_mivia.sh my_algo --with-ref