@kent-tokyo/chematic 0.1.90 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -96,6 +96,26 @@ const ifg = JSON.parse(identify_functional_groups(mol));
96
96
  console.log(ifg); // [{"atoms":[1,2,3],"types":"OC=O"}, ...]
97
97
  ```
98
98
 
99
+ ## Version History
100
+
101
+ **v0.1.94** (2026-06-12):
102
+ - SA Score corpus expanded: 188 FDA molecules (1415 unique fragments)
103
+ - Enhanced fingerprints: True MHFP, True ERG, path FP with bond types
104
+ - Full multi-sphere CIP stereochemistry for R/S assignment
105
+ - InChI stereo layer round-trip support (tetrahedral and E/Z)
106
+
107
+ **v0.1.93** (2026-06-12):
108
+ - Full multi-sphere CIP priority rules
109
+ - Correct stereochemistry assignment for complex chiral centers
110
+
111
+ **v0.1.92** (2026-06-12):
112
+ - InChI stereo layer parsing (tetrahedral `/t` and E/Z `/b`)
113
+ - Path fingerprint with bond type interleaving
114
+
115
+ **v0.1.91** (2026-06-12):
116
+ - True MHFP (structural fragment hashing)
117
+ - True ERG (Ertl 2017 functional group detection)
118
+
99
119
  ## Building from source
100
120
 
101
121
  ```sh
