[us-commits] [ehb54/ultrascan3] aca818: Add SSSR ring perception and expose the perceived ...

emre brookes noreply at github.com
Sat Aug 8 07:36:10 MDT 2026


  Branch: refs/heads/ehb54-issue-980
  Home:   https://github.com/ehb54/ultrascan3
  Commit: aca818535d29d2f0f1742799a0abe5ba3a9a4457
      https://github.com/ehb54/ultrascan3/commit/aca818535d29d2f0f1742799a0abe5ba3a9a4457
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-08 (Sat, 08 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/tests/sssr.cpp
    A us_somo/develop/perceiver/tests/sssr_real.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp

  Log Message:
  -----------
  Add SSSR ring perception and expose the perceived bond graph

Prerequisite for the Durchschlag & Zipper volume increments, which charge a
ring-formation decrement once per ring (3-ring 2.1 through >=9-ring 14.1).
The perceiver exposed only an "aromatic" flag and never returned Bonds at all,
so ring sizes and the topology needed to classify a nitrogen or oxygen
environment were unavailable to any caller.

Bonds gains "rings", the smallest set of smallest rings. find_sssr() is
declared in the header so it can be unit-tested on hand-built adjacency with
no geometry involved. A new perceive(atoms, bonds_out, explicit_bonds)
overload hands the graph back; the existing signature delegates to it, so
current callers are unaffected.

SSSR is kept separate from find_rings(), which enumerates every simple 5- or
6-cycle and feeds aromaticity. That is the right input for "is this atom in a
flat conjugated ring" but the wrong one for anything charged per ring: a fused
bicyclic has three simple cycles and circuit rank two. Keeping them apart also
leaves the validated perception untouched, confirmed by the regression figure
holding at 99.833%.

Method is the standard one for molecule-sized graphs: smallest cycle through
each bond, then greedy smallest-first acceptance while a candidate covers a
bond no accepted ring covers, until the circuit rank is reached. Rings beyond
max_ring (12) are not sought, since the consumer charges a single large-ring
term for everything from nine up.

Tests

  sssr.cpp      35 checks on hand-built graphs: acyclic shapes, every ring size
                3 to 9, ring with substituent, fused bicyclics (naphthalene,
                indole, purine) giving two rings rather than three cycles,
                spiro, bridged, three-fused, disconnected components,
                macrocycle beyond max_ring, idempotency, and that every
                reported ring is a genuine cycle. Also checks the arithmetic
                the counts drive: one 6-ring decrement reproduces the published
                phenylalanine volume, one 5-ring the proline one.

  sssr_real.cpp 18 checks on real coordinates through the whole perception
                path, over all eight demo structures. Phe {6}, Tyr {6},
                Trp {5,6}, His {5}, Pro {5}, DA/DG {5,5,6}, DC/DT {5,6}, and
                Ala/Gly/Leu/Ser/Arg ring-free, with every instance of a type
                giving an identical signature.

Some demo structures carry physically impossible geometry, which produces
spurious small rings: 1AO6 models LYS536/NZ 0.73 A from LEU583/CG, shorter
than any covalent bond, and 6LYZ has two oxygens 1.22 A apart. This yields 13
cross-residue and 12 three-membered rings across the demo set, none of them
inside a residue, so no residue's own ring count is affected. The tests assert
this as such: a cross-residue ring must be closed by an inter-residue bond that
is neither a backbone link nor a disulfide, and no three-membered ring may lie
within a single residue.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>



To unsubscribe from these emails, change your notification settings at https://github.com/ehb54/ultrascan3/settings/notifications


More information about the us-commits mailing list