chematic-chem 0.4.6

Molecular descriptors: MW, LogP, TPSA, QED, Gasteiger charges, CIP stereo, Murcko scaffold, tautomers, BRICS fragmentation — pure-Rust
Documentation
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
//! Synthetic Accessibility Score (SA Score).
//!
//! Reference: P. Ertl & A. Schuffenhauer, J. Cheminf. 2009, 1, 8.
//!
//! The SA Score estimates synthetic accessibility on a scale of 1 (easy) to
//! 10 (hard). It combines:
//!   - A fragment score based on circular Morgan-like environments (radii 0–2)
//!     and their frequency in a reference corpus of drug-like molecules.
//!   - A complexity penalty for spiro atoms, bridgehead atoms, macrocycles,
//!     stereocenters, and ring complexity.
//!
//! # Fragment table
//!
//! The table below was generated by `tools/gen_sa_table` from 145 drug-like
//! molecules validated against the chematic test suite.  Hashes use the same
//! FNV-1a scheme as ECFP fingerprints (`chematic_fp::morgan_fp_counts`).
//! Score encoding: i16 = (log10(fragment_frequency) × 1000) as i16.
//! Fragments not in the table receive DEFAULT_LOG_FREQ = log10(1e-5) = -5.0.

use crate::descriptors::{num_bridgehead_atoms, num_spiro_atoms, num_stereocenters, ring_count};
use chematic_core::{AtomIdx, Molecule};
use chematic_fp::morgan_fp_counts;
use std::collections::HashMap;

// ---------------------------------------------------------------------------
// Fragment scoring table (auto-generated — do not edit by hand)
// Regenerate with: cargo run -p gen-sa-table
// Corpus: 188 molecules (v0.1.94 expansion) | 1415 unique fragment environments
// Score encoding: i16 = (log10(freq_in_corpus) * 1000.0) as i16
// Missing fragments use DEFAULT_LOG_FREQ = -5000 (log10(1e-5))
// ---------------------------------------------------------------------------