@@ -23,6 +23,18 @@ export class ConformerHandle {
23
23
  * Returns the index of the newly added conformer.
24
24
  */
25
25
  add_minimized_conformer(): number;
26
+ /**
27
+ * Cluster conformers by Kabsch-aligned RMSD and return a JSON object
28
+ * describing which conformers to keep.
29
+ *
30
+ * Uses greedy leader-linkage: conformers are visited in index order; each
31
+ * is compared against existing cluster representatives. If the RMSD to any
32
+ * representative is < `rms_threshold`, the conformer is discarded; otherwise
33
+ * it starts a new cluster and is kept.
34
+ *
35
+ * Returns `{"kept_indices":[0,3,7,...],"removed_count":5}` on success.
36
+ */
37
+ cluster_conformers_json(rms_threshold: number): string;
26
38
  /**
27
39
  * Number of conformers currently stored.
28
40
  */
@@ -94,6 +106,47 @@ export class DepictOptions {
94
106
  set_width(w: number): void;
95
107
  }
96
108
 
109
+ /**
110
+ * MinHash LSH index: insert MHFP fingerprints and query by approximate similarity.
111
+ *
112
+ * ```js
113
+ * const idx = new MhfpLshHandle(128);
114
+ * const i0 = idx.add_smiles("c1ccccc1"); // benzene → index 0
115
+ * const i1 = idx.add_smiles("Cc1ccccc1"); // toluene → index 1
116
+ * const hits = JSON.parse(idx.query_json("c1ccccc1", 0.5));
117
+ * // hits: [{index:0,similarity:1.0}, {index:1,similarity:0.xxx}]
118
+ * ```
119
+ */
120
+ export class MhfpLshHandle {
121
+ free(): void;
122
+ [Symbol.dispose](): void;
123
+ /**
124
+ * Add a molecule by SMILES; returns its 0-based index in the index.
125
+ */
126
+ add_smiles(smiles: string): number;
127
+ /**
128
+ * True if the index contains no molecules.
129
+ */
130
+ is_empty(): boolean;
131
+ /**
132
+ * Number of molecules in the index.
133
+ */
134
+ len(): number;
135
+ /**
136
+ * Create a new LSH index for MHFP fingerprints with `num_hashes` hash lanes.
137
+ * Default band decomposition: 16 bands × (num_hashes / 16) rows.
138
+ * `num_hashes` must be a multiple of 16 (e.g. 128).
139
+ */
140
+ constructor(num_hashes: number);
141
+ /**
142
+ * Query by SMILES for all entries with similarity ≥ threshold.
143
+ *
144
+ * Returns a JSON array `[{"index":N,"similarity":0.xxx},...]` sorted by
145
+ * descending similarity. Empty array `[]` when nothing qualifies.
146
+ */
147
+ query_json(query_smiles: string, threshold: number): string;
148
+ }
149
+
97
150
  /**
98
151
  * A handle to a parsed molecule. Owns the molecule behind an `Rc` so that
99
152
  * it can be cheaply cloned on the JS side without copying atom/bond data.
@@ -106,6 +159,12 @@ export class MolHandle {
106
159
  * Number of aromatic rings (all ring atoms aromatic).
107
160
  */
108
161
  aromatic_ring_count(): number;
162
+ /**
163
+ * Assign CIP (R/S/E/Z) stereocenters and return JSON.
164
+ *
165
+ * Format: `{"centers":[{"atom":0,"code":"R"},{"atom":3,"code":"E"}]}`
166
+ */
167
+ assign_cip_json(): string;
109
168
  /**
110
169
  * Number of heavy atoms (explicit atoms in the graph; does not count implicit H).
111
170
  */
@@ -213,6 +272,21 @@ export class MolHandle {
213
272
  * Number of non-hydrogen heavy atoms.
214
273
  */
215
274
  heavy_atom_count(): number;
275
+ /**
276
+ * Isotope distribution as JSON.
277
+ *
278
+ * Returns `[{"mass":100.0,"abundance":0.9},...]` sorted by mass.
279
+ * `resolution`: m/z bin width in Da (e.g. `0.1` for nominal, `0.01` for high-res).
280
+ */
281
+ isotope_distribution_json(resolution: number): string;
282
+ /**
283
+ * Generate IUPAC systematic name for the molecule.
284
+ *
285
+ * Returns the name string on success, or an empty string when the
286
+ * structure is outside the supported naming scope (complex polycyclics,
287
+ * multi-functional groups, etc.).
288
+ */
289
+ iupac_name(): string;
216
290
  /**
217
291
  * Hall–Kier κ1 shape index.
218
292
  */
@@ -233,6 +307,19 @@ export class MolHandle {
233
307
  * Returns `true` if the molecule satisfies Lipinski's Rule of Five.
234
308
  */
235
309
  lipinski_passes(): boolean;
310
+ /**
311
+ * LogD (distribution coefficient) at a specific pH.
312
+ *
313
+ * Accounts for ionization state: neutral molecules return LogP unchanged,
314
+ * ionizable molecules are adjusted by log(neutral_fraction).
315
+ */
316
+ logd_at_ph(ph: number): number;
317
+ /**
318
+ * LogD profile across a pH range as JSON.
319
+ *
320
+ * Returns `[{"ph":0.0,"logd":2.5}, ...]` with `steps` evenly-spaced pH points.
321
+ */
322
+ logd_profile_json(ph_start: number, ph_end: number, steps: number): string;
236
323
  /**
237
324
  * Crippen–Wildman octanol/water partition coefficient (LogP).
238
325
  */
@@ -307,6 +394,12 @@ export class MolHandle {
307
394
  * Quantitative Estimate of Drug-likeness (QED); range [0, 1].
308
395
  */
309
396
  qed(): number;
397
+ /**
398
+ * Randić connectivity index (χ₀).
399
+ *
400
+ * χ₀ = Σ 1/√(d_i × d_j) over all bonds, where d is heavy-atom degree.
401
+ */
402
+ randic_index(): number;
310
403
  /**
311
404
  * Returns `true` if the molecule passes the REOS (Rapid Elimination Of Swill) filter.
312
405
  */
@@ -344,6 +437,10 @@ export class MolHandle {
344
437
  * Wiener topological index (sum of all pairwise shortest-path distances).
345
438
  */
346
439
  wiener_index(): number;
440
+ /**
441
+ * Zagreb index M1: Σ d_i² over all heavy atoms.
442
+ */
443
+ zagreb_index_m1(): number;
347
444
  }
348
445
 
349
446
  /**
@@ -412,6 +509,17 @@ export function butina_cluster_ecfp4_json(smiles_json: string, cutoff: number):
412
509
  */
413
510
  export function canonical_tautomer(mol: MolHandle): MolHandle;
414
511
 
512
+ /**
513
+ * Compute the canonical tautomer with specific atoms blocked from H-transfer.
514
+ *
515
+ * `blocked_atom_indices_json`: JSON array of 0-based atom indices, e.g. `[0, 3]`.
516
+ * Any tautomer move whose donor, bridge, or acceptor is in the blocked set is suppressed.
517
+ *
518
+ * Returns canonical SMILES of the result, or `{"error":"..."}` on failure.
519
+ * Out-of-range indices are silently ignored (no effect).
520
+ */
521
+ export function canonical_tautomer_with_blocked_atoms_json(mol: MolHandle, blocked_atom_indices_json: string): string;
522
+
415
523
  /**
416
524
  * Parse all molecular fragments from a CDXML string.
417
525
  *
@@ -552,6 +660,21 @@ export function depict_svg_grid_highlighted(smiles_block: string, cols: number,
552
660
  */
553
661
  export function detect_functional_groups(mol: MolHandle): string;
554
662
 
663
+ /**
664
+ * Infer bond connectivity and bond orders from an XYZ-format string.
665
+ *
666
+ * Explicit hydrogen atoms must be present in the XYZ for reliable bond-order
667
+ * assignment (without H, carbonyl C=O cannot be distinguished from C-O).
668
+ *
669
+ * Returns JSON on success: `{"smiles":"CCO","atom_count":3,"bond_count":2}`.
670
+ * `atom_count` and `bond_count` refer to the heavy-atom skeleton (H removed).
671
+ *
672
+ * Returns JSON on error: `{"error":"molecule has 450 atoms; maximum is 300"}`.
673
+ *
674
+ * Safe: never freezes. All internal loops are O(n²). Capped at 300 atoms.
675
+ */
676
+ export function determine_bonds_from_xyz_json(xyz_str: string): string;
677
+
555
678
  /**
556
679
  * Dice similarity between `a` and `b` using ECFP4 fingerprints.
557
680
  */
@@ -643,6 +766,14 @@ export function enumerate_stereo_isomers_json(mol: MolHandle): string;
643
766
  */
644
767
  export function enumerate_tautomers_json(mol: MolHandle): string;
645
768
 
769
+ /**
770
+ * Compute ERG-style 315-element float histogram fingerprint.
771
+ * Returns JSON: {"len":315,"values":[f64,...]} or {"error":"..."}.
772
+ * Format: 21 pharmacophore-feature-pair × 15 distance bins with Gaussian fuzzing.
773
+ * See `chematic_fp::erg_vec` for details.
774
+ */
775
+ export function erg_vec_json(mol: MolHandle): string;
776
+
646
777
  /**
647
778
  * Per-atom EState values as a JSON array of f64.
648
779
  *
@@ -905,6 +1036,14 @@ export function maxmin_picks_ecfp4_json(smiles_json: string, n: number): string;
905
1036
  */
906
1037
  export function mcs_smiles_json(smiles_json: string): string;
907
1038
 
1039
+ /**
1040
+ * MinHash fingerprint (128 hashes) as JSON.
1041
+ *
1042
+ * Returns `{"num_hashes":128,"hashes":[u64,...]}`.
1043
+ * Use `tanimoto_mhfp_smiles` for direct SMILES-to-SMILES similarity.
1044
+ */
1045
+ export function mhfp_hashes_json(mol: MolHandle): string;
1046
+
908
1047
  /**
909
1048
  * Optimize molecular geometry using DREIDING force field.
910
1049
  *
@@ -919,6 +1058,48 @@ export function mcs_smiles_json(smiles_json: string): string;
919
1058
  */
920
1059
  export function minimize_dreiding_json(mol: MolHandle): string;
921
1060
 
1061
+ /**
1062
+ * Minimize geometry using MMFF94 steepest descent (Halgren 1996 full parameters).
1063
+ * Generates 3D coords internally if needed.
1064
+ * Returns JSON: {"energy":E,"rmsd":R,"converged":true,"iterations":N} or {"error":"..."}.
1065
+ */
1066
+ export function minimize_mmff94_json(mol: MolHandle, max_iter: number): string;
1067
+
1068
+ /**
1069
+ * Minimize geometry using MMFF94 L-BFGS (faster convergence than steepest descent).
1070
+ * Returns JSON: {"energy":E,"rmsd":R,"converged":true,"iterations":N} or {"error":"..."}.
1071
+ */
1072
+ export function minimize_mmff94_lbfgs_json(mol: MolHandle, max_iter: number): string;
1073
+
1074
+ /**
1075
+ * MMFF94 partial charges (BCI table, ±0.1e accuracy) as a JSON array of f64.
1076
+ *
1077
+ * Uses Bond Charge Increment (BCI) model (Halgren 1996) for 25 common bond types.
1078
+ * Returns `[q0, q1, ..., qN]` — one value per heavy atom.
1079
+ * Total charge equals the sum of formal charges (charge conserved).
1080
+ */
1081
+ export function mmff94_charges_json(mol: MolHandle): string;
1082
+
1083
+ /**
1084
+ * Compute MMFF94-style atom-typed partial charges (improved over element-pair BCI).
1085
+ * Returns JSON: {"charges":[f64,...]} or {"error":"..."}.
1086
+ * Uses atom-type classification (Csp3/Ccarbonyl/Ohydroxyl/Oester/Nar/NarH etc.)
1087
+ * for better accuracy (~±0.02e) vs element-pair BCI (~±0.05e).
1088
+ */
1089
+ export function mmff94_charges_typed_json(mol: MolHandle): string;
1090
+
1091
+ /**
1092
+ * Compute MMFF94 energy breakdown for current rule-based 3D geometry.
1093
+ * Returns JSON: {"bond":B,"angle":A,"torsion":T,"vdw":V,"elec":E,"total":X} or {"error":"..."}.
1094
+ */
1095
+ export function mmff94_energy_breakdown_json(mol: MolHandle): string;
1096
+
1097
+ /**
1098
+ * Compute MMFF94 partial charges using numeric atom types (Halgren 1996 eq. 15).
1099
+ * Returns JSON: {"charges":[-0.28,0.15,...]} or {"error":"..."}.
1100
+ */
1101
+ export function mmff94_partial_charges_json(mol: MolHandle): string;
1102
+
922
1103
  /**
923
1104
  * Find matched molecular pairs in a set of molecules as JSON.
924
1105
  *
@@ -1442,6 +1623,22 @@ export function tanimoto_fcfp6(a: MolHandle, b: MolHandle): number;
1442
1623
  */
1443
1624
  export function tanimoto_maccs(a: MolHandle, b: MolHandle): number;
1444
1625
 
1626
+ /**
1627
+ * Tanimoto-like similarity between two SMILES via MHFP (MinHash Jaccard approximation).
1628
+ */
1629
+ export function tanimoto_mhfp_smiles(smi1: string, smi2: string): number;
1630
+
1631
+ /**
1632
+ * Compute ECFP4 Tanimoto similarity from one query SMILES to all db SMILES (dense output).
1633
+ *
1634
+ * `db_smiles_json`: JSON array of SMILES strings (max 1024 via WASM_MAX_BATCH_ITEMS).
1635
+ *
1636
+ * Returns a flat JSON array of f32 scores, one per db entry, e.g. `[0.12,0.0,0.85]`.
1637
+ * No zero-filtering: the length always equals the number of db entries.
1638
+ * Returns `"error:<msg>"` on parse failure or oversized input.
1639
+ */
1640
+ export function tanimoto_row_json(query_smi: string, db_smiles_json: string): string;
1641
+
1445
1642
  /**
1446
1643
  * Tanimoto similarity between two molecules given only SMILES strings (ECFP4).
1447
1644
  *
@@ -1491,6 +1688,23 @@ export function to_xyz(mol: MolHandle): string;
1491
1688
  */
1492
1689
  export function torsion_bitvec(mol: MolHandle): Uint8Array;
1493
1690
 
1691
+ /**
1692
+ * Scan a torsion dihedral i-j-k-l from 0° to 360° in `steps` increments.
1693
+ * Returns JSON array: [{"angle":0.0,"energy":E},...] or {"error":"..."}.
1694
+ */
1695
+ export function torsion_scan_json(mol: MolHandle, i: number, j: number, k: number, l: number, steps: number): string;
1696
+
1697
+ /**
1698
+ * Virtual screen a query SMILES against a database of SMILES using ECFP4 Tanimoto.
1699
+ *
1700
+ * `db_smiles_json`: JSON array of SMILES strings (max 1024 via WASM_MAX_BATCH_ITEMS).
1701
+ * `k`: number of top hits to return; clamped to db size if larger.
1702
+ *
1703
+ * Returns JSON: `{"results":[{"rank":1,"score":0.85,"smiles":"CCO","idx":42},...]}`.
1704
+ * Returns `"error:<msg>"` on any parse failure or oversized input.
1705
+ */
1706
+ export function virtual_screen_ecfp4_json(query_smi: string, db_smiles_json: string, k: number): string;
1707
+
1494
1708
  /**
1495
1709
  * Compute WHIM descriptors (Weighted Holistic Invariant Molecular) from 3D coordinates.
1496
1710
  * Returns JSON array of 10 values: [L1, L2, L3, P1, P2, P3, ALPHA, BETA, GAMMA, DELTA]
@@ -1520,6 +1734,7 @@ export interface InitOutput {
1520
1734
  readonly memory: WebAssembly.Memory;
1521
1735
  readonly __wbg_conformerhandle_free: (a: number, b: number) => void;
1522
1736
  readonly __wbg_depictoptions_free: (a: number, b: number) => void;
1737
+ readonly __wbg_mhfplshhandle_free: (a: number, b: number) => void;
1523
1738
  readonly __wbg_molhandle_free: (a: number, b: number) => void;
1524
1739
  readonly add_hydrogens: (a: number) => number;
1525
1740
  readonly atom_pair_bitvec: (a: number) => [number, number];
@@ -1530,10 +1745,12 @@ export interface InitOutput {
1530
1745
  readonly brics_fragments_json: (a: number) => [number, number];
1531
1746
  readonly butina_cluster_ecfp4_json: (a: number, b: number, c: number) => [number, number, number, number];
1532
1747
  readonly canonical_tautomer: (a: number) => number;
1748
+ readonly canonical_tautomer_with_blocked_atoms_json: (a: number, b: number, c: number) => [number, number];
1533
1749
  readonly cdxml_to_smiles_json: (a: number, b: number) => [number, number, number, number];
1534
1750
  readonly cip_assignments_json: (a: number) => [number, number];
1535
1751
  readonly conformerhandle_add_generated_conformer: (a: number) => number;
1536
1752
  readonly conformerhandle_add_minimized_conformer: (a: number) => number;
1753
+ readonly conformerhandle_cluster_conformers_json: (a: number, b: number) => [number, number];
1537
1754
  readonly conformerhandle_conformer_count: (a: number) => number;
1538
1755
  readonly conformerhandle_conformer_rmsd: (a: number, b: number, c: number) => number;
1539
1756
  readonly conformerhandle_conformer_rmsd_no_align: (a: number, b: number, c: number) => number;
@@ -1562,6 +1779,7 @@ export interface InitOutput {
1562
1779
  readonly depictoptions_set_show_atom_indices: (a: number, b: number) => void;
1563
1780
  readonly depictoptions_set_width: (a: number, b: number) => void;
1564
1781
  readonly detect_functional_groups: (a: number) => [number, number];
1782
+ readonly determine_bonds_from_xyz_json: (a: number, b: number) => [number, number];
1565
1783
  readonly dice_ecfp4: (a: number, b: number) => number;
1566
1784
  readonly dice_ecfp6: (a: number, b: number) => number;
1567
1785
  readonly dice_maccs: (a: number, b: number) => number;
@@ -1573,6 +1791,7 @@ export interface InitOutput {
1573
1791
  readonly enumerate_library_2way: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number, number];
1574
1792
  readonly enumerate_stereo_isomers_json: (a: number) => [number, number, number, number];
1575
1793
  readonly enumerate_tautomers_json: (a: number) => [number, number];
1794
+ readonly erg_vec_json: (a: number) => [number, number];
1576
1795
  readonly estate_indices_json: (a: number) => [number, number];
1577
1796
  readonly fcfp4_bitvec: (a: number) => [number, number];
1578
1797
  readonly fcfp6_bitvec: (a: number) => [number, number];
@@ -1602,7 +1821,19 @@ export interface InitOutput {
1602
1821
  readonly match_smarts_smiles: (a: number, b: number, c: number, d: number) => [number, number, number, number];
1603
1822
  readonly maxmin_picks_ecfp4_json: (a: number, b: number, c: number) => [number, number, number, number];
1604
1823
  readonly mcs_smiles_json: (a: number, b: number) => [number, number, number, number];
1824
+ readonly mhfp_hashes_json: (a: number) => [number, number];
1825
+ readonly mhfplshhandle_add_smiles: (a: number, b: number, c: number) => [number, number, number];
1826
+ readonly mhfplshhandle_is_empty: (a: number) => number;
1827
+ readonly mhfplshhandle_len: (a: number) => number;
1828
+ readonly mhfplshhandle_new: (a: number) => number;
1829
+ readonly mhfplshhandle_query_json: (a: number, b: number, c: number, d: number) => [number, number, number, number];
1605
1830
  readonly minimize_dreiding_json: (a: number) => [number, number];
1831
+ readonly minimize_mmff94_json: (a: number, b: number) => [number, number];
1832
+ readonly minimize_mmff94_lbfgs_json: (a: number, b: number) => [number, number];
1833
+ readonly mmff94_charges_json: (a: number) => [number, number];
1834
+ readonly mmff94_charges_typed_json: (a: number) => [number, number];
1835
+ readonly mmff94_energy_breakdown_json: (a: number) => [number, number];
1836
+ readonly mmff94_partial_charges_json: (a: number) => [number, number];
1606
1837
  readonly mmp_pairs_json: (a: number, b: number) => [number, number, number, number];
1607
1838
  readonly mol2_to_smiles: (a: number, b: number) => [number, number];
1608
1839
  readonly mol_block_coords_json: (a: number, b: number) => [number, number, number, number];
@@ -1621,6 +1852,7 @@ export interface InitOutput {
1621
1852
  readonly mol_with_bond_added: (a: number, b: number, c: number, d: number) => [number, number, number];
1622
1853
  readonly mol_with_bond_removed: (a: number, b: number) => [number, number, number];
1623
1854
  readonly molhandle_aromatic_ring_count: (a: number) => number;
1855
+ readonly molhandle_assign_cip_json: (a: number) => [number, number];
1624
1856
  readonly molhandle_bertz_ct: (a: number) => number;
1625
1857
  readonly molhandle_bond_count: (a: number) => number;
1626
1858
  readonly molhandle_canonical_smiles: (a: number) => [number, number];
@@ -1646,11 +1878,15 @@ export interface InitOutput {
1646
1878
  readonly molhandle_hba_count: (a: number) => number;
1647
1879
  readonly molhandle_hbd_count: (a: number) => number;
1648
1880
  readonly molhandle_heavy_atom_count: (a: number) => number;
1881
+ readonly molhandle_isotope_distribution_json: (a: number, b: number) => [number, number];
1882
+ readonly molhandle_iupac_name: (a: number) => [number, number];
1649
1883
  readonly molhandle_kappa1: (a: number) => number;
1650
1884
  readonly molhandle_kappa2: (a: number) => number;
1651
1885
  readonly molhandle_kappa3: (a: number) => number;
1652
1886
  readonly molhandle_labute_asa: (a: number) => number;
1653
1887
  readonly molhandle_lipinski_passes: (a: number) => number;
1888
+ readonly molhandle_logd_at_ph: (a: number, b: number) => number;
1889
+ readonly molhandle_logd_profile_json: (a: number, b: number, c: number, d: number) => [number, number];
1654
1890
  readonly molhandle_logp_crippen: (a: number) => number;
1655
1891
  readonly molhandle_max_estate: (a: number) => number;
1656
1892
  readonly molhandle_min_estate: (a: number) => number;
@@ -1669,6 +1905,7 @@ export interface InitOutput {
1669
1905
  readonly molhandle_num_unspecified_stereocenters: (a: number) => number;
1670
1906
  readonly molhandle_pains_passes: (a: number) => number;
1671
1907
  readonly molhandle_qed: (a: number) => number;
1908
+ readonly molhandle_randic_index: (a: number) => number;
1672
1909
  readonly molhandle_reos_passes: (a: number) => number;
1673
1910
  readonly molhandle_ring_count: (a: number) => number;
1674
1911
  readonly molhandle_rotatable_bond_count: (a: number) => number;
@@ -1678,6 +1915,7 @@ export interface InitOutput {
1678
1915
  readonly molhandle_tpsa: (a: number) => number;
1679
1916
  readonly molhandle_veber_passes: (a: number) => number;
1680
1917
  readonly molhandle_wiener_index: (a: number) => number;
1918
+ readonly molhandle_zagreb_index_m1: (a: number) => number;
1681
1919
  readonly mqn_json: (a: number) => [number, number];
1682
1920
  readonly mr_per_atom_json: (a: number) => [number, number];
1683
1921
  readonly murcko_scaffold: (a: number) => number;
@@ -1721,6 +1959,8 @@ export interface InitOutput {
1721
1959
  readonly tanimoto_fcfp4: (a: number, b: number) => number;
1722
1960
  readonly tanimoto_fcfp6: (a: number, b: number) => number;
1723
1961
  readonly tanimoto_maccs: (a: number, b: number) => number;
1962
+ readonly tanimoto_mhfp_smiles: (a: number, b: number, c: number, d: number) => [number, number, number];
1963
+ readonly tanimoto_row_json: (a: number, b: number, c: number, d: number) => [number, number];
1724
1964
  readonly tanimoto_smiles: (a: number, b: number, c: number, d: number) => [number, number, number];
1725
1965
  readonly tanimoto_topo_path: (a: number, b: number) => number;
1726
1966
  readonly tanimoto_torsion: (a: number, b: number) => number;
@@ -1729,6 +1969,8 @@ export interface InitOutput {
1729
1969
  readonly to_mol_v3000_block: (a: number) => [number, number];
1730
1970
  readonly to_xyz: (a: number) => [number, number];
1731
1971
  readonly torsion_bitvec: (a: number) => [number, number];
1972
+ readonly torsion_scan_json: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number];
1973
+ readonly virtual_screen_ecfp4_json: (a: number, b: number, c: number, d: number, e: number) => [number, number];
1732
1974
  readonly whim_descriptors_json: (a: number) => [number, number];
1733
1975
  readonly whim_getaway_combined_json: (a: number) => [number, number];
1734
1976
  readonly write_smiles: (a: number) => [number, number];
package/chematic_wasm.js CHANGED
@@ -38,6 +38,31 @@ export class ConformerHandle {
38
38
  const ret = wasm.conformerhandle_add_minimized_conformer(this.__wbg_ptr);
39
39
  return ret >>> 0;
40
40
  }
41
+ /**
42
+ * Cluster conformers by Kabsch-aligned RMSD and return a JSON object
43
+ * describing which conformers to keep.
44
+ *
45
+ * Uses greedy leader-linkage: conformers are visited in index order; each
46
+ * is compared against existing cluster representatives. If the RMSD to any
47
+ * representative is < `rms_threshold`, the conformer is discarded; otherwise
48
+ * it starts a new cluster and is kept.
49
+ *
50
+ * Returns `{"kept_indices":[0,3,7,...],"removed_count":5}` on success.
51
+ * @param {number} rms_threshold
52
+ * @returns {string}
53
+ */
54
+ cluster_conformers_json(rms_threshold) {
55
+ let deferred1_0;
56
+ let deferred1_1;
57
+ try {
58
+ const ret = wasm.conformerhandle_cluster_conformers_json(this.__wbg_ptr, rms_threshold);
59
+ deferred1_0 = ret[0];
60
+ deferred1_1 = ret[1];
61
+ return getStringFromWasm0(ret[0], ret[1]);
62
+ } finally {
63
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
64
+ }
65
+ }
41
66
  /**
42
67
  * Number of conformers currently stored.
43
68
  * @returns {number}
@@ -239,6 +264,102 @@ export class DepictOptions {
239
264
  }
240
265
  if (Symbol.dispose) DepictOptions.prototype[Symbol.dispose] = DepictOptions.prototype.free;
241
266
 
267
+ /**
268
+ * MinHash LSH index: insert MHFP fingerprints and query by approximate similarity.
269
+ *
270
+ * ```js
271
+ * const idx = new MhfpLshHandle(128);
272
+ * const i0 = idx.add_smiles("c1ccccc1"); // benzene → index 0
273
+ * const i1 = idx.add_smiles("Cc1ccccc1"); // toluene → index 1
274
+ * const hits = JSON.parse(idx.query_json("c1ccccc1", 0.5));
275
+ * // hits: [{index:0,similarity:1.0}, {index:1,similarity:0.xxx}]
276
+ * ```
277
+ */
278
+ export class MhfpLshHandle {
279
+ __destroy_into_raw() {
280
+ const ptr = this.__wbg_ptr;
281
+ this.__wbg_ptr = 0;
282
+ MhfpLshHandleFinalization.unregister(this);
283
+ return ptr;
284
+ }
285
+ free() {
286
+ const ptr = this.__destroy_into_raw();
287
+ wasm.__wbg_mhfplshhandle_free(ptr, 0);
288
+ }
289
+ /**
290
+ * Add a molecule by SMILES; returns its 0-based index in the index.
291
+ * @param {string} smiles
292
+ * @returns {number}
293
+ */
294
+ add_smiles(smiles) {
295
+ const ptr0 = passStringToWasm0(smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
296
+ const len0 = WASM_VECTOR_LEN;
297
+ const ret = wasm.mhfplshhandle_add_smiles(this.__wbg_ptr, ptr0, len0);
298
+ if (ret[2]) {
299
+ throw takeFromExternrefTable0(ret[1]);
300
+ }
301
+ return ret[0] >>> 0;
302
+ }
303
+ /**
304
+ * True if the index contains no molecules.
305
+ * @returns {boolean}
306
+ */
307
+ is_empty() {
308
+ const ret = wasm.mhfplshhandle_is_empty(this.__wbg_ptr);
309
+ return ret !== 0;
310
+ }
311
+ /**
312
+ * Number of molecules in the index.
313
+ * @returns {number}
314
+ */
315
+ len() {
316
+ const ret = wasm.mhfplshhandle_len(this.__wbg_ptr);
317
+ return ret >>> 0;
318
+ }
319
+ /**
320
+ * Create a new LSH index for MHFP fingerprints with `num_hashes` hash lanes.
321
+ * Default band decomposition: 16 bands × (num_hashes / 16) rows.
322
+ * `num_hashes` must be a multiple of 16 (e.g. 128).
323
+ * @param {number} num_hashes
324
+ */
325
+ constructor(num_hashes) {
326
+ const ret = wasm.mhfplshhandle_new(num_hashes);
327
+ this.__wbg_ptr = ret;
328
+ MhfpLshHandleFinalization.register(this, this.__wbg_ptr, this);
329
+ return this;
330
+ }
331
+ /**
332
+ * Query by SMILES for all entries with similarity ≥ threshold.
333
+ *
334
+ * Returns a JSON array `[{"index":N,"similarity":0.xxx},...]` sorted by
335
+ * descending similarity. Empty array `[]` when nothing qualifies.
336
+ * @param {string} query_smiles
337
+ * @param {number} threshold
338
+ * @returns {string}
339
+ */
340
+ query_json(query_smiles, threshold) {
341
+ let deferred3_0;
342
+ let deferred3_1;
343
+ try {
344
+ const ptr0 = passStringToWasm0(query_smiles, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
345
+ const len0 = WASM_VECTOR_LEN;
346
+ const ret = wasm.mhfplshhandle_query_json(this.__wbg_ptr, ptr0, len0, threshold);
347
+ var ptr2 = ret[0];
348
+ var len2 = ret[1];
349
+ if (ret[3]) {
350
+ ptr2 = 0; len2 = 0;
351
+ throw takeFromExternrefTable0(ret[2]);
352
+ }
353
+ deferred3_0 = ptr2;
354
+ deferred3_1 = len2;
355
+ return getStringFromWasm0(ptr2, len2);
356
+ } finally {
357
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
358
+ }
359
+ }
360
+ }
361
+ if (Symbol.dispose) MhfpLshHandle.prototype[Symbol.dispose] = MhfpLshHandle.prototype.free;
362
+
242
363
  /**
243
364
  * A handle to a parsed molecule. Owns the molecule behind an `Rc` so that
244
365
  * it can be cheaply cloned on the JS side without copying atom/bond data.
@@ -268,6 +389,24 @@ export class MolHandle {
268
389
  const ret = wasm.molhandle_aromatic_ring_count(this.__wbg_ptr);
269
390
  return ret >>> 0;
270
391
  }
392
+ /**
393
+ * Assign CIP (R/S/E/Z) stereocenters and return JSON.
394
+ *
395
+ * Format: `{"centers":[{"atom":0,"code":"R"},{"atom":3,"code":"E"}]}`
396
+ * @returns {string}
397
+ */
398
+ assign_cip_json() {
399
+ let deferred1_0;
400
+ let deferred1_1;
401
+ try {
402
+ const ret = wasm.molhandle_assign_cip_json(this.__wbg_ptr);
403
+ deferred1_0 = ret[0];
404
+ deferred1_1 = ret[1];
405
+ return getStringFromWasm0(ret[0], ret[1]);
406
+ } finally {
407
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
408
+ }
409
+ }
271
410
  /**
272
411
  * Number of heavy atoms (explicit atoms in the graph; does not count implicit H).
273
412
  * @returns {number}
@@ -515,6 +654,46 @@ export class MolHandle {
515
654
  const ret = wasm.molhandle_heavy_atom_count(this.__wbg_ptr);
516
655
  return ret >>> 0;
517
656
  }
657
+ /**
658
+ * Isotope distribution as JSON.
659
+ *
660
+ * Returns `[{"mass":100.0,"abundance":0.9},...]` sorted by mass.
661
+ * `resolution`: m/z bin width in Da (e.g. `0.1` for nominal, `0.01` for high-res).
662
+ * @param {number} resolution
663
+ * @returns {string}
664
+ */
665
+ isotope_distribution_json(resolution) {
666
+ let deferred1_0;
667
+ let deferred1_1;
668
+ try {
669
+ const ret = wasm.molhandle_isotope_distribution_json(this.__wbg_ptr, resolution);
670
+ deferred1_0 = ret[0];
671
+ deferred1_1 = ret[1];
672
+ return getStringFromWasm0(ret[0], ret[1]);
673
+ } finally {
674
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
675
+ }
676
+ }
677
+ /**
678
+ * Generate IUPAC systematic name for the molecule.
679
+ *
680
+ * Returns the name string on success, or an empty string when the
681
+ * structure is outside the supported naming scope (complex polycyclics,
682
+ * multi-functional groups, etc.).
683
+ * @returns {string}
684
+ */
685
+ iupac_name() {
686
+ let deferred1_0;
687
+ let deferred1_1;
688
+ try {
689
+ const ret = wasm.molhandle_iupac_name(this.__wbg_ptr);
690
+ deferred1_0 = ret[0];
691
+ deferred1_1 = ret[1];
692
+ return getStringFromWasm0(ret[0], ret[1]);
693
+ } finally {
694
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
695
+ }
696
+ }
518
697
  /**
519
698
  * Hall–Kier κ1 shape index.
520
699
  * @returns {number}
@@ -555,6 +734,39 @@ export class MolHandle {
555
734
  const ret = wasm.molhandle_lipinski_passes(this.__wbg_ptr);
556
735
  return ret !== 0;
557
736
  }
737
+ /**
738
+ * LogD (distribution coefficient) at a specific pH.
739
+ *
740
+ * Accounts for ionization state: neutral molecules return LogP unchanged,
741
+ * ionizable molecules are adjusted by log(neutral_fraction).
742
+ * @param {number} ph
743
+ * @returns {number}
744
+ */
745
+ logd_at_ph(ph) {
746
+ const ret = wasm.molhandle_logd_at_ph(this.__wbg_ptr, ph);
747
+ return ret;
748
+ }
749
+ /**
750
+ * LogD profile across a pH range as JSON.
751
+ *
752
+ * Returns `[{"ph":0.0,"logd":2.5}, ...]` with `steps` evenly-spaced pH points.
753
+ * @param {number} ph_start
754
+ * @param {number} ph_end
755
+ * @param {number} steps
756
+ * @returns {string}
757
+ */
758
+ logd_profile_json(ph_start, ph_end, steps) {
759
+ let deferred1_0;
760
+ let deferred1_1;
761
+ try {
762
+ const ret = wasm.molhandle_logd_profile_json(this.__wbg_ptr, ph_start, ph_end, steps);
763
+ deferred1_0 = ret[0];
764
+ deferred1_1 = ret[1];
765
+ return getStringFromWasm0(ret[0], ret[1]);
766
+ } finally {
767
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
768
+ }
769
+ }
558
770
  /**
559
771
  * Crippen–Wildman octanol/water partition coefficient (LogP).
560
772
  * @returns {number}
@@ -710,6 +922,16 @@ export class MolHandle {
710
922
  const ret = wasm.molhandle_qed(this.__wbg_ptr);
711
923
  return ret;
712
924
  }
925
+ /**
926
+ * Randić connectivity index (χ₀).
927
+ *
928
+ * χ₀ = Σ 1/√(d_i × d_j) over all bonds, where d is heavy-atom degree.
929
+ * @returns {number}
930
+ */
931
+ randic_index() {
932
+ const ret = wasm.molhandle_randic_index(this.__wbg_ptr);
933
+ return ret;
934
+ }
713
935
  /**
714
936
  * Returns `true` if the molecule passes the REOS (Rapid Elimination Of Swill) filter.
715
937
  * @returns {boolean}
@@ -799,6 +1021,14 @@ export class MolHandle {
799
1021
  const ret = wasm.molhandle_wiener_index(this.__wbg_ptr);
800
1022
  return ret;
801
1023
  }
1024
+ /**
1025
+ * Zagreb index M1: Σ d_i² over all heavy atoms.
1026
+ * @returns {number}
1027
+ */
1028
+ zagreb_index_m1() {
1029
+ const ret = wasm.molhandle_zagreb_index_m1(this.__wbg_ptr);
1030
+ return ret >>> 0;
1031
+ }
802
1032
  }
803
1033
  if (Symbol.dispose) MolHandle.prototype[Symbol.dispose] = MolHandle.prototype.free;
804
1034
 
@@ -973,6 +1203,34 @@ export function canonical_tautomer(mol) {
973
1203
  return MolHandle.__wrap(ret);
974
1204
  }
975
1205
 
1206
+ /**
1207
+ * Compute the canonical tautomer with specific atoms blocked from H-transfer.
1208
+ *
1209
+ * `blocked_atom_indices_json`: JSON array of 0-based atom indices, e.g. `[0, 3]`.
1210
+ * Any tautomer move whose donor, bridge, or acceptor is in the blocked set is suppressed.
1211
+ *
1212
+ * Returns canonical SMILES of the result, or `{"error":"..."}` on failure.
1213
+ * Out-of-range indices are silently ignored (no effect).
1214
+ * @param {MolHandle} mol
1215
+ * @param {string} blocked_atom_indices_json
1216
+ * @returns {string}
1217
+ */
1218
+ export function canonical_tautomer_with_blocked_atoms_json(mol, blocked_atom_indices_json) {
1219
+ let deferred2_0;
1220
+ let deferred2_1;
1221
+ try {
1222
+ _assertClass(mol, MolHandle);
1223
+ const ptr0 = passStringToWasm0(blocked_atom_indices_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1224
+ const len0 = WASM_VECTOR_LEN;
1225
+ const ret = wasm.canonical_tautomer_with_blocked_atoms_json(mol.__wbg_ptr, ptr0, len0);
1226
+ deferred2_0 = ret[0];
1227
+ deferred2_1 = ret[1];
1228
+ return getStringFromWasm0(ret[0], ret[1]);
1229
+ } finally {
1230
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1231
+ }
1232
+ }
1233
+
976
1234
  /**
977
1235
  * Parse all molecular fragments from a CDXML string.
978
1236
  *
@@ -1326,6 +1584,36 @@ export function detect_functional_groups(mol) {
1326
1584
  }
1327
1585
  }
1328
1586
 
1587
+ /**
1588
+ * Infer bond connectivity and bond orders from an XYZ-format string.
1589
+ *
1590
+ * Explicit hydrogen atoms must be present in the XYZ for reliable bond-order
1591
+ * assignment (without H, carbonyl C=O cannot be distinguished from C-O).
1592
+ *
1593
+ * Returns JSON on success: `{"smiles":"CCO","atom_count":3,"bond_count":2}`.
1594
+ * `atom_count` and `bond_count` refer to the heavy-atom skeleton (H removed).
1595
+ *
1596
+ * Returns JSON on error: `{"error":"molecule has 450 atoms; maximum is 300"}`.
1597
+ *
1598
+ * Safe: never freezes. All internal loops are O(n²). Capped at 300 atoms.
1599
+ * @param {string} xyz_str
1600
+ * @returns {string}
1601
+ */
1602
+ export function determine_bonds_from_xyz_json(xyz_str) {
1603
+ let deferred2_0;
1604
+ let deferred2_1;
1605
+ try {
1606
+ const ptr0 = passStringToWasm0(xyz_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1607
+ const len0 = WASM_VECTOR_LEN;
1608
+ const ret = wasm.determine_bonds_from_xyz_json(ptr0, len0);
1609
+ deferred2_0 = ret[0];
1610
+ deferred2_1 = ret[1];
1611
+ return getStringFromWasm0(ret[0], ret[1]);
1612
+ } finally {
1613
+ wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
1614
+ }
1615
+ }
1616
+
1329
1617
  /**
1330
1618
  * Dice similarity between `a` and `b` using ECFP4 fingerprints.
1331
1619
  * @param {MolHandle} a
@@ -1547,6 +1835,28 @@ export function enumerate_tautomers_json(mol) {
1547
1835
  }
1548
1836
  }
1549
1837
 
1838
+ /**
1839
+ * Compute ERG-style 315-element float histogram fingerprint.
1840
+ * Returns JSON: {"len":315,"values":[f64,...]} or {"error":"..."}.
1841
+ * Format: 21 pharmacophore-feature-pair × 15 distance bins with Gaussian fuzzing.
1842
+ * See `chematic_fp::erg_vec` for details.
1843
+ * @param {MolHandle} mol
1844
+ * @returns {string}
1845
+ */
1846
+ export function erg_vec_json(mol) {
1847
+ let deferred1_0;
1848
+ let deferred1_1;
1849
+ try {
1850
+ _assertClass(mol, MolHandle);
1851
+ const ret = wasm.erg_vec_json(mol.__wbg_ptr);
1852
+ deferred1_0 = ret[0];
1853
+ deferred1_1 = ret[1];
1854
+ return getStringFromWasm0(ret[0], ret[1]);
1855
+ } finally {
1856
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
1857
+ }
1858
+ }
1859
+
1550
1860
  /**
1551
1861
  * Per-atom EState values as a JSON array of f64.
1552
1862
  *
@@ -2236,6 +2546,28 @@ export function mcs_smiles_json(smiles_json) {
2236
2546
  }
2237
2547
  }
2238
2548
 
2549
+ /**
2550
+ * MinHash fingerprint (128 hashes) as JSON.
2551
+ *
2552
+ * Returns `{"num_hashes":128,"hashes":[u64,...]}`.
2553
+ * Use `tanimoto_mhfp_smiles` for direct SMILES-to-SMILES similarity.
2554
+ * @param {MolHandle} mol
2555
+ * @returns {string}
2556
+ */
2557
+ export function mhfp_hashes_json(mol) {
2558
+ let deferred1_0;
2559
+ let deferred1_1;
2560
+ try {
2561
+ _assertClass(mol, MolHandle);
2562
+ const ret = wasm.mhfp_hashes_json(mol.__wbg_ptr);
2563
+ deferred1_0 = ret[0];
2564
+ deferred1_1 = ret[1];
2565
+ return getStringFromWasm0(ret[0], ret[1]);
2566
+ } finally {
2567
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2568
+ }
2569
+ }
2570
+
2239
2571
  /**
2240
2572
  * Optimize molecular geometry using DREIDING force field.
2241
2573
  *
@@ -2264,6 +2596,134 @@ export function minimize_dreiding_json(mol) {
2264
2596
  }
2265
2597
  }
2266
2598
 
2599
+ /**
2600
+ * Minimize geometry using MMFF94 steepest descent (Halgren 1996 full parameters).
2601
+ * Generates 3D coords internally if needed.
2602
+ * Returns JSON: {"energy":E,"rmsd":R,"converged":true,"iterations":N} or {"error":"..."}.
2603
+ * @param {MolHandle} mol
2604
+ * @param {number} max_iter
2605
+ * @returns {string}
2606
+ */
2607
+ export function minimize_mmff94_json(mol, max_iter) {
2608
+ let deferred1_0;
2609
+ let deferred1_1;
2610
+ try {
2611
+ _assertClass(mol, MolHandle);
2612
+ const ret = wasm.minimize_mmff94_json(mol.__wbg_ptr, max_iter);
2613
+ deferred1_0 = ret[0];
2614
+ deferred1_1 = ret[1];
2615
+ return getStringFromWasm0(ret[0], ret[1]);
2616
+ } finally {
2617
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2618
+ }
2619
+ }
2620
+
2621
+ /**
2622
+ * Minimize geometry using MMFF94 L-BFGS (faster convergence than steepest descent).
2623
+ * Returns JSON: {"energy":E,"rmsd":R,"converged":true,"iterations":N} or {"error":"..."}.
2624
+ * @param {MolHandle} mol
2625
+ * @param {number} max_iter
2626
+ * @returns {string}
2627
+ */
2628
+ export function minimize_mmff94_lbfgs_json(mol, max_iter) {
2629
+ let deferred1_0;
2630
+ let deferred1_1;
2631
+ try {
2632
+ _assertClass(mol, MolHandle);
2633
+ const ret = wasm.minimize_mmff94_lbfgs_json(mol.__wbg_ptr, max_iter);
2634
+ deferred1_0 = ret[0];
2635
+ deferred1_1 = ret[1];
2636
+ return getStringFromWasm0(ret[0], ret[1]);
2637
+ } finally {
2638
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2639
+ }
2640
+ }
2641
+
2642
+ /**
2643
+ * MMFF94 partial charges (BCI table, ±0.1e accuracy) as a JSON array of f64.
2644
+ *
2645
+ * Uses Bond Charge Increment (BCI) model (Halgren 1996) for 25 common bond types.
2646
+ * Returns `[q0, q1, ..., qN]` — one value per heavy atom.
2647
+ * Total charge equals the sum of formal charges (charge conserved).
2648
+ * @param {MolHandle} mol
2649
+ * @returns {string}
2650
+ */
2651
+ export function mmff94_charges_json(mol) {
2652
+ let deferred1_0;
2653
+ let deferred1_1;
2654
+ try {
2655
+ _assertClass(mol, MolHandle);
2656
+ const ret = wasm.mmff94_charges_json(mol.__wbg_ptr);
2657
+ deferred1_0 = ret[0];
2658
+ deferred1_1 = ret[1];
2659
+ return getStringFromWasm0(ret[0], ret[1]);
2660
+ } finally {
2661
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2662
+ }
2663
+ }
2664
+
2665
+ /**
2666
+ * Compute MMFF94-style atom-typed partial charges (improved over element-pair BCI).
2667
+ * Returns JSON: {"charges":[f64,...]} or {"error":"..."}.
2668
+ * Uses atom-type classification (Csp3/Ccarbonyl/Ohydroxyl/Oester/Nar/NarH etc.)
2669
+ * for better accuracy (~±0.02e) vs element-pair BCI (~±0.05e).
2670
+ * @param {MolHandle} mol
2671
+ * @returns {string}
2672
+ */
2673
+ export function mmff94_charges_typed_json(mol) {
2674
+ let deferred1_0;
2675
+ let deferred1_1;
2676
+ try {
2677
+ _assertClass(mol, MolHandle);
2678
+ const ret = wasm.mmff94_charges_typed_json(mol.__wbg_ptr);
2679
+ deferred1_0 = ret[0];
2680
+ deferred1_1 = ret[1];
2681
+ return getStringFromWasm0(ret[0], ret[1]);
2682
+ } finally {
2683
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2684
+ }
2685
+ }
2686
+
2687
+ /**
2688
+ * Compute MMFF94 energy breakdown for current rule-based 3D geometry.
2689
+ * Returns JSON: {"bond":B,"angle":A,"torsion":T,"vdw":V,"elec":E,"total":X} or {"error":"..."}.
2690
+ * @param {MolHandle} mol
2691
+ * @returns {string}
2692
+ */
2693
+ export function mmff94_energy_breakdown_json(mol) {
2694
+ let deferred1_0;
2695
+ let deferred1_1;
2696
+ try {
2697
+ _assertClass(mol, MolHandle);
2698
+ const ret = wasm.mmff94_energy_breakdown_json(mol.__wbg_ptr);
2699
+ deferred1_0 = ret[0];
2700
+ deferred1_1 = ret[1];
2701
+ return getStringFromWasm0(ret[0], ret[1]);
2702
+ } finally {
2703
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2704
+ }
2705
+ }
2706
+
2707
+ /**
2708
+ * Compute MMFF94 partial charges using numeric atom types (Halgren 1996 eq. 15).
2709
+ * Returns JSON: {"charges":[-0.28,0.15,...]} or {"error":"..."}.
2710
+ * @param {MolHandle} mol
2711
+ * @returns {string}
2712
+ */
2713
+ export function mmff94_partial_charges_json(mol) {
2714
+ let deferred1_0;
2715
+ let deferred1_1;
2716
+ try {
2717
+ _assertClass(mol, MolHandle);
2718
+ const ret = wasm.mmff94_partial_charges_json(mol.__wbg_ptr);
2719
+ deferred1_0 = ret[0];
2720
+ deferred1_1 = ret[1];
2721
+ return getStringFromWasm0(ret[0], ret[1]);
2722
+ } finally {
2723
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
2724
+ }
2725
+ }
2726
+
2267
2727
  /**
2268
2728
  * Find matched molecular pairs in a set of molecules as JSON.
2269
2729
  *
@@ -3713,6 +4173,53 @@ export function tanimoto_maccs(a, b) {
3713
4173
  return ret;
3714
4174
  }
3715
4175
 
4176
+ /**
4177
+ * Tanimoto-like similarity between two SMILES via MHFP (MinHash Jaccard approximation).
4178
+ * @param {string} smi1
4179
+ * @param {string} smi2
4180
+ * @returns {number}
4181
+ */
4182
+ export function tanimoto_mhfp_smiles(smi1, smi2) {
4183
+ const ptr0 = passStringToWasm0(smi1, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4184
+ const len0 = WASM_VECTOR_LEN;
4185
+ const ptr1 = passStringToWasm0(smi2, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4186
+ const len1 = WASM_VECTOR_LEN;
4187
+ const ret = wasm.tanimoto_mhfp_smiles(ptr0, len0, ptr1, len1);
4188
+ if (ret[2]) {
4189
+ throw takeFromExternrefTable0(ret[1]);
4190
+ }
4191
+ return ret[0];
4192
+ }
4193
+
4194
+ /**
4195
+ * Compute ECFP4 Tanimoto similarity from one query SMILES to all db SMILES (dense output).
4196
+ *
4197
+ * `db_smiles_json`: JSON array of SMILES strings (max 1024 via WASM_MAX_BATCH_ITEMS).
4198
+ *
4199
+ * Returns a flat JSON array of f32 scores, one per db entry, e.g. `[0.12,0.0,0.85]`.
4200
+ * No zero-filtering: the length always equals the number of db entries.
4201
+ * Returns `"error:<msg>"` on parse failure or oversized input.
4202
+ * @param {string} query_smi
4203
+ * @param {string} db_smiles_json
4204
+ * @returns {string}
4205
+ */
4206
+ export function tanimoto_row_json(query_smi, db_smiles_json) {
4207
+ let deferred3_0;
4208
+ let deferred3_1;
4209
+ try {
4210
+ const ptr0 = passStringToWasm0(query_smi, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4211
+ const len0 = WASM_VECTOR_LEN;
4212
+ const ptr1 = passStringToWasm0(db_smiles_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4213
+ const len1 = WASM_VECTOR_LEN;
4214
+ const ret = wasm.tanimoto_row_json(ptr0, len0, ptr1, len1);
4215
+ deferred3_0 = ret[0];
4216
+ deferred3_1 = ret[1];
4217
+ return getStringFromWasm0(ret[0], ret[1]);
4218
+ } finally {
4219
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
4220
+ }
4221
+ }
4222
+
3716
4223
  /**
3717
4224
  * Tanimoto similarity between two molecules given only SMILES strings (ECFP4).
3718
4225
  *
@@ -3855,6 +4362,61 @@ export function torsion_bitvec(mol) {
3855
4362
  return v1;
3856
4363
  }
3857
4364
 
4365
+ /**
4366
+ * Scan a torsion dihedral i-j-k-l from 0° to 360° in `steps` increments.
4367
+ * Returns JSON array: [{"angle":0.0,"energy":E},...] or {"error":"..."}.
4368
+ * @param {MolHandle} mol
4369
+ * @param {number} i
4370
+ * @param {number} j
4371
+ * @param {number} k
4372
+ * @param {number} l
4373
+ * @param {number} steps
4374
+ * @returns {string}
4375
+ */
4376
+ export function torsion_scan_json(mol, i, j, k, l, steps) {
4377
+ let deferred1_0;
4378
+ let deferred1_1;
4379
+ try {
4380
+ _assertClass(mol, MolHandle);
4381
+ const ret = wasm.torsion_scan_json(mol.__wbg_ptr, i, j, k, l, steps);
4382
+ deferred1_0 = ret[0];
4383
+ deferred1_1 = ret[1];
4384
+ return getStringFromWasm0(ret[0], ret[1]);
4385
+ } finally {
4386
+ wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
4387
+ }
4388
+ }
4389
+
4390
+ /**
4391
+ * Virtual screen a query SMILES against a database of SMILES using ECFP4 Tanimoto.
4392
+ *
4393
+ * `db_smiles_json`: JSON array of SMILES strings (max 1024 via WASM_MAX_BATCH_ITEMS).
4394
+ * `k`: number of top hits to return; clamped to db size if larger.
4395
+ *
4396
+ * Returns JSON: `{"results":[{"rank":1,"score":0.85,"smiles":"CCO","idx":42},...]}`.
4397
+ * Returns `"error:<msg>"` on any parse failure or oversized input.
4398
+ * @param {string} query_smi
4399
+ * @param {string} db_smiles_json
4400
+ * @param {number} k
4401
+ * @returns {string}
4402
+ */
4403
+ export function virtual_screen_ecfp4_json(query_smi, db_smiles_json, k) {
4404
+ let deferred3_0;
4405
+ let deferred3_1;
4406
+ try {
4407
+ const ptr0 = passStringToWasm0(query_smi, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4408
+ const len0 = WASM_VECTOR_LEN;
4409
+ const ptr1 = passStringToWasm0(db_smiles_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
4410
+ const len1 = WASM_VECTOR_LEN;
4411
+ const ret = wasm.virtual_screen_ecfp4_json(ptr0, len0, ptr1, len1, k);
4412
+ deferred3_0 = ret[0];
4413
+ deferred3_1 = ret[1];
4414
+ return getStringFromWasm0(ret[0], ret[1]);
4415
+ } finally {
4416
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
4417
+ }
4418
+ }
4419
+
3858
4420
  /**
3859
4421
  * Compute WHIM descriptors (Weighted Holistic Invariant Molecular) from 3D coordinates.
3860
4422
  * Returns JSON array of 10 values: [L1, L2, L3, P1, P2, P3, ALPHA, BETA, GAMMA, DELTA]
@@ -3990,6 +4552,9 @@ const ConformerHandleFinalization = (typeof FinalizationRegistry === 'undefined'
3990
4552
  const DepictOptionsFinalization = (typeof FinalizationRegistry === 'undefined')
3991
4553
  ? { register: () => {}, unregister: () => {} }
3992
4554
  : new FinalizationRegistry(ptr => wasm.__wbg_depictoptions_free(ptr, 1));
4555
+ const MhfpLshHandleFinalization = (typeof FinalizationRegistry === 'undefined')
4556
+ ? { register: () => {}, unregister: () => {} }
4557
+ : new FinalizationRegistry(ptr => wasm.__wbg_mhfplshhandle_free(ptr, 1));
3993
4558
  const MolHandleFinalization = (typeof FinalizationRegistry === 'undefined')
3994
4559
  ? { register: () => {}, unregister: () => {} }
3995
4560
  : new FinalizationRegistry(ptr => wasm.__wbg_molhandle_free(ptr, 1));
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "kent-tokyo <kent-tokyo@users.noreply.github.com>"
6
6
  ],
7
7
  "description": "WebAssembly bindings for chematic — use chematic from JavaScript/TypeScript",
8
- "version": "0.1.90",
8
+ "version": "0.2.10",
9
9
  "license": "MIT OR Apache-2.0",
10
10
  "repository": {
11
11
  "type": "git",