1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! SMARTS substructure-matching engine.
//!
//! A parser + backtracking subgraph-isomorphism matcher covering the SMARTS
//! feature subset used by RDKit's ETKDGv3 experimental-torsion preference
//! tables (`torsionPreferences_v2 / _smallrings / _macrocycles`), including
//! recursive SMARTS `[$(...)]`.
//!
//! Match semantics follow RDKit `GetSubstructMatches(uniquify=False)`: every
//! distinct query-atom → mol-atom embedding is reported, ordered by query-atom
//! index. Ported (semantics only) from RDKit under the BSD-3 licence:
//! - `Code/GraphMol/SmilesParse/SmartsParse.cpp` (grammar)
//! - `Code/GraphMol/Substruct/SubstructMatch.cpp` (matching + recursive eval)
//! - `Code/GraphMol/QueryAtom.h` / `QueryBond.h` (query primitives)
//!
//! # Aromaticity convention
//!
//! `Atomistic` carries no aromatic model. Aromatic atoms are perceived as those
//! incident to a bond of order `1.5` (the project convention), unless an
//! explicit `is_aromatic` atom/bond prop is present, which takes precedence.
//! This lets callers transplant a reference perception (e.g. RDKit's) so that
//! aromatic queries (`a`, `c`, `:` bonds) agree exactly.
//!
//! # Supported features
//!
//! - Atom primitives: aliphatic/aromatic elements, `*`, `a`, `A`, `#<n>`,
//! `H<n>`, `X<n>`, `D<n>`, `R`/`R<n>`, `r<n>`, `+`/`++`/`+<n>`/`-`/`-<n>`,
//! atom-map `:<n>`.
//! - Atom logic: implicit/`&` high AND, `;` low AND, `,` OR, `!` NOT.
//! - Recursive SMARTS `[$(...)]` (nestable), rooted at the candidate atom.
//! - Bond primitives: `-` `=` `#` `:` `~` `@`, `!`, logical combos
//! (`!@;-`, `-,:`); default bond = single-or-aromatic.
//! - Branches `( )`, ring closures incl. `%nn`.
//!
//! Out of scope: chirality `@`/`@@`, isotopes, reaction / component SMARTS.
//!
//! # Example
//!
//! ```
//! use molrs_core::chem::smarts::SmartsPattern;
//! use molrs_core::{Atom, Atomistic, PropValue};
//!
//! // Acetamide skeleton C-C(=O)-N (no Hs needed for this query).
//! let mut g = Atomistic::new();
//! let c0 = g.add_atom(Atom::xyz("C", 0.0, 0.0, 0.0));
//! let c1 = g.add_atom(Atom::xyz("C", 1.0, 0.0, 0.0));
//! let o = g.add_atom(Atom::xyz("O", 2.0, 0.0, 0.0));
//! let n = g.add_atom(Atom::xyz("N", 1.0, 1.0, 0.0));
//! g.add_bond(c0, c1).unwrap();
//! let bo = g.add_bond(c1, o).unwrap();
//! g.set_bond_prop(bo, "order", PropValue::F64(2.0)).unwrap();
//! g.add_bond(c1, n).unwrap();
//!
//! let pat = SmartsPattern::parse("[$([CX3]=[OX1]):1]~[*:2]").unwrap();
//! assert!(pat.has_match(&g));
//! assert_eq!(pat.map_label(0), Some(1));
//! ```
use crateMolRsError;
use crate;
use QueryGraph;
/// A compiled SMARTS query.