// Auto-generated by tools/gen_sa_table
// Corpus: 188 molecules | 1415 unique fragment environments
// Score encoding: i16 = (log10(freq_in_corpus) * 1000.0) as i16
// Missing fragments use DEFAULT_LOG_FREQ = -5000 (log10(1e-5))
static FRAGMENT_SCORES: &[(u64, i16)] = &[
    (0x004964fdf62938bc, -2274), (0x0076dfd9f5d5e92f, -2274), (0x008478d2a965a7d3, -2274), (0x00857a26146afbbe, -1797),
    (0x00920e29c72d57c7, -1797), (0x00f3c98125d0fd0b, -2274), (0x0116b293ae56fc0b, -2274), (0x0122d33741722698, -1797),
    (0x01346a7a0a6a4a0b, -2274), (0x01541220532e32af, -2274), (0x0174164141c74a49, -1973), (0x01792c3d14a1bff2, -2274),
    (0x01df51eebf3e9af8, -1973), (0x01f02a1d9b408cc5, -2274), (0x01f6420114cb0c2f, -1797), (0x02423bfddc4b2164, -1429),
    (0x0257c42c4d26b63c, -1672), (0x028f3cfc5524a7eb, -1797), (0x0307575f08697b50, -2274), (0x030e115ca0c2da1e, -2274),
    (0x03923643b928b17e, -1973), (0x03ac5ed040dbb9bc, -2274), (0x03b614ff5a84337c, -2274), (0x03fd4c650173b478, -1973),
    (0x04374c64422da884, -1973), (0x046520163bab2f75, -1797), (0x04799cc5c03d2b61, -2274), (0x04bee69c862ee09c, -2274),
    (0x04efeb2d2a7d577d, -2274), (0x052e74ed182c0313, -2274), (0x0538ec63cef1b7ca, -1973), (0x05609c276e42ecd1, -2274),
    (0x05f69a0fb0b6eb67, -1973), (0x05f9add393b901d0, -1973), (0x0647330488aa81f9, -1973), (0x06826ff6a276a5fa, -1672),
    (0x06a1b9a55d3aceeb, -2274), (0x06ab1497d6d675d7, -2274), (0x07290ca8784452f0, -2274), (0x07ab814d2660c71c, -2274),
    (0x07fa83823e964914, -2274), (0x083f31c7dee29a93, -2274), (0x084143c271b0bd49, -2274), (0x0879232294a61644, -1973),
    (0x0881244bb00dee60, -1797), (0x089a5b3e74f993be, -1797), (0x0984db8bb5d7939d, -2274), (0x09c92985e8b96b99, -2274),
    (0x09e2dac051b3c093, -2274), (0x0a0bed9ab97aaddd, -2274), (0x0a493dfbb1da469e, -1575), (0x0a8fc9d9c8cc3f27, -2274),
    (0x0a980f6f4ad1ffdb,  -416), (0x0adcd6285debc907, -2274), (0x0b07b903c0c08671, -1672), (0x0b2aa31778ae8835, -2274),
    (0x0b431c350343558f, -2274), (0x0ba08a32cb665d29, -2274), (0x0bb8d8fad52164e6, -1319), (0x0bcab9f7c5502977, -2274),
    (0x0bd9f545c283dc1b, -1797), (0x0c5ab6a370d2faa9, -2274), (0x0c5ae3f93c054670, -2274), (0x0cb2d17a5595fe32, -1973),
    (0x0d106d6947d85640, -2274), (0x0d462d17a4802f56, -1973), (0x0d583992c96c069a, -2274), (0x0d5ccde7e9cbfa6d, -2274),
    (0x0db76be9ebd9c092, -1797), (0x0e0376266a8bec44, -2274), (0x0e072814e29c188c, -1232), (0x0e072914e29c1a3f, -1128),
    (0x0e0a8e14e29efbb5,  -912), (0x0e3e3c386d67f31c, -2274), (0x0e56c77424dcd7b4, -1575), (0x0e83ecfc94b68fd1, -1973),
    (0x0e8bea7de713e860, -1973), (0x0e910648edc4cdaa, -2274), (0x0e9a9ad04a7ee557, -2274), (0x0eb25a5432308c3e, -1973),
    (0x0eb59c2454c0a80b, -2274), (0x0ec3bf996032f5c7, -1973), (0x0ece2cb1fabe2c66, -2274), (0x0f6d21323826b337, -1973),
    (0x1038f8f5c37e5fc0, -2274), (0x106112e7d4a5a811, -2274), (0x106494bcb5abaf32, -2274), (0x10852a35673a7846, -2274),
    (0x109606cf03d13cce, -2274), (0x10b754226afd3043,  -694), (0x11407e4b26b7602e, -2274), (0x1170feaa69ecb5b7, -2274),
    (0x117c897cb6c9b5ee, -2274), (0x118cfa7f4931d270, -1973), (0x11bba021fef24f95, -1973), (0x11c33a94cc0a703b, -2274),
    (0x11d5090450bd4399, -2274), (0x12197b33ed502eff, -2274), (0x12205613dc8c11cf, -2274), (0x1231f702ce707674, -1575),
    (0x1262b1edcb2a3284, -1194), (0x12f6d6f181811b15, -1973), (0x1303b7dd5bd8a90d, -2274), (0x1324326b221d46cc, -1973),
    (0x136658b69b5ec468, -2274), (0x13d87ee8d7bcb94c, -1973), (0x142c920f65afb38b, -2274), (0x144fde33d16b19cb, -2274),
    (0x14617ffdadbdf1d5, -2274), (0x14c6cff2b4b0c8ac, -2274), (0x14c8f2d15c49a4ef, -1575), (0x156f4ad7f7975164, -1973),
    (0x157672f70dc078b0, -2274), (0x158e807996ec8cc5, -2274), (0x159971e29aec8f4c, -1973), (0x15a266930ee75fc1, -1575),
    (0x15b68ecdc21d30aa, -1973), (0x15e7ac66e120f8dd, -1672), (0x15fed04eef320ec5, -2274), (0x16057ad0271e705e, -1575),
    (0x1638dd075c357440, -1672), (0x16a17f6bc7e366e7, -2274), (0x16af9720bf576e4f, -1274), (0x16d4c66669ba63d1, -2274),
    (0x16f1423a93372ad5, -2274), (0x175c377ed50ea04c, -1797), (0x179a83d47104aa6c, -1973), (0x185dc2129bd67250, -1973),
    (0x18e6482032e2bb12, -1973), (0x1946adc3a80e3827, -2274), (0x194badb927573b66, -2274), (0x19af0fe684d06da5, -2274),
    (0x19f8660c31cd8678, -2274), (0x1a0a084b0cbde182, -1319), (0x1a2cf86bce61107b, -2274), (0x1a88373fb50838c8, -2274),
    (0x1a92fafae8796a2f, -2274), (0x1a9fde6d38513705, -2274), (0x1b07f8cd99879d2e, -2274), (0x1b2ec62571d026a4, -2274),
    (0x1b7a69208099fd6c, -2274), (0x1b9e47ea1dc8e260, -2274), (0x1c3f087568ccdd60, -2274), (0x1c8a5dbe430f6c16, -1797),
    (0x1cf161a809579ab3, -2274), (0x1d0112f7ade936bb, -1973), (0x1d027b9ca41348b8, -2274), (0x1d08634c968afc6c, -2274),
    (0x1de4fe99e6eca0cb, -2274), (0x1e13a35c60ca339e, -1973), (0x1e2a7340105efa2a, -1973), (0x1e2c49d999eeeb3d, -2274),
    (0x1e7e7ec59ebe9dc2, -2274), (0x1ea6b4cdddb6120e, -1973), (0x1ead3a4c3ea891dc, -2274), (0x1ef262987a9ea3cb, -1797),
    (0x1f0df9de8450bd25, -2274), (0x1f395a325eba426a, -2274), (0x1f63affe49bdd5cd, -2274), (0x1f6ef0a6cfe3dc69, -2274),
    (0x1f7e6fd67342c629, -2274), (0x1fc3839242a817e9, -1973), (0x1fc9c759945123d6, -2274), (0x1fcf80328cad0210, -2274),
    (0x202d2ff867845e57, -2274), (0x203d88f70eff2858, -2274), (0x20491bec562cdeac, -2274), (0x205c443b2ec62a7d, -2274),
    (0x20608a747a74641b, -1973), (0x20e8ec8f2a5c455a, -1973), (0x21180c1ade818796, -2274), (0x2123add8b77232c6, -2274),
    (0x21430d4bee6504e9, -1973), (0x21882e22200bfd05, -2274), (0x21d8c1160c0c1eb5, -2274), (0x21f6cac09e36c9ae, -2274),
    (0x223e10ac5632f867, -2274), (0x226c4223f6055aec, -2274), (0x227eb8b76ee6ac25, -2274), (0x229b7183c12bf558, -2274),
    (0x22beea1f4817719d, -2274), (0x22cf849e223a17fc, -2274), (0x22ef820111ddc011, -1429), (0x237a97d8243d0fd0, -2274),
    (0x23a48f94f84a26da, -1973), (0x23d85d51dddac175,  -575), (0x242eb745e093f971, -2274), (0x24314d7bc9413743, -2274),
    (0x2447be64e758d4d7, -1973), (0x24784972d976e1e5, -1973), (0x24ab0ce97002ddf7, -2274), (0x24d042cf5e0d6936, -2274),
    (0x24eccbe3d079923c, -2274), (0x252021e19e8b9377, -2274), (0x252ccc0f7bca0736, -2274), (0x252e5544ce51986d, -2274),
    (0x258b3ba24d950901, -2274), (0x25ce0c11b56be582, -2274), (0x25dcc98d36f9f3f4, -2274), (0x25e3cfdb5ff70798, -2274),
    (0x2608bc9e99918b81, -2274), (0x26bef7d87ffa4d16, -2274), (0x26e007da0d8f32c8, -2274), (0x271638e85b0c3b23, -1575),
    (0x271f51077458ad09, -2274), (0x273e1903a64933f5, -2274), (0x274e25532ecdc76e, -1575), (0x2757e32e72bea5d8, -1973),
    (0x2799e0205be0a067, -1973), (0x27e85b77f13be42e, -1672), (0x2807683cfef35bae, -2274), (0x2892239e6e3e9947, -1973),
    (0x28e7fdad6ad31373, -2274), (0x2920b45d7954451c, -1973), (0x294ac191846541bd, -2274), (0x296c540d465f6239, -2274),
    (0x296e45103975c05b, -1973), (0x29ae53b8efdac32f, -2274), (0x2a12deb140a33f64, -2274), (0x2a3dd2196f0bd444, -2274),
    (0x2a4528592e2d1977, -2274), (0x2a5cb1f2e4342f1a, -1973), (0x2a943aefc5ac266d, -1797), (0x2aa9aaa2cb43b958, -2274),
    (0x2ad12bebf0577a47, -2274), (0x2ad9b6230042a822, -1973), (0x2b0887b05c8820b8, -2274), (0x2b754f7757c3234b, -2274),
    (0x2b8c70b7e65b0131, -2274), (0x2ba54c732034feb4, -1232), (0x2bb8ee311ff41c41, -1973), (0x2c4cbc063e3c5950, -1429),
    (0x2c8ec0b57acb6fd4, -2274), (0x2c8ece7fcb862975, -1797), (0x2cbde31ff8356f2c, -1973), (0x2cf7eb372af7745e, -2274),
    (0x2d010544454befc8, -2274), (0x2d30432d81089fe2, -1973), (0x2d30f942a6d3d693, -1797), (0x2d31011baac74404, -2274),
    (0x2d8d500a9e4ab55a, -2274), (0x2d9bf070e26c4662, -2274), (0x2ddeb8de0e184048, -1973), (0x2de59def01f6db65, -2274),
    (0x2e122703a11c30ed, -1973), (0x2e3e0d0726160bab, -2274), (0x2e4d488b61aa89e3, -2274), (0x2ecc30d41e125584, -2274),
    (0x2f0a8c02aaadb01b, -2274), (0x2f21d18c14334dda, -1797), (0x2ff1677c5cafe7be, -1973), (0x30ac56cbc7dc04d2, -2274),
    (0x30b8e24790a12b3a, -2274), (0x30c4fbf0e3942f05, -2274), (0x31636c537e8365df, -2274), (0x319e19f4341c4f34, -1429),
    (0x31ca0e373ea8426f, -2274), (0x322410b3e74c3665, -1973), (0x324647d8916ca1f9, -2274), (0x32555b05d258c124, -1672),
    (0x3266bcaf8b17a822, -2274), (0x327fd14d65044ff1, -2274), (0x32bc14f9cd815a32,  -782), (0x32bf7af9cd843d5b,  -410),
    (0x32c68f664a3bb734, -2274), (0x334a8831023dd7b1, -2274), (0x3353e4dcd80c7343, -1973), (0x335ed078bcbe5140, -2274),
    (0x3379451cb346af9c, -2274), (0x33a64083ba82d58c, -2274), (0x33ecc9a706205329, -1973), (0x340b20a10adbc1b9, -2274),
    (0x341966a74349ee48, -1429), (0x3429d7a892587634, -2274), (0x34fb723a5bcf8909, -1429), (0x350464e4d3ce2516, -2274),
    (0x353c695406f165bf, -2274), (0x3559061afbaccd68, -2274), (0x35829089ebc1ba32, -2274), (0x358799f7b3afdc68, -1973),
    (0x35ab48493ed03c48, -1496), (0x35be22044914d55f, -1672), (0x35c40ac3cc681602, -2274), (0x35c75d115414a921, -2274),
    (0x361ab675154b5622, -2274), (0x368170c54c6b8fa2, -2274), (0x3688d710011c86dd, -1973), (0x36b011ce2d26afe6, -2274),
    (0x36c839b2051223f1, -1575), (0x36ccdccc694130c9, -1575), (0x36d0693874039772, -2274), (0x370201e25b9c7e0a, -2274),
    (0x37452d82fa4ba573,  -269), (0x3758fda03bc67d97, -2274), (0x3771f7f252aa6c46, -2274), (0x377574e027d71171, -2274),
    (0x37a8fd981f9a74ff, -2274), (0x37b1050c2b9c0df9, -2274), (0x3805fed4f98f72bc, -2274), (0x386eb18453ce1edc, -2274),
    (0x38cd452e36088f72, -2274), (0x38d1ef005ef620af, -2274), (0x392942e8c7cd681c, -1797), (0x39575e082fe1f1d1, -1797),
    (0x39f52f347b7f471a, -2274), (0x3a010a032a53d965, -2274), (0x3a0183ce2cc8aa90, -2274), (0x3a05d055fe996aea, -2274),
    (0x3a0df6586c4f4abe, -2274), (0x3a14f4dc2cc9aa3a, -2274), (0x3a3c229889d60f23, -2274), (0x3a639e99e3695820, -1973),
    (0x3baad33237588702, -1973), (0x3c08ca054202cfe5, -2274), (0x3c0a836901146878, -2274), (0x3cc0b2945f753989, -2274),
    (0x3cedf6b502306fdd, -1672), (0x3d2bd38b6089633a, -2274), (0x3d96d3c800913cdf, -1973), (0x3de1f14d05a28bca, -2274),
    (0x3e09d995b6e15428, -2274), (0x3e8ac0e6c3a209ef, -2274), (0x3f19f59d52b144d9, -2274), (0x3f8f71748d326e1d, -2274),
    (0x3f99f96e51fd2dc4, -1672), (0x4074176a52d5cd2b, -2274), (0x40be026ea1208a24, -2274), (0x416fc2d6a31d897e, -2274),
    (0x423364784e7f7a64, -2274), (0x42eb18c9aa37d60e, -2274), (0x431602e280cc42e7, -2274), (0x431c36e8a0a84552, -1973),
    (0x432e261a7287471a, -2274), (0x434fac478944f67e, -2274), (0x4373b69458f73ecb, -1319), (0x439d87eb88902042, -2274),
    (0x43a5a092a36ad3e5, -2274), (0x4460d2463203fa35, -2274), (0x447ae66b8657b49f, -2274), (0x449711ffa5709e4a, -2274),
    (0x44abd12b5c892f83, -2274), (0x44ee4fc634d7acbe, -1797), (0x45136f682a4c0fac, -1274), (0x4542020c842ed431, -2274),
    (0x45bb7bf881a88283, -1371), (0x45befd36805dba20, -2274), (0x45c812642be715eb, -2274), (0x45ee51b848811490, -1973),
    (0x45f7cd6764cc339e, -2274), (0x45ff134e282c3c51, -2274), (0x469ef7878555fbe6, -2274), (0x46a4c27b7abddbe3, -2274),
    (0x46ab089bafc023d8, -2274), (0x46b900d613499cd8, -1672), (0x46e272680498fa67, -2274), (0x4712be7ce76241a9, -1973),
    (0x4724727d57cd835c, -2274), (0x47481c6912ad9a4f, -1429), (0x47587fab12b96ae6, -2274), (0x47a0fa5633181f0c, -2274),
    (0x48478073db011eaf, -2274), (0x484bb95551694d01, -2274), (0x4888d06f23a3d987, -1496), (0x490da1e9d7fee20e, -2274),
    (0x492ce9658d9e588b, -2274), (0x49334b429a423fd0, -1371), (0x496ef5e0db507775, -2274), (0x49718bbb2856e893, -2274),
    (0x497ce4cae1877144, -2274), (0x49982f2126c559d4, -1973), (0x49c498d111b1acfb, -1575), (0x49ea28a97a20609e, -2274),
    (0x49f475eb731e087d, -1797), (0x4a47b8b1f265f346, -2274), (0x4a7c781a95d72ee5, -2274), (0x4a7d4e636dffceb5, -2274),
    (0x4a877f1ab23b5430, -2274), (0x4a8be010a1da5d36, -2274), (0x4ac4f49a9c3fb71d, -2274), (0x4af38f01581ce103, -2274),
    (0x4b20f8dd7cfbc508, -2274), (0x4b256d172861c6ca, -1973), (0x4bd52452074c7b8a, -2274), (0x4c042c3547317ad7, -2274),
    (0x4c2f0ffb905a93e6, -2274), (0x4c42d3782bfedb82, -2274), (0x4c6072e6226d3434, -2274), (0x4c6fdf9015b15f5e, -2274),
    (0x4c856359e1f4c9b7, -1797), (0x4c85a524821f2b10, -1973), (0x4c9d6b6a78aa0ac6, -1797), (0x4ca7714d860c67af, -2274),
    (0x4ca9f6369244bb58, -2274), (0x4ccf0feb62d7e7b7, -2274), (0x4d0402138f59e057, -1973), (0x4d3d0df11590ed05, -2274),
    (0x4d5680f6e57a8be5, -2274), (0x4d6760025d19c532, -2274), (0x4d9a62ef1f870b91, -2274), (0x4da71ad13b352efe, -2274),
    (0x4de362ecd68a0fb0, -2274), (0x4e1896e770a45ffa, -2274), (0x4e3a857f02356ea6, -1797), (0x4e3fef1234c334a9, -2274),
    (0x4e85f1e0e9cd1828, -2274), (0x4e9915734746ee77, -2274), (0x4ebef8229e8c976e, -2274), (0x4ecea16cb41910b5, -2274),
    (0x4f4ea4db61b281ad, -2274), (0x4f5084fe642a7512, -2274), (0x4f5369c157376be7, -1672), (0x4f5f8cb262e1584c, -1274),
    (0x4f7ac8f3073b5af3, -2274), (0x4f95629c69c129ed, -2274), (0x4fea127c3e38f39e, -1973), (0x5007f4eb951047ef, -2274),
    (0x5058698579fb50de, -2274), (0x5066cda3b6e1aaff, -2274), (0x5075a54e5b93dc7f, -2274), (0x5079060fab42a5a1, -2274),
    (0x5086bd0d983cceda, -2274), (0x50e064d639ff60c4, -1973), (0x5104cfd313531c71, -1232), (0x513039b7ca971bc0, -1319),
    (0x51339e3483cc633c, -2274), (0x515aa591285d78fe, -1973), (0x515efd9a25f6f74e, -2274), (0x517ae53dee3f28dd, -1973),
    (0x517edd5e6da8b313, -2274), (0x51866aea9712cf96, -2274), (0x51a7e9718f20c46b, -2274), (0x51cb9b45368e9290, -2274),
    (0x5202d4f9026b4d0e, -2274), (0x520a310d1e81a619, -2274), (0x520e34191558df40, -2274), (0x528a16e578612bae, -2274),
    (0x533640c5817406e2, -2274), (0x53768eb1f482f51f, -2274), (0x5399f6de55e7d5a7, -2274), (0x539d6994b9c45ad7, -2274),
    (0x53bd34a7e1eb4bf8, -1973), (0x53c66a8bc20ef234, -2274), (0x53d3c2eb229ee81c, -2274), (0x5425dc6bfdfc677e, -1672),
    (0x544aea528c109962, -2274), (0x54503582c7651ad2, -2274), (0x5457dfc07d75aca1, -2274), (0x54bcdca66d8238e9, -2274),
    (0x554977d15159e88a, -2274), (0x556ce68991d8e109, -2274), (0x5575131f62de7bf7, -2274), (0x55963af5fe9222d5, -2274),
    (0x55b5df7e9edeab87, -2274), (0x561960caaf636e22, -2274), (0x561db32592c61df8, -1973), (0x5697488ef64427b4, -1575),
    (0x56e9bf89b2c6a734, -2274), (0x572054af4a86178b, -1973), (0x572c5b466c634136, -2274), (0x57a111024e86b576, -2274),
    (0x57e46d6734ba46fb, -1973), (0x57fe56020d5719d5, -2274), (0x582fe0dd3008e9a0, -1371), (0x58a9ab022551d187, -2274),
    (0x5925839e743e86d4, -2274), (0x594eaff9274e018c, -1973), (0x59570cb57f50e1b7, -2274), (0x59793ed87483d22e, -2274),
    (0x59b8a0708e69bd1b, -2274), (0x59b90612d6d48edc, -1973), (0x5a07f0560d8ba7e2, -2274), (0x5a6e2968e1ae80c5, -2274),
    (0x5aa3f185c238eb49, -2274), (0x5ae552cd9504178d, -2274), (0x5afd2987d48fd054, -2274), (0x5b2ed9f915fa9e03, -1973),
    (0x5b3a09a461aefdfe, -1496), (0x5b5dfe5d2984fa3f, -2274), (0x5b74f00b881289f5, -2274), (0x5bbe1b405973053e, -1973),
    (0x5bf9c6bd5088b8d4, -2274), (0x5c3f7b1ee98763de, -2274), (0x5c4300e556e64241, -2274), (0x5c6bc1cf78d726d0, -2274),
    (0x5d1cc1345438980a, -2274), (0x5d3701f629252549, -2274), (0x5d7bc80484c373fe, -1973), (0x5d7d89a7fee51fb1, -2274),
    (0x5ddeca18e933289a, -2274), (0x5deb1a3c7749f5be, -1429), (0x5deb1b3c7749f771, -1672), (0x5dee803c774cd8e7,  -951),
    (0x5e0cb4244118919d, -2274), (0x5e836be445549baf, -2274), (0x5efdc4c22cccd52b, -2274), (0x5f03aa2ecf2d57ed, -1575),
    (0x5f3719dfdd6fd0bd, -2274), (0x5f52488f64e7f8fa, -2274), (0x5f5590feb097c120, -2274), (0x5f80ee368da52630, -1973),
    (0x5f8e009021aa6b86, -2274), (0x5f9a1a247f3cc270, -2274), (0x5fb8e9e4840ef0de, -1672), (0x5fd27557e2e089b9, -2274),
    (0x5fecabbbe9cda749, -1973), (0x60501a7e26bb0b90, -2274), (0x60884458d52ffab8, -2274), (0x60c7ac390cf8acc3, -2274),
    (0x60f5702da6154958, -2274), (0x612545b89ae1195a, -2274), (0x61e6ebf0a5639b3e, -2274), (0x623746267c587906, -2274),
    (0x623dc91b0e820579, -2274), (0x6284f08ee2f9c667, -2274), (0x6289c423ea2192d1, -2274), (0x62a486237543e821, -2274),
    (0x62bed07c53de9d80, -1429), (0x62eea70b892ee8d0, -2274), (0x62fd700b89830b3d, -1797), (0x6332756c2ab549af, -2274),
    (0x6344790385595b9a, -2274), (0x63a6467d6000ced4, -2274), (0x63d8906defe276e4, -2274), (0x63fa2c8f0994c3d4, -2274),
    (0x6400aee34714987c, -2274), (0x6407d82ce7275672,  -811), (0x641d378ce6765958, -2274), (0x643472dafd221385, -1098),
    (0x64b450919a1f329b, -2274), (0x64c311967bbdd2bd, -1429), (0x64e097db6f09c84a, -2274), (0x64f6954064502f13, -1973),
    (0x6521c3b4777bb90f, -2274), (0x65385cc729987966, -2274), (0x655198c8a3a42ae3, -2274), (0x655d163420b4d6ad, -2274),
    (0x6568b2358ab723b7, -1973), (0x657d0ddbcb1a0553, -1973), (0x6594b628386dc796, -1973), (0x65975b953879f0ff, -2274),
    (0x65af1398349118e6, -2274), (0x65ce41f130a3021d, -2274), (0x660a0b9fc30d71b7, -2274), (0x664dc78ce289dc10, -1973),
    (0x66ab1f434eeab441, -1672), (0x66bde602faeb8f4f, -2274), (0x66d83133ddecfb06, -2274), (0x67390eec41258673, -1973),
    (0x6757c128693df153, -1672), (0x6779f87fb0eb250c, -2274), (0x67f22daaf79cb2e2, -1371), (0x682b883af61d6a56, -2274),
    (0x6838cd4b1d222b78, -1672), (0x68f291e55b7ad503, -1973), (0x68f7a2fd31484ae9, -1797), (0x695426e8ade9a1f2, -2274),
    (0x69841d75895d9029, -1672), (0x698a2f835fa1d70c, -1797), (0x69b57dbeabb906f8, -2274), (0x6a0691c5e11700a2, -2274),
    (0x6a25e79eba731c74, -2274), (0x6a2fd1412d60849f, -2274), (0x6a430831fae8335a, -2274), (0x6a5c6196bf205103, -2274),
    (0x6a5d29d2b8835813, -2274), (0x6a7b4e22abdb2f93, -1797), (0x6a9146bc54aba831, -1973), (0x6a9d05111f7ed2e5, -2274),
    (0x6a9f4aff9de73c6c, -2274), (0x6ad7cd6f5afdae2b, -2274), (0x6b025ef0678edb15, -2274), (0x6b71c99cf0d05044, -2274),
    (0x6baecb8970e06009, -2274), (0x6bbe2baa6cb843f1, -1973), (0x6c45a774c3299131, -2274), (0x6c4ea59cb5562038, -1973),
    (0x6cb82571ff6041a1, -1973), (0x6cc19595d24e6868, -1973), (0x6cf05109ae71a6ae, -2274), (0x6d0733002da8658e, -1973),
    (0x6d0fd34271c2426e, -1797), (0x6d2389c8bceb32d5, -1973), (0x6d2f3e0a7b335229, -2274), (0x6d511c00c9cce16f, -1672),
    (0x6dccc7dfd864ebf0, -2274), (0x6e0fe20c8c693f24, -2274), (0x6e13470c8c6c209a,  -931), (0x6e13480c8c6c224d, -1973),
    (0x6e7599798a4d61aa, -2274), (0x6f31e277b88b6bbf, -2274), (0x6f34eb84a1d95c39, -2274), (0x6f61606cc0802cbe, -1797),
    (0x6f73fa84b4db1142, -1797), (0x6f9a4e30e927c77e, -1274), (0x6fa15a9be7fc0874, -2274), (0x6fd996e7cde822d5, -2274),
    (0x6fe5608be5b96558, -2274), (0x700962d5766ef5cd, -2274), (0x706c0b9a864e0c33, -2274), (0x708437900e51be62, -2274),
    (0x70a5fa0518ad9687, -1496), (0x70c995d4d4981c68, -1575), (0x70ca64813394c8b3, -2274), (0x70df99d681a6e87f, -1797),
    (0x710d3947d983cbce, -1575), (0x718b96596023547e, -2274), (0x724099588e27a4b9, -2274), (0x724767aa4209a46f, -2274),
    (0x72936eda38c64d21, -2274), (0x72bb7151324d4d06, -2274), (0x730688109dc1822c, -2274), (0x73ae6992506dd923, -2274),
    (0x73b0197f70e5db58, -2274), (0x73b1ace14a20bac7, -2274), (0x742174354a2838e6, -2274), (0x7429cb4661cf0e05, -2274),
    (0x748312d8efcde3a5, -1973), (0x74cc9be181058ca6, -2274), (0x74e75501098a3f02, -2274), (0x754aa22d9e4c747e, -2274),
    (0x7572bdddd4beba1a, -2274), (0x75a78461c5f1c921, -2274), (0x75d641ec0de94a09, -1973), (0x75f360e617ae205a, -1973),
    (0x76a97aba4ab101c4, -1672), (0x76cb1db8affa2902, -2274), (0x77514bacefa3a172, -2274), (0x77600c29d2bf7fc6, -2274),
    (0x77a6a001d77619b0, -2274), (0x77b24e45f235fa61, -2274), (0x77d1ba1ecc8d4e43, -1797), (0x782d3b1ea8fc4ef4, -2274),
    (0x7837e3bc133e896d, -1973), (0x788530b784cf9ce2, -2274), (0x788bc7ea208bc16b, -2274), (0x789bbcfd07c9f138, -2274),
    (0x78d63ec8a435f50a, -2274), (0x792bc2c50a3475b7, -1797), (0x792e2035c469057d, -1973), (0x7980a911b93c0407, -1797),
    (0x79e2e10708e01c53, -1973), (0x7a184f6b3998820c, -2274), (0x7a2746d383cb33c5, -1319), (0x7a2e660c6ba6eeab, -2274),
    (0x7a87eb9a5a02b8bf, -1797), (0x7aa60c3f1432e34e, -2274), (0x7aa989ace8e2c7d7, -2274), (0x7acd736bc01d08cd, -1973),
    (0x7adc80358317e583, -1575), (0x7aefd668b2b30128, -1973), (0x7af07ac5ac6d7b6b, -2274), (0x7ba89e652f34ac2a, -2274),
    (0x7bbb120e6097c78c, -2274), (0x7bd38d5112153110, -2274), (0x7bf8220d17d0a4f8, -1672), (0x7c6f20e73b2508f4, -1575),
    (0x7c7d05a6c4c04c27, -2274), (0x7d4ec4835bd338cd, -2274), (0x7d516308608f0950, -1429), (0x7d61d2e96f98aee9, -1973),
    (0x7deb8faeb3bb4c73, -2274), (0x7e1a0dc96c90139c, -1672), (0x7e47c9e096f6b9ad, -1973), (0x7e630da3d5d1205d, -1672),
    (0x7e781ad217f6ec28, -2274), (0x7eb143e7bd354d9f, -2274), (0x7ebc5bec0ef01e9d, -1973), (0x7ebca741784b57c5, -2274),
    (0x7eec8178f9f5c683, -2274), (0x7f4ce95c23f9db3f, -2274), (0x7f6d7adc40af87e1, -2274), (0x7f8bac5de4e2d267, -2274),
    (0x7fb123c1ee8b702f, -2274), (0x7fd140c7d7db5b01, -2274), (0x8054eca72d841815, -2274), (0x80554999b33ca26b, -2274),
    (0x809126d6a81519b2, -2274), (0x80b17b7e31520400, -2274), (0x80be26a07d8e4a2e, -2274), (0x80ef05f184934e02, -2274),
    (0x8125b83ec147e933, -2274), (0x8155aa89e4845a95, -2274), (0x818e1f7cb5fd59d7, -1797), (0x81e8673834e21126, -2274),
    (0x8226b3b35db79c8d, -2274), (0x8231c843e38d2589, -2274), (0x8233efda378043a1, -2274), (0x823ee47e26f7dee9, -1797),
    (0x8264d0c2280c95f9, -1797), (0x82857a82e1b596c8, -2274), (0x8344a026c20bd995, -2274), (0x834852d7e8e723d7, -2274),
    (0x837897ca4578ff18, -2274), (0x8408b9347124dc70, -1797), (0x841e54e70bfe31f6, -2274), (0x84706917f8b11a0d, -1496),
    (0x847b82c64dac64d5, -2274), (0x8499d46703543f4b, -1575), (0x854c9e90c8832ed9, -2274), (0x8554cc8296e39cbc, -1128),
    (0x8569e7df11734899, -2274), (0x858401ca69d6dafe, -1672), (0x85f46502dce6b0ed, -1672), (0x85f5f7d998a99637, -2274),
    (0x861285c6f9fc333e, -1128), (0x8615ebc6f9ff1667,  -672), (0x86381a5171c7e7a4, -2274), (0x864ce6504c4bc1d9, -2274),
    (0x866597f112031541, -1429), (0x868ff024b50692f0, -1672), (0x86b0f7fd5cfa6bee, -2274), (0x86b643f2912e0cad, -1973),
    (0x86c33e6076af2dd5, -2274), (0x8701933b3323b807, -2274), (0x872544675d203569, -2274), (0x875528cd3e897a48, -2274),
    (0x87985119198796cf, -2274), (0x87a24a66713efb1b, -2274), (0x87de239ce3bb31e5, -2274), (0x882c727d802d3b55, -2274),
    (0x8853338656d6de20, -2274), (0x8862b6049669b258, -2274), (0x887ad34404a3ffc8, -2274), (0x88b6c62ce8a2a4d3, -2274),
    (0x88babf8843e3437e, -1973), (0x88bd03a149671fa5, -2274), (0x891389f976e7a451, -1973), (0x8922f54bd6ae86fc, -2274),
    (0x8948a01de43a184f, -1973), (0x894ced0b46962640, -2274), (0x899cfe7cef58fb3e, -2274), (0x89d353d9202c8da2, -2274),
    (0x89e9d8f29e256432, -2274), (0x8a2c6530d6241976, -2274), (0x8aacbfaa8f561a8a, -2274), (0x8ab045132a1f5306, -1429),
    (0x8ab47abc38b0fbef, -1973), (0x8b23b92bd319cd58, -1973), (0x8b876e6f5a89ef12, -1973), (0x8bf4174c77ff9958, -2274),
    (0x8c1d5bc984261318, -2274), (0x8c216b381a815c0b, -2274), (0x8c719c95d4e72e10, -2274), (0x8c83a4e2eac9c3fc, -2274),
    (0x8c89d7d7cc759b66, -1429), (0x8ce402fddb841d94, -1973), (0x8ceb8d090918de11, -2274), (0x8d552e400a13d5f2, -2274),
    (0x8d918d56e29125e2, -2274), (0x8dbbe42509d98f00, -2274), (0x8dd59b7245994c76, -2274), (0x8dee0430d8ad7988, -1797),
    (0x8e213a41d875eaeb, -1973), (0x8e2ec17e64285c00,  -481), (0x8edb71acb8afe240, -2274), (0x8f0ab1c98e5f91cb, -2274),
    (0x8f430a7169ff630e, -2274), (0x8f58d613c2d9a35b, -2274), (0x8f5a41ece2c39329, -2274), (0x8f70ec5fab158dc5, -2274),
    (0x8fab043f5c66e629, -2274), (0x8fbe9c9bf3fd2e6d, -1575), (0x8fc78acd264998bf, -2274), (0x8fe4abbfc080bd92, -1672),
    (0x8fe62800e8770450, -1575), (0x8fe6de21a1de497f, -2274), (0x90147c6e1c24c439, -2274), (0x902b3e81dda70ad8, -2274),
    (0x90a0b360d149b5fc, -2274), (0x90b18b743f2d03c7, -1797), (0x90e1d1aabef372ca, -2274), (0x9101cd913338ae7b, -2274),
    (0x91362e7473bf4656, -1973), (0x914f6ac094cce7bc, -2274), (0x9182e87f1d7c01a5, -2274), (0x91b6f2598c055ebc, -2274),
    (0x91c6fbcb98feef8c, -1797), (0x91e9f6a9c82e8e29, -1797), (0x9243c81a858cccb4, -2274), (0x925dbe772bb11ada, -2274),
    (0x92c7ba45bf09a016, -2274), (0x937f8906312e512f, -1797), (0x93acf9d16d44a8a9, -2274), (0x93bd01940be341a7, -1973),
    (0x93f6ac35fd7c0b30, -1319), (0x9429570f1230e284, -1797), (0x945f93fa5a519dda, -2274), (0x94834c88d8ddc42e, -2274),
    (0x948d86e3cbcd2bc6, -2274), (0x94f81ebc26b04194, -1319), (0x953d736b378d26c2, -2274), (0x9540107731fbafbd, -2274),
    (0x95d528d14fb0e0d0, -1575), (0x95fb82f71459086f, -1973), (0x96026fcc6a623d08, -2274), (0x961dea166481f4c4, -2274),
    (0x965d7d08bd3222a2, -2274), (0x965db2da45955fed, -2274), (0x96bc333e6a34a086, -1429), (0x96bf993e6a3783af, -1319),
    (0x96e14667bba843c4, -1973), (0x9715d2ba75241490, -2274), (0x974dc55f28cb472d, -2274), (0x9774aaf7709cb750, -1575),
    (0x978922dc0908ae9b, -2274), (0x98c1c5a6bc70ea89, -1973), (0x98dddabdcb8e8e10, -2274), (0x98e629fd6792c230, -2274),
    (0x99396c814ec12223, -2274), (0x993e74a59101d397, -1575), (0x995543a5a0a819a8, -2274), (0x99789cbf384f4019, -2274),
    (0x99911540abf08df6, -2274), (0x99b3d97144877ede, -2274), (0x99bf52616a3996a9, -2274), (0x99fe0db120cd8f47, -2274),
    (0x9a0e411b6bc84ada, -2274), (0x9a2a27e6d6f83a00, -2274), (0x9a43bff97264626f, -1043), (0x9a5b375c67883d6f, -1797),
    (0x9a5e8c58cb526786, -1429), (0x9a8978156d9ef395, -2274), (0x9ad9c58c2b67ad65, -1973), (0x9ae56c3d8122502b, -2274),
    (0x9b1b256d73ed7f44, -1973), (0x9b76aa0f135b9a33, -2274), (0x9b7cea1295c8427f, -1797), (0x9bc9b14475edb9ed, -1232),
    (0x9bd8414d09e8eccc, -1973), (0x9be591e4070df321, -1797), (0x9c1a27137c1968d4, -2274), (0x9c3a024bd227a618, -2274),
    (0x9c5bc04154ffabd9, -2274), (0x9c7a5f4de0ce9aa0, -1496), (0x9c7e111d4409f533, -1973), (0x9ca99c4ca166a3c4, -1797),
    (0x9cea7a6a317ea457, -2274), (0x9cec2f2ec28c1dfd, -1973), (0x9d1e23e65d9d9447, -1973), (0x9d9f36f7f0f4340c, -1973),
    (0x9dc6e3afd5337a3f, -2274), (0x9dfa7b3255d865ae, -1973), (0x9e0d47dd35896025, -2274), (0x9e27d749f348a57b, -1973),
    (0x9f09edb32baf439f, -2274), (0x9f419410e2a65657, -2274), (0x9f665b972fd04bca, -2274), (0x9f6804542d41a995, -1973),
    (0x9f6a63d0853fc1d3, -1232), (0x9f7c982dbff5cf68, -2274), (0x9fa0f91ed8f279e8, -2274), (0xa01191496094a24b, -2274),
    (0xa03b44993833fff7, -1429), (0xa045536554c100d9, -2274), (0xa075dd9f5ba0d6f8, -2274), (0xa07c82b93b628e0f, -1672),
    (0xa08237f53610fae3, -2274), (0xa0ad95467aa5d127, -1973), (0xa0bf29ac3270434f, -2274), (0xa0c08e5d144962f0, -2274),
    (0xa11a35198542be00, -1973), (0xa12fa57c5b86d998, -1973), (0xa13531c31c764bbd, -2274), (0xa1373b7f03422b83, -2274),
    (0xa164f21a8d0cdea0, -2274), (0xa17b23fcc1bbbd17, -2274), (0xa18dd99de621ff97, -2274), (0xa1dd017602357afa, -2274),
    (0xa1f2123aa45368b0, -1973), (0xa259179a4a3a28dc, -2274), (0xa267bcdfb4bf7a74, -2274), (0xa2ac77cf939dd6b5, -2274),
    (0xa2b56e1b8340ccb9, -1973), (0xa2defd97e6b24f1b, -2274), (0xa31ea1ffe528bde9, -1797), (0xa33e9306ef8f6176, -2274),
    (0xa355c365a69f9e2b, -1797), (0xa38e318646a23611, -2274), (0xa3f5417150ce8f60, -2274), (0xa468d14ef842834f, -2274),
    (0xa4fb0bcfd59b6b81,  -429), (0xa4fe0d7ddd89a3d8, -2274), (0xa5930eaa3ca5b19e, -2274), (0xa59a1b479b77cf3f, -2274),
    (0xa59d57c1c71f0b95, -2274), (0xa60db2cb7ebfd2ed, -1973), (0xa615f0527e09b36e, -2274), (0xa63e526cd5eba8bb, -2274),
    (0xa6721f9490b27aa3, -2274), (0xa68750b1239f8848, -2274), (0xa6bec194c072c908, -2274), (0xa6fdaff11cbd8b1c, -1797),
    (0xa744e21cb1bc53ac, -2274), (0xa764c589014951d7, -1429), (0xa7952e346d743820, -2274), (0xa80b11b2b5fd167a, -2274),
    (0xa81528eb870f2481, -2274), (0xa81fed2a1d7de297, -2274), (0xa86c00a5af4cc30b, -1797), (0xa882f841b37652aa, -2274),
    (0xa8882e04761239e9, -1575), (0xa8a614d404148ff0, -1797), (0xa9101376f993d3aa, -2274), (0xa962f425c174e973, -1672),
    (0xa9774d12141badf3, -2274), (0xa988fb81ddab3cf5, -2274), (0xa999a71ce8516dbc, -1973), (0xa9e833ffc57653d0, -1973),
    (0xaa216694818df6dd, -1973), (0xaa7724d04ccf2d17, -1973), (0xaa8e98be03ec2bc7, -1973), (0xab337b62cff23544, -1973),
    (0xab6359ba8a2e2fef, -2274), (0xab6e6e1bf3b7dced, -1973), (0xab745672de3f3efa, -1973), (0xab7613acf0d52908, -2274),
    (0xabb032138f698e3c, -2274), (0xabbf6ff7f967ac84, -2274), (0xabc6e2f9f0768799, -2274), (0xac13c5f35ab078cd, -2274),
    (0xac20406703c7d4c6, -1973), (0xac20430e9688b9ed, -2274), (0xac4b365850a535b0, -2274), (0xace8bd972b43033b, -2274),
    (0xad14e45e56e47cc0, -1496), (0xadd77d2f074cdc9e, -2274), (0xade5da5fe92d2c82,  -769), (0xae185a702534a000, -1973),
    (0xae1df0c269d30dc5, -1043), (0xae42b059560286fc, -1973), (0xae44f57a03167f0b, -2274), (0xae50d26939a44e75, -2274),
    (0xae79d04ab4e0e571, -2274), (0xae96a308ef2201c6, -1128), (0xaea5967497649efd, -1973), (0xaeb7e7bce6e3ad99, -2274),
    (0xaecd8d4eb2d8b176, -2274), (0xaf9ad70a616c886e, -2274), (0xafcecc8e44e4ffc9, -1973), (0xafdaecac00d2aad6, -1194),
    (0xb01844dd5d768668, -2274), (0xb09c4ec91f0dfc1b, -1973), (0xb0a118e41cc9d553, -2274), (0xb0f3400351f69843, -1973),
    (0xb0fb2e8c12eaf3b8, -2274), (0xb14313d41d3496a9, -2274), (0xb2018dbec2f040b4, -2274), (0xb2424b6d8e43e364, -1797),
    (0xb243caee3e5f479f, -1797), (0xb25cbf4d76f89156, -1797), (0xb28cf1280e3110b2, -1319), (0xb2e854bcda3dc37b, -2274),
    (0xb2f6a102f1820770, -2274), (0xb31ceb48fb0f4f4a, -1973), (0xb329c84b68f97df8, -2274), (0xb344526f959089df, -1575),
    (0xb35b42661586490d, -2274), (0xb378690c1ab23369, -2274), (0xb387d912be1b968e, -1043), (0xb3d2036051b42d32, -1797),
    (0xb3db8b7f3abc2099, -1429), (0xb3fe47477dbc4baa, -2274), (0xb4276cb08c623140, -2274), (0xb4534a2cd05690c3, -2274),
    (0xb4937b9fb9bcefbf, -2274), (0xb4a853584f4d4a25, -2274), (0xb4acbe4505a50dec, -2274), (0xb4af333f189c4c24, -2274),
    (0xb4af5c6d1f8cad6f, -2274), (0xb4c24b7bc3fd1116, -2274), (0xb4d1881f8b12413d, -1575), (0xb4e940c425ef5fc6, -2274),
    (0xb51219461e0c1c00, -2274), (0xb53dc9dd5cff17e9, -2274), (0xb5437ef303365d31, -2274), (0xb5a6f03fe2da3864, -1973),
    (0xb5e27feefd12ad84, -1973), (0xb6118f3e0c0d15a5, -2274), (0xb69474f02dd130e5, -1973), (0xb6a6cd0569af209d, -1973),
    (0xb6ce5699c8ec4c90, -2274), (0xb6d6dbe84dc057f4, -1274), (0xb6ff38182098fe09, -2274), (0xb71cf0bd7be9d362, -2274),
    (0xb8326b3207dff480, -1672), (0xb89725f98fb3b86b, -2274), (0xb8dac78f0d0bd2e5, -2274), (0xb92efd2dc027f5f5, -2274),
    (0xb936d1818b63c6b0, -1973), (0xb93929dbe3328751, -1070), (0xb99df8e8ea9fbf98, -2274), (0xb9ca36bdfcb357fb, -2274),
    (0xba38d6d5e9950520, -2274), (0xba52bc85c6adc96e, -2274), (0xba5c2584a2926a9a, -2274), (0xbaac19e4cafaf3f5, -2274),
    (0xbaae318ea238cfed, -2274), (0xbab1dcfddee4ec7e, -1973), (0xbae94fa44bf9c341, -1973), (0xbb19c4b4ee72f2d5, -2274),
    (0xbb5a685e2549cbd8, -2274), (0xbb731075f4503b90, -2274), (0xbb7538bfc098e963, -1797), (0xbbafd8373bf47b8d, -1973),
    (0xbbc3490e51106279, -2274), (0xbbc585eb32e98f7f, -1575), (0xbbc691ee02e036f2, -2274), (0xbc03ddb704ee8ffa, -2274),
    (0xbc24e65e5c22bbab, -2274), (0xbc2da77a239bc1be, -2274), (0xbc492f220936e480, -1672), (0xbc8090f8e50cbf61, -1973),
    (0xbc989e8d65178093, -2274), (0xbca7ce85380680ec, -2274), (0xbd01e4198b2995b7, -2274), (0xbd1acccbb4eaedb5, -2274),
    (0xbd1e5c0413acb5c9, -1973), (0xbd50ffc8b69d212e, -2274), (0xbd7c575255f7f6e9, -1797), (0xbd87c65a326ef109, -2274),
    (0xbdd63f5b2e18c749, -2274), (0xbe23823121abc719, -2274), (0xbe3afe7832a409a9, -2274), (0xbe4f53e75e2046ad, -2274),
    (0xbe9135dfe2866c0e, -2274), (0xbefab5d4c91cd325, -1797), (0xbf3d909228f0217f, -2274), (0xbf76364dd71d8806, -2274),
    (0xbf93b1774735d57b, -2274), (0xbff948d6881e3744, -2274), (0xc02083b2b27c2bfe, -2274), (0xc02969e454e47134, -1973),
    (0xc093721e2125447c, -2274), (0xc0a070577751bf93, -2274), (0xc0afc3b93a3c4038, -2274), (0xc0c97d1fd479be16, -1429),
    (0xc0dda29e7a0d51e3, -2274), (0xc12648a6da570f49, -1973), (0xc1404caa534aaff4, -2274), (0xc1826d7a849a0dd9, -2274),
    (0xc1d45dd3418c5418, -2274), (0xc1e21d602491e121, -1797), (0xc20ffff5e1d9d746, -1973), (0xc22443c70cb90db6, -2274),
    (0xc22885b471910712, -2274), (0xc2577c38f4a465bf, -1797), (0xc2c36a8bca00b748, -1797), (0xc2e705f3a3deb732, -2274),
    (0xc2fe0043144c5c81, -2274), (0xc34bef2eaf66b687, -2274), (0xc383c79a608b89f5, -1973), (0xc3b75f6b09c91e38, -2274),
    (0xc4905e94d33c9f14, -2274), (0xc4bd5befe40ff267, -2274), (0xc4d339b5430482f0, -2274), (0xc4edba2068fbdc22, -2274),
    (0xc4ef61807f27bac9, -2274), (0xc5188343a6d7653c, -1797), (0xc5258ec3bfe8777d, -2274), (0xc54870dc4ec2baee, -1672),
    (0xc585b6219f52c666, -2274), (0xc5a031530d227b6a, -1973), (0xc5b363e688c5ddb7, -2274), (0xc5cb87c363277c61, -2274),
    (0xc5edc24512a70f7a, -2274), (0xc601968ea26832c3, -2274), (0xc649989c393fb751, -2274), (0xc6951ded93e95bb7, -2274),
    (0xc6c0861ebea87657, -1672), (0xc6c621f6ebf87ef7, -2274), (0xc6e525c1293940b7, -1672), (0xc77ce97f5ecbc234, -2274),
    (0xc77dbd9a5032ebbb, -2274), (0xc7bb5f4a212ae9c9, -2274), (0xc7f2865e99bf77d3, -2274), (0xc810a8118a9afdbe, -2274),
    (0xc850cd3f4cd87a5e, -2274), (0xc86570985da4ba38, -1973), (0xc86852535b765a99, -2274), (0xc884021b7b66df8f, -2274),
    (0xc8cbb159b338a6da, -2274), (0xc8d4d8219adb3f46, -1672), (0xc8efeeff8e52fcb6, -1575), (0xc9078ec1b2802784, -2274),
    (0xc90b7e318704ee36, -2274), (0xc90de2470cba2d11, -2274), (0xc94225758d2c7111, -2274), (0xc950d109a3067e00, -1797),
    (0xc9a96892c4f94a57, -2274), (0xc9b699a59612fee8, -1797), (0xc9f1c1d7aaf80d19, -1973), (0xc9f99da38d79050d, -2274),
    (0xca0713a00364244f, -2274), (0xca28382fffc00acd, -2274), (0xca36e6c8c3720686, -2274), (0xca3cf05761ca00ab, -1797),
    (0xcaa24958838e6593, -1973), (0xcb50ecb095e7e9f0, -2274), (0xcb85cbbd7cd0d45d, -2274), (0xcb98e26579ca5e44, -1973),
    (0xcc1801cc22895d96, -1973), (0xcc33b9bb337706a5, -2274), (0xcd1d0257954e7af3, -1973), (0xcd35ebd435581236, -1973),
    (0xcd35ecd4355813e9, -1797), (0xcd3951d4355af55f, -1973), (0xcd766d83277b424e, -2274), (0xcd7e69c18f884283, -2274),
    (0xcd8c32246b047a08, -1973), (0xcd9a32924240cfdb, -2274), (0xcda76ee7114f9784, -2274), (0xcdd1730afd51dd15, -2274),
    (0xcdead70b2583583d, -2274), (0xcdfb8600369bd016, -2274), (0xce1d0d2e45b434ba, -2274), (0xce42b8f85699bc40, -1575),
    (0xce5444103f5bbcde, -1672), (0xce5b3b953bc4bdeb, -1672), (0xce630e53d49105bc, -2274), (0xcef9ca054fa37927, -2274),
    (0xcf02247b1812be17, -2274), (0xcf061c37b9cabd3a, -1797), (0xcf16ed03b2ea59c2, -2274), (0xcf681634ba801d3a, -1496),
    (0xcf6ac04c0136d815, -2274), (0xcf6f2fbe73c07c43, -2274), (0xcf970838737ee10a, -1973), (0xcf99337150bb4f61, -1797),
    (0xcfad6b3f70d941f6, -2274), (0xcfd8ad2c1c3b2cfa, -1429), (0xcfef11290b6f9c0b, -2274), (0xcff0857920fd6b7e, -2274),
    (0xd00d00d9540f9dd6, -1973), (0xd02298a91cb0576b, -1973), (0xd05bcb69c09cd996, -1797), (0xd0632c476a5cc9fc, -1672),
    (0xd0d6535e7df1fb7f, -2274), (0xd0e3fe69d877759c, -2274), (0xd100a60d74e26e04, -1274), (0xd140d35c3a904a2a, -2274),
    (0xd1a2d7926c9e3613, -2274), (0xd1b7fb2d5a6dd0e1, -2274), (0xd1d8ba4f46283ad8, -1973), (0xd1e31719122c43c0, -1973),
    (0xd22d2d1cf6a6548b, -2274), (0xd239632b9305be99, -2274), (0xd26154cbe1054964, -2274), (0xd273c530b99b864a, -2274),
    (0xd2f697fe331738e3, -2274), (0xd34d94f6d45d2277, -2274), (0xd38b200255a2ca01, -2274), (0xd395197b39e52e41, -1797),
    (0xd3aba2935d102322, -2274), (0xd411e39cb0c2f76f,  -683), (0xd4adb89ad70195c6, -2274), (0xd4c4818de4dba184, -2274),
    (0xd4f5945d456dfa66, -2274), (0xd51eb4fba391c442, -1797), (0xd5457e2ea433a729, -2274), (0xd5a91f2dbb16a154, -2274),
    (0xd5d37e6d8d8ab454, -2274), (0xd5f7bf21ea8014a4, -1575), (0xd60f82c9002c0f92, -2274), (0xd6641c5b717bf0b6, -1973),
    (0xd66eb4525ccc3858, -2274), (0xd6806e4334600b5b, -2274), (0xd6a8427984b602ab, -2274), (0xd6b139695fa11539, -2274),
    (0xd6bd9f3fa954d81a, -2274), (0xd706fcdd9c09e473, -2274), (0xd71470e29a3c059a, -2274), (0xd78dfb17d5bd90fc, -2274),
    (0xd7c1ff60e04e0911, -2274), (0xd7cdb4f8902b3b30, -2274), (0xd7f4bf78a27f6dd9, -2274), (0xd7f92fee6fa5f47c, -1973),
    (0xd80a9fd0f2bdf28e, -1973), (0xd82273d92b9e5916, -2274), (0xd829d302c71d2205, -2274), (0xd84a6f17e8b2b17b, -2274),
    (0xd86c5fbc455b58e6, -1973), (0xd87ee844dfc2ef77, -1973), (0xd8ca901bc0ae5817, -1973), (0xd8e2e6d2c568e5d2, -1797),
    (0xd93ec24ceab061c0, -2274), (0xd952a7556f3b8097, -2274), (0xd9b993b65f1eb560, -1672), (0xda390d44501607a0, -1973),
    (0xdac034d29a084462, -2274), (0xdac7c924b677571f, -1797), (0xdae2bd82f447c6af, -2274), (0xdb4f7b8455c903dc, -2274),
    (0xdb9d0cf1a8a41f37, -2274), (0xdbb2573c715bc7f8, -2274), (0xdc4d44af60a4cea4, -2274), (0xdc5bd69c211a0398, -2274),
    (0xdc5d954fee1d26fe, -1973), (0xdd2b348bf428d5b7, -1797), (0xdd436e425731acef, -2274), (0xdd51e19976e31213, -2274),
    (0xdd6726e11962f258, -1575), (0xdd673bcf6472a461, -2274), (0xdd6a8be11965d3ce,  -282), (0xdd6a8ce11965d581, -1429),
    (0xdd8ef3d56f59ded4, -1429), (0xdda44b8ebf209b09, -2274), (0xddcb101ccfa1980c, -2274), (0xddcb83ee995267c6, -2274),
    (0xdde502e673e876ff, -2274), (0xdde8aa294c7c8dba, -2274), (0xdde8d31d9e48aa47, -2274), (0xde52bc5f00a86f4b, -2274),
    (0xde647e2af92c3864, -1797), (0xdeadcb5b9909908e, -2274), (0xdec3d732730f04f0, -1973), (0xdef1e98f7a5b7f42, -2274),
    (0xdf24976a65b97a35, -2274), (0xdf27d1c22fe65a9b, -1973), (0xdf3f8f5dcb4ae8ed, -2274), (0xdf556328b60c6d83, -1797),
    (0xdf57d81be11513c4, -2274), (0xdfced088e2606791, -2274), (0xdfd78a6d87caeedf, -2274), (0xe021c1e9d9afb427, -2274),
    (0xe092e52febfbfb69, -2274), (0xe0beec50ba7e4b07, -2274), (0xe0c5a6976203bd57, -2274), (0xe0e85ac57db2c15b, -2274),
    (0xe10b84555bda8b9d, -2274), (0xe11ccbe0ef60e7fa, -1319), (0xe123104118256cf2, -2274), (0xe12e81a4ecda8281, -2274),
    (0xe159b3fcc46e9800, -2274), (0xe162ebb1df690374, -2274), (0xe16d376d0395e186, -2274), (0xe17c9189cbee0f8d, -2274),
    (0xe199c60cd6c5bc85, -1797), (0xe27526d4213ffe9d, -2274), (0xe2795538373c0e4c, -2274), (0xe31e12dbba0bee74, -1672),
    (0xe33418c7c30feb4e, -2274), (0xe33e94609cbe335f, -2274), (0xe365e696c8ef5bc1, -2274), (0xe3754f12c0416837, -1973),
    (0xe3bfcd9c96036d6b, -2274), (0xe3c4e5e6e357bd45, -2274), (0xe3fe5afd80cc06a0, -2274), (0xe43fb45ea9f0dbaf, -2274),
    (0xe47b9787b86e6e34, -2274), (0xe523dc5e922ce63e, -2274), (0xe5c59a1be62de9cf, -2274), (0xe61b3fbea3c959d6,  -416),
    (0xe61dc4275a76e145, -1973), (0xe61ea4bea3cc3b4c,  -344), (0xe61ea5bea3cc3cff, -1070), (0xe6295cf7a1fa5438, -1070),
    (0xe62a9dc09f693085, -1496), (0xe64c4a1c7f926b62, -2274), (0xe6e346a658dadef9, -1973), (0xe6f57be57edc7bed, -1496),
    (0xe70b18fa3cdf9e25, -2274), (0xe711afd1ce049834,  -951), (0xe72ec9c714f93671, -2274), (0xe733435119e3929c, -2274),
    (0xe73e4b1e91bfb699, -1371), (0xe74b39a9d690ed8e, -2274), (0xe7767a7b27392004, -2274), (0xe77a1a07cac24833, -2274),
    (0xe77d9a36b650c02c, -1973), (0xe78713acf0bc2c8c, -1797), (0xe794f85c5507262c, -2274), (0xe7bbc495a962ed6c, -2274),
    (0xe7f6e3b2d59a11db, -2274), (0xe863938150f5e4fc, -1672), (0xe86e368e9dcd1e9c, -1043), (0xe8d67a03cde82b5b, -1973),
    (0xe8e2158ffb305219, -2274), (0xe8efae0bbba275c7, -2274), (0xe906af1076a2e5f5, -2274), (0xe911e5f9af65e561, -1973),
    (0xe95a347581a12c48, -1973), (0xe97b0cea0d933feb, -1429), (0xe989255051c1da60, -1973), (0xe98dd74db99b11b8, -2274),
    (0xe9a46abeff766748, -1429), (0xe9c165dc927efefa, -2274), (0xea395534c9fb5df4, -1973), (0xea540bb27d154110, -1973),
    (0xea8fb0dcecf2275a, -2274), (0xeb4515d9f3c9c172, -1672), (0xebd8beb4e6156de0, -2274), (0xec2eb0c130008b8a, -2274),
    (0xec41b39d6e1b97a9, -2274), (0xec5846b490abdcdc, -2274), (0xeca759ade6161257, -2274), (0xed6c3bccf9021468, -1797),
    (0xedbad7949fbde449, -2274), (0xedeccbde5d7799f3, -1575), (0xedf46f9ea6fe6d54, -1973), (0xee0a1010059ef075, -2274),
    (0xee1d18dbe3c44e1f, -2274), (0xee48667f54bea84b, -2274), (0xee50cc725056af63, -2274), (0xee54a834009751a0, -2274),
    (0xee6893424ee373b8, -1429), (0xee74810f392b21a0, -1973), (0xeeb65a39c9ed0c45, -2274), (0xef0f3a4695ba163e, -2274),
    (0xef263b57e87fa690, -2274), (0xef36ab955747d04a, -2274), (0xef3aac08b09d2249, -1672), (0xef46ce740bcb2485, -2274),
    (0xef4d437a6d3a524e, -2274), (0xefb4723519a82a11, -1672), (0xf023af36bb35dbae, -1160), (0xf023b036bb35dd61, -1672),
    (0xf0271536bb38bed7, -1371), (0xf028aa5e02497f94, -2274), (0xf03f552d3bd947cf, -2274), (0xf08bee460006d3c3, -1973),
    (0xf0a64b5ef534fb3e, -2274), (0xf0ab111752c25513, -1797), (0xf0c6c4d5548847e4, -2274), (0xf1c3e16d1567d771, -1973),
    (0xf1d8028b47e5077a, -2274), (0xf1ebd66d8d05884b, -1797), (0xf259ef69fb69055d, -2274), (0xf261c17d54e62b54, -2274),
    (0xf29bed2f336e0e62, -1496), (0xf2b267e06d23b334, -2274), (0xf2be626be0a8b956, -2274), (0xf30532c355dbe875, -2274),
    (0xf31e2c766a5e07b3, -1797), (0xf380a340243bd94f, -2274), (0xf3975d440bc5f4c7, -2274), (0xf3cbea0d23acff2e, -2274),
    (0xf421f71881ec3ebf, -2274), (0xf42cd2cfd1ea5e0b, -2274), (0xf443cce4292fd148, -2274), (0xf469a650ff39066a, -2274),
    (0xf46e318b08dfc1ce, -2274), (0xf49f99838242c17d, -1973), (0xf4c13b7ab62043ae, -2274), (0xf4d8970fc5e76afb, -2274),
    (0xf4faf7c6fc59f8d3, -1973), (0xf5351367431c2dfa,  -278), (0xf55ca8d95956da7f, -2274), (0xf571b9ec7f408f14, -2274),
    (0xf58f21073351170e, -2274), (0xf598b6014503a9ad, -2274), (0xf5cbc8289b8e3b92, -2274), (0xf60e2e6ddf74f103, -1429),
    (0xf6bae8c69119b64d, -2274), (0xf700eac98ca93a17, -2274), (0xf719b1fb03ea9707, -1797), (0xf730d59531bd325a, -2274),
    (0xf73680a01e19424a, -2274), (0xf75983109756681e, -2274), (0xf761a7b3b81c6ae6, -1429), (0xf7720f5e3edb7a1a, -1797),
    (0xf7acde0c3ee83218, -2274), (0xf7fd4aee5c95982a,  -826), (0xf80c18ba79d3249c, -1973), (0xf84fbf7dd4dd616b, -2274),
    (0xf895fa94621a19b2, -2274), (0xf8b5fdb86c5c724a,  -371), (0xf8dcf3f1984cd6b4, -2274), (0xf8def55e446b6d49, -1232),
    (0xf8fdeb49f66761ab, -2274), (0xf96f96602bfc60bf, -2274), (0xf9746470d0aaea09, -1575), (0xf9a084f8c51ab19a, -2274),
    (0xf9dc240a576cf703, -1973), (0xfa1e836f6645134a, -2274), (0xfa3272dab6783338, -2274), (0xfa5ac66e0de0efbb, -2274),
    (0xfa72d21f91f6726a, -2274), (0xfaa1cc9e41e6dedb, -1797), (0xfaab156a2ea98378, -2274), (0xfaac3148f0973fd0, -2274),
    (0xfacec7cbbb840262, -2274), (0xfadfb5545e2d0e01, -1496), (0xfaef20c7ccaa5c8e, -2274), (0xfaf6be64f9238a2a, -1973),
    (0xfb19960664481d36, -2274), (0xfb1b31d98c5d6650, -2274), (0xfb33e9cc4397a662, -2274), (0xfb5c1b735603cc40, -1973),
    (0xfb686e4d6675a140, -1319), (0xfb9e60a825cb0404, -2274), (0xfbaa27a0955e4ee9, -2274), (0xfbb834dd2a162ba4, -1797),
    (0xfbf5a5f8fc152312, -2274), (0xfc19ede177184d7e, -2274), (0xfc258f05bb50ec30, -2274), (0xfc382071b5ac689b, -2274),
    (0xfcbed3fb98880984, -1973), (0xfcd62fdf2d29ccae, -2274), (0xfd1bc33167637957, -2274), (0xfd4b3cd1601caf52, -1128),
    (0xfd6f7bc3d9adb20d, -1973), (0xfda56976c632fa2d, -1973), (0xfdacc6b2e03f4267, -1973), (0xfdd373bf87555078, -2274),
    (0xfdfb50692e48fb44, -2274), (0xfe1b60ab53800382, -1797), (0xfe875568bc4611c7, -1973), (0xfeb557f1070a6a57, -1797),
    (0xfee63fc5280c4b76, -2274), (0xff1550139397a305, -2274), (0xff23115b6e867650, -2274), (0xff66871f6556f2e9, -2274),
    (0xff76f0274ea81c2d, -2274), (0xff7b9ba5052ffe35, -1672), (0xff898f9fe471ed19, -2274),
];

