Skip to content

In-warp substructure search for MCS - #243

Closed
scal444 wants to merge 9 commits into
NVIDIA-BioNeMo:mainfrom
scal444:mcs-split-05-substructure
Closed

In-warp substructure search for MCS#243
scal444 wants to merge 9 commits into
NVIDIA-BioNeMo:mainfrom
scal444:mcs-split-05-substructure

Conversation

@scal444

@scal444 scal444 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

scal444 added 9 commits July 28, 2026 12:52
There is exactly one topology representation. The QueryTopology /
TargetTopology template parameters and the kHasAdjacencyBondIndices
trait made it look like there were two, but the only type that ever set
the trait false was a test double -- production code has always passed a
CSR view with all four arrays populated.

The trait dates from when the CSR-adjacency scan was added on top of the
original linear bond-endpoint scan and the old path was kept alive
behind `if constexpr`. Both paths now land together, so the fallback was
dead on arrival: each `else` branch held a verbatim copy of the
adjacency loop under a runtime null-check plus a linear scan nothing
reaches.

Hoist DeviceCsrView into a new fmcs_topology.cuh (along with the bond
endpoint pack/unpack constants, which fmcs_grow.cuh had been
duplicating), take it concretely in matchSingleBondWithinThread,
matchIncrementalFastCooperative, and fillNewBondsCooperative, and delete
the trait with both fallback branches. fmcs_match.cuh drops from 453 to
321 lines with no behaviour change.

The match tests relied on the fallback -- they never populated CSR at
all -- so they now build real CSR arrays via a TestGraph helper and
exercise the path that actually ships.
Extends the cut in the parent commits to the exact substructure layer,
which carried five more `if constexpr` sites on the same
kHasAdjacencyBondIndices trait: findTargetBondBetweenAtomsWithinThread,
the target-degree seeding, the mapped-neighbour count, the mapped-query-
neighbour lookup, and the partial-mapping bond check.

Every else branch was the same dead shape as before -- a copy of the CSR
walk behind a runtime null-check, then a linear scan over all bonds that
no production caller could reach. Only the test double set the trait
false.

Also renames the fast-path call to tryMatchIncrementalGreedyCooperative.
The substructure fallback is exactly the caller the greedy contract
describes: it runs the exact search when the greedy attempt returns
false, rather than treating false as a rejection.

test_fmcs_substructure.cu now builds real CSR via the same TestGraph
helper as the match tests. fmcs_match.cuh drops another 431 lines.
@scal444
scal444 requested a review from evasnow1992 July 31, 2026 14:54
@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR implements and unit-tests a cooperative in-warp substructure matcher, including mapping reconstruction, bounded partial-search storage, and a greedy-first fallback wrapper.

  • Adds substructure-search and fallback helpers to the CUDA FMCS matcher.
  • Adds CUDA tests for successful, rejected, compatibility-constrained, and greedy-fallback matches.
  • Registers the new test executable with CMake.

Confidence Score: 4/5

The production matching path must invoke the new fallback before merging, otherwise real FMCS searches continue to miss the cases this PR is intended to recover.

The fallback works only through the dedicated test kernel; production growth still calls the greedy matcher directly, so the new behavior is unreachable in actual FMCS execution.

Files Needing Attention: src/mcs/fmcs_cuda/fmcs_match.cuh and src/mcs/fmcs_cuda/fmcs_grow.cuh

Important Files Changed

Filename Overview
src/mcs/fmcs_cuda/fmcs_match.cuh Adds the cooperative substructure search and fallback wrapper, but the wrapper is not connected to the production grow path.
tests/test_fmcs_substructure.cu Adds focused CUDA tests for the new helper behavior, including the greedy-failure recovery scenario.
tests/CMakeLists.txt Correctly builds and registers the new substructure test executable.

Reviews (1): Last reviewed commit: "Formatting" | Re-trigger Greptile

Comment on lines +873 to +885
__device__ __forceinline__ bool matchSeedWithSubstructureFallbackCooperative(
const GroupT& group,
const Seed<maxAtoms, maxBonds>& seed,
const DeviceCsrView& queryTopology,
const DeviceCsrView& targetTopology,
const PairMatchTablesDevice& tables,
MatchResult<maxAtoms, maxBonds, maxTA, maxTB>& match,
FmcsSubstructureScratch<maxAtoms, maxTA>& scratch,
int* scratchLock,
std::uint8_t* partialStorage,
int partialCapacity,
bool* overflowedFlag) {
if (tryMatchIncrementalGreedyCooperative(group, seed, queryTopology, targetTopology, tables, match)) {

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.

P1 Fallback remains outside production path

When the incremental greedy matcher selects a locally valid mapping that prevents completion, production FMCS growth never invokes the new exhaustive fallback, causing valid substructures to remain incorrectly rejected even though the dedicated test path recovers them.

@scal444 scal444 closed this Jul 31, 2026
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.

1 participant