Native molecular queries and transformations
MOLMATCH(molecule, pattern) returns the atom matches for a bounded textual SMARTS profile. MOLTRANSFORM(molecule, pattern) applies a bounded mapped SMIRKS graph transformation and returns…
Native molecular queries and transformations
MOL_MATCH(molecule, pattern) returns the atom matches for a bounded textual
SMARTS profile. MOL_TRANSFORM(molecule, pattern) applies a bounded mapped
SMIRKS graph transformation and returns products. Both run through the existing
native molecular graph owner and leave the input unchanged.
Open the complete example as ordinary Grid source:
input substrate = "CBr"
input query_pattern = "[C:1]-[Br:2]"
input transform_pattern = "[C:1]-[Br]>>[C:1]-[O-]"
matches = MOL_MATCH(substrate, query_pattern)
transformed = MOL_TRANSFORM(substrate, transform_pattern)
first_product = INDEX(transformed.products, 1).molecule
product_properties = MOL_DESCRIPTORS(first_product)
The query identifies the carbon–bromine bond. The transformation deletes the unmapped bromine and adds an unmapped negatively charged oxygen bonded to the retained carbon. This is a declared graph edit, not a prediction that a reaction will occur, a balanced reaction equation or a kinetic simulation. Use REACTIONS for kinetics.
The target may be topology-only SMILES text or one molecule_graph. Products carry typed molecule values and can feed existing descriptors or another query. Inspect an empty product list before selecting a first product. Editing any input recomputes the dependent report. Owning source retains the text; saved LIR retains the calls and input definitions for deterministic reopen.
Admitted profile
Profile identity: grid.molecular-pattern.v1. This is a deliberately limited
subset of SMARTS
and SMIRKS,
not full language compatibility.
Every atom is bracketed and every bond is explicit. The profile admits:
- Query elements
H B C N O F P S Cl Br I; lowercaseb c n o p srequire aromatic atoms. Uppercase elements require nonaromatic atoms.[*],[a]and[A]select any, aromatic and nonaromatic atoms. - Optional signed formal charge, one
;D<n>explicit graph-degree constraint, and a final positive map label:[N+1;D4:7]. Absent query charge is unrestricted. Maps are unique integers from 1 through 1,000,000. - Explicit single (-), double (=), triple (#), aromatic (:) and query-only
wildcard (~) bonds; branches such as
[C](=[O])-[O]; top-level dot-separated patterns. Dots impose no same-component or different-component condition. - A transformation written
reactant>>product, with explicit aliphatic elements and single/double/triple bonds. Retained maps must occur on both sides with the same element. Unmapped non-hydrogen atoms are deleted or added. Explicit hydrogen atoms must be mapped on both sides. Absent transform charge means neutral. Degree predicates, wildcards and aromatic transformations are refused.
Ring closures, implicit bonds, recursive patterns, boolean alternatives, isotope/H-count predicates, reaction agents and stereochemical pattern syntax are not admitted. Aromatic queries inspect the target's existing aromatic flags and bonds; they do not run a new aromaticity-perception algorithm. Degree counts explicit graph neighbors, including explicit hydrogens.
Results, identity and limits
Query reports contain profile, source, target_sha256, complete and matches. Each match contains atoms in textual query-atom order, plus maps from supplied labels to target indices. Atom indices are zero-based. Distinct injective mappings are retained, so symmetric patterns can return several mappings for the same selected atom set.
Transformation reports are native records containing the same identity fields\nand a native products vector. Each product contains molecule, atom_mapping for retained user maps, and rule with the source text. Existing graph-signature deduplication is reused; this is not canonical chemical-isomer deduplication. Product indices follow the existing graph editor's compaction after deletions. Source target indices can be inspected separately with MOL_MATCH.
The target_sha256 field hashes the owner's serialized molecule, including its retained metadata; it is provenance identity, not a canonical chemical identifier. A successful empty result means no match. Search/output exhaustion is an error, never a successful truncated result with complete set to true.
Bounds are 4 KiB pattern text, 32 atoms per pattern side, 512 target/product atoms, 1,024 target bonds and 256 returned matches/products. The matcher uses at most 10,000 recursive search states, reduced by a conservative 50-million candidate/bond-scan estimate for larger graphs. Target SMILES is limited to 64 KiB; graph metadata to 16 KiB and one conformer for queries. These are synchronous bounded operations, not background jobs.
The existing supported valence/charge policy validates every product before any report is returned. A single invalid product fails the operation. Transformations admit topology-only targets: aromatic/isotopic/residue-bearing targets, conformers and external properties are refused. New atoms have explicit bracket-atom hydrogen semantics. The workflow does not infer hydrogen balancing, geometry, stereochemical retention/inversion or product feasibility.
Stereo-qualified target text is rejected at these functions. Existing MOL_PARSE_SMILES does not retain chirality as a query predicate: passing an already parsed graph cannot restore information that reader discarded. Queries over coordinate-bearing graphs are topology-only and do not discriminate stereoisomers. Existing concrete-graph MOL_SUBSTRUCTURE behavior is unchanged.
Native ownership
The grid-molecular-core::query_language module owns text admission, immutable prepared queries/transforms and reports. PreparedMolecularQuery and PreparedMolecularTransform let Rust callers parse once and execute against several supplied targets. Their private admitted state cannot be deserialized as an unchecked executable pattern.
Matching and product edits reuse the existing molecular chemistry engine. The runtime adapters only decode arguments and expose typed results; the compiler uses ordinary calls on the existing LIR path. No external toolkit, network request, alternate evaluator, worker or hidden cache is introduced.