const DEFAULT_LOG_FREQ: f64 = -5.0;

#[inline]
fn lookup_score(hash: u64) -> f64 {
    let idx = FRAGMENT_SCORES.partition_point(|&(h, _)| h < hash);
    if idx < FRAGMENT_SCORES.len() && FRAGMENT_SCORES[idx].0 == hash {
        FRAGMENT_SCORES[idx].1 as f64 / 1000.0
    } else {
        DEFAULT_LOG_FREQ
    }
}

// ---------------------------------------------------------------------------
// Complexity corrections
// ---------------------------------------------------------------------------

fn complexity_penalty(mol: &Molecule) -> f64 {
    let n = mol.atom_count() as f64;
    if n == 0.0 {
        return 0.0;
    }

    let spiro = num_spiro_atoms(mol) as f64;
    let bridge = num_bridgehead_atoms(mol) as f64;
    let rings = ring_count(mol) as f64;
    let stereo = num_stereocenters(mol) as f64;

    let macro_count = count_macrorings(mol) as f64;

    let bond_n = mol.bond_count() as f64;
    let ring_bond_frac = if bond_n > 0.0 {
        ring_bond_count(mol) as f64 / bond_n
    } else {
        0.0
    };

    let penalty = spiro * 0.25
        + bridge * 0.35
        + macro_count * 0.30
        + stereo * 0.10
        + (rings - 1.0).max(0.0) * 0.05
        + ring_bond_frac * 0.50;

    let size_penalty = (n / 10.0 - 1.0).max(0.0) * 0.05;

    penalty + size_penalty
}

fn count_macrorings(mol: &Molecule) -> usize {
    let n = mol.atom_count();
    let rings = ring_count(mol);
    if rings == 0 {
        return 0;
    }
    let avg_ring_size = n as f64 / rings as f64;
    if avg_ring_size > 8.0 { 1 } else { 0 }
}

fn ring_bond_count(mol: &Molecule) -> usize {
    let n = mol.atom_count();
    let mut in_ring = vec![false; mol.bond_count()];
    let mut visited = vec![false; n];
    let mut bond_idx_map: HashMap<(usize, usize), usize> = HashMap::new();
    for (bidx, bond) in mol.bonds() {
        let i = bond.atom1.0 as usize;
        let j = bond.atom2.0 as usize;
        bond_idx_map.insert((i.min(j), i.max(j)), bidx.0 as usize);
    }

    let adj: Vec<Vec<usize>> = (0..n)
        .map(|i| {
            mol.neighbors(AtomIdx(i as u32))
                .map(|(nb, _)| nb.0 as usize)
                .collect()
        })
        .collect();

    let mut stack: Vec<(usize, usize, usize)> = Vec::new();
    for root in 0..n {
        if visited[root] {
            continue;
        }
        stack.push((root, usize::MAX, 0));
        while let Some((cur, par, d)) = stack.pop() {
            if visited[cur] {
                continue;
            }
            visited[cur] = true;
            let _ = d;
            for &nb in &adj[cur] {
                if nb == par {
                    continue;
                }
                if visited[nb] {
                    let key = (cur.min(nb), cur.max(nb));
                    if let Some(&bi) = bond_idx_map.get(&key) {
                        in_ring[bi] = true;
                    }
                } else {
                    stack.push((nb, cur, 0));
                }
            }
        }
    }
    in_ring.iter().filter(|&&r| r).count()
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

/// Compute the Synthetic Accessibility Score for `mol`.
///
/// Returns a value in \[1, 10\]: 1 = trivially easy, 10 = very hard to synthesize.
///
/// Fragment environments use the same FNV-1a hash scheme as ECFP fingerprints
/// (`chematic_fp::morgan_fp_counts`), so the fragment table is directly
/// compatible with ECFP4 lookups.
pub fn sa_score(mol: &Molecule) -> f64 {
    let n = mol.atom_count();
    if n == 0 {
        return 10.0;
    }

    // Collect all circular environments at radii 0–2 with their occurrence counts.
    let counts = morgan_fp_counts(mol, 2);
    let total_frags: u32 = counts.values().sum();
    if total_frags == 0 {
        return 10.0;
    }

    // Fragment score = mean of log10(frequency) over all environment instances.
    // Environments not in the table use DEFAULT_LOG_FREQ (very rare).
    let total_score: f64 = counts
        .iter()
        .map(|(&hash, &count)| lookup_score(hash) * count as f64)
        .sum();
    let fscore = total_score / total_frags as f64;

    let cscore = complexity_penalty(mol);

    // Raw score: higher fscore (common fragments) → easier; higher cscore → harder.
    let raw = fscore * 2.0 - cscore * 4.5;

    // Map raw ∈ (−∞, 0] → sa ∈ [1, 10].
    let sa = 1.0 + (-raw).max(0.0);
    sa.clamp(1.0, 10.0)
}

#[cfg(test)]
mod tests {
    use super::*;
    use chematic_smiles::parse;

    fn mol(s: &str) -> Molecule {
        parse(s).unwrap()
    }

    #[test]
    fn sa_score_in_range_1_to_10() {
        for s in &["C", "CC(=O)O", "c1ccccc1", "CC(=O)Oc1ccccc1C(=O)O"] {
            let score = sa_score(&mol(s));
            assert!(
                (1.0..=10.0).contains(&score),
                "SA score for {s} = {score:.2} is out of [1, 10]"
            );
        }
    }

    #[test]
    fn simple_molecule_lower_than_complex() {
        let simple = sa_score(&mol("CC"));
        let complex = sa_score(&mol("C1CC2(CC1)CCCC2")); // spiro bicyclic
        assert!(
            simple <= complex,
            "simple {simple:.2} should be ≤ complex {complex:.2}"
        );
    }

    #[test]
    fn methane_is_easy() {
        let score = sa_score(&mol("C"));
        assert!(
            score < 6.0,
            "methane SA score should be < 6, got {score:.2}"
        );
    }

    #[test]
    fn taxol_harder_than_aspirin() {
        let aspirin = sa_score(&mol("CC(=O)Oc1ccccc1C(=O)O"));
        let taxol = sa_score(&mol(
            "CC1=C2C(C(=O)C3(C(CC4C(C3C(C(=C2OC1=O)C)(C)C)OC(=O)C5=CC=CC=C5)OC(=O)C4)O)(C)C",
        ));
        assert!(
            aspirin < taxol,
            "aspirin ({aspirin:.2}) should be easier than taxol ({taxol:.2})"
        );
    }
}