synkit 1.6.5__py3-none-win_amd64.whl
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.
- synkit/CRN/Benchmark/__init__.py +53 -0
- synkit/CRN/Benchmark/crosschecks.py +13 -0
- synkit/CRN/Benchmark/kegg.py +12 -0
- synkit/CRN/Benchmark/networks.py +13 -0
- synkit/CRN/Benchmark/scaling.py +13 -0
- synkit/CRN/Benchmark/validate.py +13 -0
- synkit/CRN/Construct/__init__.py +16 -0
- synkit/CRN/Construct/abstract.py +668 -0
- synkit/CRN/Construct/arity.py +36 -0
- synkit/CRN/Construct/builder.py +619 -0
- synkit/CRN/Construct/derivation.py +63 -0
- synkit/CRN/Construct/flattener.py +100 -0
- synkit/CRN/Construct/keys.py +14 -0
- synkit/CRN/Construct/mixtures.py +117 -0
- synkit/CRN/Construct/rdkit_worker.py +69 -0
- synkit/CRN/Construct/smiles.py +99 -0
- synkit/CRN/Construct/state.py +31 -0
- synkit/CRN/Construct/strategy.py +75 -0
- synkit/CRN/Construct/worker.py +42 -0
- synkit/CRN/IO/__init__.py +36 -0
- synkit/CRN/IO/sbml.py +925 -0
- synkit/CRN/Pathway/__init__.py +72 -0
- synkit/CRN/Pathway/_adapter.py +333 -0
- synkit/CRN/Pathway/pathfinder.py +500 -0
- synkit/CRN/Pathway/reachability.py +796 -0
- synkit/CRN/Pathway/realizability.py +1322 -0
- synkit/CRN/Petrinet/__init__.py +93 -0
- synkit/CRN/Petrinet/analyzer.py +486 -0
- synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
- synkit/CRN/Petrinet/net.py +1041 -0
- synkit/CRN/Petrinet/persistence.py +97 -0
- synkit/CRN/Petrinet/semiflows.py +483 -0
- synkit/CRN/Petrinet/siphon_search.py +402 -0
- synkit/CRN/Petrinet/structure.py +286 -0
- synkit/CRN/Props/__init__.py +130 -0
- synkit/CRN/Props/_rank.py +29 -0
- synkit/CRN/Props/deficiency.py +953 -0
- synkit/CRN/Props/dynamics.py +832 -0
- synkit/CRN/Props/helper.py +151 -0
- synkit/CRN/Props/stoich.py +751 -0
- synkit/CRN/Props/thermo.py +584 -0
- synkit/CRN/Query/__init__.py +66 -0
- synkit/CRN/Query/cache.py +41 -0
- synkit/CRN/Query/kegg_api.py +99 -0
- synkit/CRN/Query/kegg_extract.py +714 -0
- synkit/CRN/Query/kegg_impute.py +707 -0
- synkit/CRN/Query/kegg_parse.py +480 -0
- synkit/CRN/Query/to_syncrn.py +290 -0
- synkit/CRN/README.md +234 -0
- synkit/CRN/Structure/__init__.py +12 -0
- synkit/CRN/Structure/_graph_io.py +713 -0
- synkit/CRN/Structure/_matrices.py +88 -0
- synkit/CRN/Structure/_parse.py +544 -0
- synkit/CRN/Structure/reaction.py +237 -0
- synkit/CRN/Structure/rule.py +55 -0
- synkit/CRN/Structure/species.py +46 -0
- synkit/CRN/Structure/syncrn.py +929 -0
- synkit/CRN/Symmetry/__init__.py +20 -0
- synkit/CRN/Symmetry/_common.py +1059 -0
- synkit/CRN/Symmetry/_ir.py +940 -0
- synkit/CRN/Symmetry/automorphism.py +472 -0
- synkit/CRN/Symmetry/canon.py +441 -0
- synkit/CRN/Symmetry/isomorphism.py +412 -0
- synkit/CRN/Symmetry/symmetry.py +61 -0
- synkit/CRN/Symmetry/wl_canon.py +967 -0
- synkit/CRN/Visualize/__init__.py +11 -0
- synkit/CRN/Visualize/labels.py +113 -0
- synkit/CRN/Visualize/layout.py +708 -0
- synkit/CRN/Visualize/palette.py +292 -0
- synkit/CRN/Visualize/validation.py +122 -0
- synkit/CRN/Visualize/vis.py +1152 -0
- synkit/CRN/__init__.py +233 -0
- synkit/CRN/_build.py +50 -0
- synkit/CRN/_native_build.py +175 -0
- synkit/CRN/analysis.py +629 -0
- synkit/CRN/backend.py +74 -0
- synkit/CRN/cpp/CMakeLists.txt +58 -0
- synkit/CRN/cpp/algebra.cpp +46 -0
- synkit/CRN/cpp/closure.cpp +29 -0
- synkit/CRN/cpp/exact.h +55 -0
- synkit/CRN/cpp/pathway.cpp +46 -0
- synkit/CRN/cpp/semiflows.cpp +209 -0
- synkit/CRN/cpp/structural.cpp +240 -0
- synkit/CRN/cpp/symmetry.cpp +45 -0
- synkit/CRN/cpp/write_manifest.cmake +28 -0
- synkit/CRN/kinds.py +137 -0
- synkit/CRN/lib/synkit_crn.dll +0 -0
- synkit/CRN/lib/synkit_crn.json +33 -0
- synkit/CRN/native.py +388 -0
- synkit/CRN/native_analysis.py +459 -0
- synkit/Chem/Cluster/__init__.py +0 -0
- synkit/Chem/Cluster/butina.py +140 -0
- synkit/Chem/Fingerprint/__init__.py +0 -0
- synkit/Chem/Fingerprint/fp_calculator.py +155 -0
- synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
- synkit/Chem/Fingerprint/transformation_fp.py +139 -0
- synkit/Chem/Mapper/README.rst +43 -0
- synkit/Chem/Mapper/__init__.py +255 -0
- synkit/Chem/Mapper/_compat.py +130 -0
- synkit/Chem/Mapper/adapters/__init__.py +1 -0
- synkit/Chem/Mapper/adapters/prediction.py +126 -0
- synkit/Chem/Mapper/adapters/template.py +412 -0
- synkit/Chem/Mapper/chem/__init__.py +52 -0
- synkit/Chem/Mapper/chem/aam.py +673 -0
- synkit/Chem/Mapper/chem/blind.py +160 -0
- synkit/Chem/Mapper/chem/its.py +309 -0
- synkit/Chem/Mapper/chem/smiles.py +564 -0
- synkit/Chem/Mapper/graph/__init__.py +66 -0
- synkit/Chem/Mapper/graph/automorphism.py +395 -0
- synkit/Chem/Mapper/graph/blockcut.py +98 -0
- synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
- synkit/Chem/Mapper/graph/refine.py +176 -0
- synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
- synkit/Chem/Mapper/io/__init__.py +13 -0
- synkit/Chem/Mapper/io/idxmapstr.py +82 -0
- synkit/Chem/Mapper/mapper.py +685 -0
- synkit/Chem/Mapper/reaction_search.py +554 -0
- synkit/Chem/Mapper/reporting/__init__.py +1 -0
- synkit/Chem/Mapper/reporting/alternatives.py +451 -0
- synkit/Chem/Mapper/reporting/analysis.py +681 -0
- synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
- synkit/Chem/Mapper/reporting/spectrum.py +642 -0
- synkit/Chem/Mapper/solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
- synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
- synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
- synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
- synkit/Chem/Mapper/solvers/exact/core.py +183 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
- synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
- synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
- synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
- synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
- synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
- synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
- synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
- synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
- synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
- synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
- synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
- synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
- synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
- synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
- synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
- synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
- synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
- synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
- synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
- synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
- synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
- synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
- synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
- synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
- synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
- synkit/Chem/Mapper/solvers/exact/search.py +55 -0
- synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
- synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
- synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
- synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
- synkit/Chem/Mapper/solvers/native/astar.py +22 -0
- synkit/Chem/Mapper/solvers/native/build.py +385 -0
- synkit/Chem/Mapper/solvers/native/classification.py +641 -0
- synkit/Chem/Mapper/solvers/native/core.py +378 -0
- synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
- synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
- synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
- synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
- synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
- synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
- synkit/Chem/Mapper/solvers/native/mces.py +16 -0
- synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
- synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
- synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
- synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
- synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
- synkit/Chem/Mapper/solvers/native/slap.py +266 -0
- synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
- synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
- synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
- synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
- synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
- synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
- synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
- synkit/Chem/Mapper/validation/__init__.py +1 -0
- synkit/Chem/Mapper/validation/aam_validator.py +442 -0
- synkit/Chem/Mapper/validation/annotations.py +274 -0
- synkit/Chem/Mapper/validation/bonds.py +124 -0
- synkit/Chem/Mapper/validation/cohorts.py +72 -0
- synkit/Chem/Mapper/validation/identifiability.py +150 -0
- synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
- synkit/Chem/Mapper/validation/orbits.py +137 -0
- synkit/Chem/Molecule/__init__.py +0 -0
- synkit/Chem/Molecule/_chirality_loci.py +165 -0
- synkit/Chem/Molecule/_chirality_types.py +231 -0
- synkit/Chem/Molecule/_helical_loci.py +167 -0
- synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
- synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
- synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
- synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
- synkit/Chem/Molecule/atom_features.py +379 -0
- synkit/Chem/Molecule/chirality.py +1041 -0
- synkit/Chem/Molecule/cip_assignment.py +569 -0
- synkit/Chem/Molecule/cip_ranking.py +843 -0
- synkit/Chem/Molecule/coordinate_stereo.py +503 -0
- synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
- synkit/Chem/Molecule/descriptors.py +452 -0
- synkit/Chem/Molecule/formula.py +249 -0
- synkit/Chem/Molecule/global_stereo.py +175 -0
- synkit/Chem/Molecule/graph_annotator.py +300 -0
- synkit/Chem/Molecule/standardize.py +817 -0
- synkit/Chem/Molecule/stereo_evidence.py +179 -0
- synkit/Chem/Molecule/stereo_perception.py +1032 -0
- synkit/Chem/Molecule/valence.py +123 -0
- synkit/Chem/Reaction/Mapper/__init__.py +44 -0
- synkit/Chem/Reaction/__init__.py +20 -0
- synkit/Chem/Reaction/aam_validator.py +5 -0
- synkit/Chem/Reaction/balance_check.py +138 -0
- synkit/Chem/Reaction/canon_rsmi.py +249 -0
- synkit/Chem/Reaction/cleaning.py +58 -0
- synkit/Chem/Reaction/deionize.py +199 -0
- synkit/Chem/Reaction/explicit_h_audit.py +232 -0
- synkit/Chem/Reaction/fix_aam.py +64 -0
- synkit/Chem/Reaction/neutralize.py +207 -0
- synkit/Chem/Reaction/radical_wildcard.py +224 -0
- synkit/Chem/Reaction/standardize.py +203 -0
- synkit/Chem/Reaction/tautomerize.py +205 -0
- synkit/Chem/__init__.py +1 -0
- synkit/Chem/utils.py +315 -0
- synkit/Data/__init__.py +0 -0
- synkit/Data/aldol.json.gz +1 -0
- synkit/Data/gen_partial_aam.py +147 -0
- synkit/Data/paracetamol.json.gz +1 -0
- synkit/Graph/Canon/__init__.py +16 -0
- synkit/Graph/Canon/_native/__init__.py +13 -0
- synkit/Graph/Canon/_native/build.py +93 -0
- synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
- synkit/Graph/Canon/_native/prepare.py +49 -0
- synkit/Graph/Canon/_native/runtime.py +140 -0
- synkit/Graph/Canon/_native/search.py +137 -0
- synkit/Graph/Canon/canon_algs.py +228 -0
- synkit/Graph/Canon/canon_graph.py +531 -0
- synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
- synkit/Graph/Canon/cpp/README.md +123 -0
- synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
- synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
- synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
- synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
- synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
- synkit/Graph/Canon/exact.py +1020 -0
- synkit/Graph/Canon/exact_refinement.py +368 -0
- synkit/Graph/Canon/nauty.py +143 -0
- synkit/Graph/Context/__init__.py +0 -0
- synkit/Graph/Context/hier_context.py +244 -0
- synkit/Graph/Context/radius_expand.py +252 -0
- synkit/Graph/FG/__init__.py +19 -0
- synkit/Graph/FG/api.py +39 -0
- synkit/Graph/FG/audit.py +155 -0
- synkit/Graph/FG/catalog.py +919 -0
- synkit/Graph/FG/detector.py +288 -0
- synkit/Graph/FG/model.py +97 -0
- synkit/Graph/FG/recognizers.py +274 -0
- synkit/Graph/FG/ring_system.py +154 -0
- synkit/Graph/Feature/Descriptors/topology.py +857 -0
- synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
- synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
- synkit/Graph/Feature/__init__.py +5 -0
- synkit/Graph/Feature/graph_descriptors.py +323 -0
- synkit/Graph/Feature/graph_fps.py +96 -0
- synkit/Graph/Feature/graph_signature.py +239 -0
- synkit/Graph/Feature/hash_fps.py +133 -0
- synkit/Graph/Feature/morgan_fps.py +88 -0
- synkit/Graph/Feature/path_fps.py +81 -0
- synkit/Graph/Feature/wl_hash.py +134 -0
- synkit/Graph/Fusion/__init__.py +85 -0
- synkit/Graph/Fusion/candidate.py +559 -0
- synkit/Graph/Fusion/constructor.py +877 -0
- synkit/Graph/Fusion/identity.py +184 -0
- synkit/Graph/Fusion/interface.py +700 -0
- synkit/Graph/Fusion/search.py +241 -0
- synkit/Graph/Hyrogen/__init__.py +6 -0
- synkit/Graph/Hyrogen/_misc.py +591 -0
- synkit/Graph/Hyrogen/hcomplete.py +995 -0
- synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
- synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
- synkit/Graph/Hyrogen/hextend.py +570 -0
- synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
- synkit/Graph/ITS/__init__.py +4 -0
- synkit/Graph/ITS/its_builder.py +120 -0
- synkit/Graph/ITS/its_construction.py +719 -0
- synkit/Graph/ITS/its_decompose.py +572 -0
- synkit/Graph/ITS/its_destruction.py +331 -0
- synkit/Graph/ITS/its_expand.py +1251 -0
- synkit/Graph/ITS/its_relabel.py +187 -0
- synkit/Graph/ITS/its_reverter.py +356 -0
- synkit/Graph/ITS/normalize_aam.py +145 -0
- synkit/Graph/ITS/partial_its.py +238 -0
- synkit/Graph/ITS/rc_extractor.py +656 -0
- synkit/Graph/ITS/stereo.py +74 -0
- synkit/Graph/MTG/__init__.py +107 -0
- synkit/Graph/MTG/gluing.py +451 -0
- synkit/Graph/MTG/history.py +928 -0
- synkit/Graph/MTG/inventory.py +118 -0
- synkit/Graph/MTG/local.py +447 -0
- synkit/Graph/MTG/mcs_matcher.py +246 -0
- synkit/Graph/MTG/mtg.py +611 -0
- synkit/Graph/MTG/mtg_explore.py +74 -0
- synkit/Graph/MTG/observation.py +209 -0
- synkit/Graph/MTG/process.py +577 -0
- synkit/Graph/MTG/queries.py +66 -0
- synkit/Graph/MTG/realization.py +95 -0
- synkit/Graph/MTG/series_parallel.py +107 -0
- synkit/Graph/MTG/utils.py +424 -0
- synkit/Graph/Matcher/__init__.py +10 -0
- synkit/Graph/Matcher/approx_mcs.py +1264 -0
- synkit/Graph/Matcher/auto_est.py +736 -0
- synkit/Graph/Matcher/automorphism.py +314 -0
- synkit/Graph/Matcher/batch_cluster.py +224 -0
- synkit/Graph/Matcher/dedup_matches.py +247 -0
- synkit/Graph/Matcher/graph_cluster.py +191 -0
- synkit/Graph/Matcher/graph_matcher.py +312 -0
- synkit/Graph/Matcher/graph_morphism.py +421 -0
- synkit/Graph/Matcher/mcs_matcher.py +804 -0
- synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
- synkit/Graph/Matcher/orbit.py +284 -0
- synkit/Graph/Matcher/partial_matcher.py +694 -0
- synkit/Graph/Matcher/sing.py +544 -0
- synkit/Graph/Matcher/subgraph_matcher.py +812 -0
- synkit/Graph/Matcher/turbo_iso.py +272 -0
- synkit/Graph/Matcher/wl_sel.py +537 -0
- synkit/Graph/Mech/__init__.py +26 -0
- synkit/Graph/Mech/conversion.py +1466 -0
- synkit/Graph/Mech/conversion_debug.py +237 -0
- synkit/Graph/Mech/electron_accounting.py +200 -0
- synkit/Graph/Mech/lwg_editor.py +406 -0
- synkit/Graph/Mech/lwg_ops.py +313 -0
- synkit/Graph/Morphism/__init__.py +99 -0
- synkit/Graph/Morphism/constraints.py +460 -0
- synkit/Graph/Morphism/llg.py +999 -0
- synkit/Graph/Morphism/morphism.py +349 -0
- synkit/Graph/Morphism/stereo.py +258 -0
- synkit/Graph/Morphism/stereo_morphism.py +383 -0
- synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
- synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
- synkit/Graph/Stereo/__init__.py +376 -0
- synkit/Graph/Stereo/_descriptor_core.py +207 -0
- synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
- synkit/Graph/Stereo/canonical.py +648 -0
- synkit/Graph/Stereo/changes.py +964 -0
- synkit/Graph/Stereo/composition.py +391 -0
- synkit/Graph/Stereo/configured.py +946 -0
- synkit/Graph/Stereo/couplings.py +245 -0
- synkit/Graph/Stereo/descriptors.py +1030 -0
- synkit/Graph/Stereo/enumeration.py +597 -0
- synkit/Graph/Stereo/extended_descriptors.py +406 -0
- synkit/Graph/Stereo/global_configured.py +152 -0
- synkit/Graph/Stereo/global_stereo.py +304 -0
- synkit/Graph/Stereo/identity.py +648 -0
- synkit/Graph/Stereo/interchange.py +496 -0
- synkit/Graph/Stereo/legacy.py +460 -0
- synkit/Graph/Stereo/matching.py +899 -0
- synkit/Graph/Stereo/native.py +154 -0
- synkit/Graph/Stereo/orbits.py +668 -0
- synkit/Graph/Stereo/outcomes.py +99 -0
- synkit/Graph/Stereo/pairwise.py +350 -0
- synkit/Graph/Stereo/rdkit_adapter.py +662 -0
- synkit/Graph/Stereo/rdkit_identity.py +118 -0
- synkit/Graph/Stereo/rdkit_resonance.py +140 -0
- synkit/Graph/Stereo/reaction_interchange.py +266 -0
- synkit/Graph/Stereo/semantics.py +296 -0
- synkit/Graph/Stereo/supports.py +257 -0
- synkit/Graph/Stereo/wire.py +339 -0
- synkit/Graph/Wildcard/__init__.py +0 -0
- synkit/Graph/Wildcard/fuse_graph.py +156 -0
- synkit/Graph/Wildcard/graph_wc.py +303 -0
- synkit/Graph/Wildcard/its_merge.py +857 -0
- synkit/Graph/Wildcard/radwc.py +114 -0
- synkit/Graph/Wildcard/wc_matcher.py +576 -0
- synkit/Graph/Wildcard/wildcard.py +225 -0
- synkit/Graph/__init__.py +17 -0
- synkit/Graph/canon_graph.py +14 -0
- synkit/Graph/syn_graph.py +199 -0
- synkit/Graph/utils.py +324 -0
- synkit/IO/__init__.py +4 -0
- synkit/IO/chem_converter.py +1059 -0
- synkit/IO/combinatorial/__init__.py +8 -0
- synkit/IO/combinatorial/gml_to_graph.py +223 -0
- synkit/IO/combinatorial/graph_to_gml.py +280 -0
- synkit/IO/combinatorial/graph_to_smarts.py +186 -0
- synkit/IO/combinatorial/smarts_expander.py +147 -0
- synkit/IO/combinatorial/smarts_generalizer.py +133 -0
- synkit/IO/combinatorial/smarts_to_graph.py +179 -0
- synkit/IO/conversion.py +42 -0
- synkit/IO/data_io.py +269 -0
- synkit/IO/data_process.py +143 -0
- synkit/IO/debug.py +73 -0
- synkit/IO/gml_to_nx.py +150 -0
- synkit/IO/graph_to_mol.py +199 -0
- synkit/IO/mol_to_graph.py +1105 -0
- synkit/IO/mol_to_graph_chemistry.py +545 -0
- synkit/IO/nx_to_gml.py +209 -0
- synkit/IO/smiles_to_id.py +123 -0
- synkit/Mechanism/__init__.py +151 -0
- synkit/Mechanism/adapters.py +136 -0
- synkit/Mechanism/audit.py +323 -0
- synkit/Mechanism/benchmark.py +638 -0
- synkit/Mechanism/compatibility.py +13 -0
- synkit/Mechanism/drawing.py +85 -0
- synkit/Mechanism/electron_models.py +725 -0
- synkit/Mechanism/equivalence.py +521 -0
- synkit/Mechanism/evidence.py +262 -0
- synkit/Mechanism/interchange.py +141 -0
- synkit/Mechanism/model.py +918 -0
- synkit/Mechanism/neighbor_stereo.py +312 -0
- synkit/Mechanism/radical_data.py +740 -0
- synkit/Mechanism/replay.py +986 -0
- synkit/Mechanism/schema.py +264 -0
- synkit/Mechanism/stereo_state.py +416 -0
- synkit/Mechanism/symbols.py +91 -0
- synkit/Rule/Apply/__init__.py +35 -0
- synkit/Rule/Apply/conditions.py +45 -0
- synkit/Rule/Apply/dpo.py +998 -0
- synkit/Rule/Apply/rule_matcher.py +218 -0
- synkit/Rule/Apply/validation.py +354 -0
- synkit/Rule/Compose/__init__.py +106 -0
- synkit/Rule/Compose/_identity.py +43 -0
- synkit/Rule/Compose/composition.py +976 -0
- synkit/Rule/Compose/laws.py +439 -0
- synkit/Rule/Compose/search.py +771 -0
- synkit/Rule/Compose/synrule.py +170 -0
- synkit/Rule/Modify/__init__.py +0 -0
- synkit/Rule/Modify/implict_rule.py +56 -0
- synkit/Rule/Modify/longest_path.py +92 -0
- synkit/Rule/Modify/molecule_rule.py +115 -0
- synkit/Rule/Modify/prune_templates.py +78 -0
- synkit/Rule/Modify/rule_utils.py +194 -0
- synkit/Rule/Modify/strip_rule.py +97 -0
- synkit/Rule/__init__.py +28 -0
- synkit/Rule/generic_stereo.py +884 -0
- synkit/Rule/stereo_identity.py +271 -0
- synkit/Rule/syn_rule.py +1090 -0
- synkit/Synthesis/MSR/__init__.py +0 -0
- synkit/Synthesis/MSR/path_finder.py +239 -0
- synkit/Synthesis/Metrics/__init__.py +0 -0
- synkit/Synthesis/Metrics/_base.py +52 -0
- synkit/Synthesis/Metrics/_plot.py +129 -0
- synkit/Synthesis/Metrics/_ranking.py +179 -0
- synkit/Synthesis/RBL/__init__.py +80 -0
- synkit/Synthesis/RBL/engine.py +1249 -0
- synkit/Synthesis/RBL/matching.py +652 -0
- synkit/Synthesis/RBL/overlap.py +336 -0
- synkit/Synthesis/RBL/pipeline.py +376 -0
- synkit/Synthesis/RBL/policy.py +139 -0
- synkit/Synthesis/RBL/proof.py +370 -0
- synkit/Synthesis/RBL/reaction.py +506 -0
- synkit/Synthesis/RBL/state.py +169 -0
- synkit/Synthesis/RBL/validation.py +1060 -0
- synkit/Synthesis/Reactor/__init__.py +60 -0
- synkit/Synthesis/Reactor/core/__init__.py +1 -0
- synkit/Synthesis/Reactor/core/engine.py +967 -0
- synkit/Synthesis/Reactor/core/product.py +621 -0
- synkit/Synthesis/Reactor/core/rewrite.py +561 -0
- synkit/Synthesis/Reactor/core/strategy.py +44 -0
- synkit/Synthesis/Reactor/matching/__init__.py +1 -0
- synkit/Synthesis/Reactor/matching/mixin.py +920 -0
- synkit/Synthesis/Reactor/matching/policy.py +345 -0
- synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
- synkit/Synthesis/Reactor/output/__init__.py +1 -0
- synkit/Synthesis/Reactor/output/deduplication.py +703 -0
- synkit/Synthesis/Reactor/output/policy.py +16 -0
- synkit/Synthesis/Reactor/output/serialization.py +485 -0
- synkit/Synthesis/Reactor/output/structural.py +893 -0
- synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
- synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
- synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
- synkit/Synthesis/Reactor/variants/__init__.py +1 -0
- synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
- synkit/Synthesis/Reactor/variants/partial.py +84 -0
- synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
- synkit/Synthesis/Reactor/workflow/batch.py +550 -0
- synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
- synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
- synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
- synkit/Synthesis/__init__.py +0 -0
- synkit/Synthesis/reactor_utils.py +316 -0
- synkit/Utils/__init__.py +0 -0
- synkit/Utils/utils.py +172 -0
- synkit/Vis/__init__.py +91 -0
- synkit/Vis/crn/__init__.py +40 -0
- synkit/Vis/epd/__init__.py +20 -0
- synkit/Vis/epd/arrows.py +425 -0
- synkit/Vis/epd/chem.py +197 -0
- synkit/Vis/epd/constants.py +83 -0
- synkit/Vis/epd/layout.py +283 -0
- synkit/Vis/epd/mapping.py +51 -0
- synkit/Vis/epd/models.py +136 -0
- synkit/Vis/epd/render.py +543 -0
- synkit/Vis/epd/utils.py +108 -0
- synkit/Vis/epd/visualizer.py +811 -0
- synkit/Vis/graph_visualizer.py +375 -0
- synkit/Vis/its/__init__.py +19 -0
- synkit/Vis/its/drawer.py +615 -0
- synkit/Vis/its_drawer.py +35 -0
- synkit/Vis/molecule/__init__.py +31 -0
- synkit/Vis/molecule/drawer.py +563 -0
- synkit/Vis/molecule/reaction.py +285 -0
- synkit/Vis/molecule_drawer.py +33 -0
- synkit/Vis/mtg/__init__.py +17 -0
- synkit/Vis/mtg/drawer.py +769 -0
- synkit/Vis/mtg_drawer.py +34 -0
- synkit/Vis/pdf_writer.py +146 -0
- synkit/Vis/reaction/__init__.py +19 -0
- synkit/Vis/reaction/rule.py +141 -0
- synkit/Vis/reaction/rxn.py +532 -0
- synkit/Vis/reaction_drawer.py +41 -0
- synkit/Vis/space/__init__.py +17 -0
- synkit/Vis/space/chemical.py +80 -0
- synkit/Vis/space/embedding.py +87 -0
- synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
- synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
- synkit/Vis/vis_synedu/rxn_vis.py +377 -0
- synkit/Vis/vis_synedu/vis.py +501 -0
- synkit/Vis/visual_drawer.py +215 -0
- synkit/Vis/visual_model.py +520 -0
- synkit/__init__.py +3 -0
- synkit/_native.py +91 -0
- synkit/examples.py +50 -0
- synkit/version.py +23 -0
- synkit-1.6.5.dist-info/METADATA +156 -0
- synkit-1.6.5.dist-info/RECORD +636 -0
- synkit-1.6.5.dist-info/WHEEL +4 -0
- synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
"""Prepare exact palettes once; construct, canonically label and dedup ITS in C++."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ctypes as ct
|
|
6
|
+
import json
|
|
7
|
+
import math
|
|
8
|
+
import time
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from functools import lru_cache
|
|
11
|
+
from numbers import Integral, Real
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
from synkit.Graph.Canon.exact import _encode_color
|
|
17
|
+
|
|
18
|
+
from ..exact.native.canonical import PackedCanonicalKey
|
|
19
|
+
from ...reporting.spectrum import _typed
|
|
20
|
+
|
|
21
|
+
_INT = ct.POINTER(ct.c_int32)
|
|
22
|
+
_LONG = ct.POINTER(ct.c_int64)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _Problem(ct.Structure):
|
|
26
|
+
_fields_ = [
|
|
27
|
+
("n", ct.c_int32),
|
|
28
|
+
("node_pair_colors", _INT),
|
|
29
|
+
("edges_r", _INT),
|
|
30
|
+
("edges_p", _INT),
|
|
31
|
+
("edge_states_r", ct.c_int32),
|
|
32
|
+
("edge_states_p", ct.c_int32),
|
|
33
|
+
("edge_pair_colors", _INT),
|
|
34
|
+
("palette_size", ct.c_int32),
|
|
35
|
+
("palette_json", ct.POINTER(ct.c_char_p)),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _Statistics(ct.Structure):
|
|
40
|
+
_fields_ = [
|
|
41
|
+
("candidates", ct.c_int64),
|
|
42
|
+
("classes", ct.c_int64),
|
|
43
|
+
("canonical_nodes", ct.c_int64),
|
|
44
|
+
("complete", ct.c_int32),
|
|
45
|
+
("reason", ct.c_int32),
|
|
46
|
+
("elapsed_seconds", ct.c_double),
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_CALLBACK = ct.CFUNCTYPE(
|
|
51
|
+
ct.c_int,
|
|
52
|
+
_INT,
|
|
53
|
+
ct.c_int64,
|
|
54
|
+
ct.c_int64,
|
|
55
|
+
ct.POINTER(ct.c_ubyte),
|
|
56
|
+
ct.c_int64,
|
|
57
|
+
ct.c_char_p,
|
|
58
|
+
ct.c_void_p,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@lru_cache(maxsize=8)
|
|
63
|
+
def _load(path):
|
|
64
|
+
library = ct.CDLL(str(Path(path).resolve()))
|
|
65
|
+
if library.synkit_mapper_classification_abi() != 1:
|
|
66
|
+
raise RuntimeError("Unsupported native classification ABI")
|
|
67
|
+
if hasattr(library, "synkit_mapper_classification_max_vertices"):
|
|
68
|
+
library.synkit_mapper_classification_max_vertices.argtypes = []
|
|
69
|
+
library.synkit_mapper_classification_max_vertices.restype = ct.c_int
|
|
70
|
+
library.synkit_mapper_classification_error.restype = ct.c_char_p
|
|
71
|
+
library.synkit_mapper_classify_batch.argtypes = [
|
|
72
|
+
ct.POINTER(_Problem),
|
|
73
|
+
ct.c_int64,
|
|
74
|
+
_INT,
|
|
75
|
+
_LONG,
|
|
76
|
+
ct.c_double,
|
|
77
|
+
ct.c_int64,
|
|
78
|
+
ct.c_int64,
|
|
79
|
+
_CALLBACK,
|
|
80
|
+
ct.c_void_p,
|
|
81
|
+
ct.POINTER(_Statistics),
|
|
82
|
+
]
|
|
83
|
+
library.synkit_mapper_classify_batch.restype = ct.c_int
|
|
84
|
+
library.synkit_mapper_classify_batch_with_cancel.argtypes = [
|
|
85
|
+
ct.POINTER(_Problem),
|
|
86
|
+
ct.c_int64,
|
|
87
|
+
_INT,
|
|
88
|
+
_LONG,
|
|
89
|
+
ct.c_double,
|
|
90
|
+
ct.c_int64,
|
|
91
|
+
ct.c_int64,
|
|
92
|
+
ct.c_void_p,
|
|
93
|
+
_CALLBACK,
|
|
94
|
+
ct.c_void_p,
|
|
95
|
+
ct.POINTER(_Statistics),
|
|
96
|
+
]
|
|
97
|
+
library.synkit_mapper_classify_batch_with_cancel.restype = ct.c_int
|
|
98
|
+
if hasattr(library, "synkit_mapper_classify_batch_updates_with_cancel"):
|
|
99
|
+
function = library.synkit_mapper_classify_batch_updates_with_cancel
|
|
100
|
+
function.argtypes = library.synkit_mapper_classify_batch_with_cancel.argtypes
|
|
101
|
+
function.restype = ct.c_int
|
|
102
|
+
if hasattr(library, "synkit_mapper_classify_batch_ex"):
|
|
103
|
+
function = library.synkit_mapper_classify_batch_ex
|
|
104
|
+
function.argtypes = [
|
|
105
|
+
*library.synkit_mapper_classify_batch_with_cancel.argtypes,
|
|
106
|
+
ct.c_int32,
|
|
107
|
+
ct.c_int32,
|
|
108
|
+
]
|
|
109
|
+
function.restype = ct.c_int
|
|
110
|
+
return library
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True)
|
|
114
|
+
class NativeITSClass:
|
|
115
|
+
representative: tuple[int, ...]
|
|
116
|
+
cost2: int
|
|
117
|
+
observed_mapping_count: int
|
|
118
|
+
key: PackedCanonicalKey
|
|
119
|
+
identifier: str
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True)
|
|
123
|
+
class NativeClassificationResult:
|
|
124
|
+
classes: tuple[NativeITSClass, ...]
|
|
125
|
+
candidates: int
|
|
126
|
+
complete: bool
|
|
127
|
+
reason: str | None
|
|
128
|
+
canonical_nodes: int
|
|
129
|
+
elapsed_seconds: float
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _records_callback(n, classes, errors, class_callback, *, upserts=False):
|
|
133
|
+
positions = {}
|
|
134
|
+
|
|
135
|
+
@_CALLBACK
|
|
136
|
+
def receive(mapping, cost2, observed, packed, size, identifier, _):
|
|
137
|
+
try:
|
|
138
|
+
name = identifier.decode("ascii")
|
|
139
|
+
key = PackedCanonicalKey(ct.string_at(packed, size), identifier=name)
|
|
140
|
+
record = NativeITSClass(
|
|
141
|
+
tuple(mapping[i] for i in range(n)), cost2, observed, key, name
|
|
142
|
+
)
|
|
143
|
+
if upserts and key.parts in positions:
|
|
144
|
+
index = positions[key.parts]
|
|
145
|
+
old = classes[index]
|
|
146
|
+
if (
|
|
147
|
+
old.representative != record.representative
|
|
148
|
+
or old.cost2 != record.cost2
|
|
149
|
+
or old.identifier != record.identifier
|
|
150
|
+
or record.observed_mapping_count < old.observed_mapping_count
|
|
151
|
+
):
|
|
152
|
+
raise RuntimeError("Invalid cumulative native class update")
|
|
153
|
+
classes[index] = record
|
|
154
|
+
return 0
|
|
155
|
+
positions[key.parts] = len(classes)
|
|
156
|
+
classes.append(record)
|
|
157
|
+
return (
|
|
158
|
+
int(bool(class_callback(record))) if class_callback is not None else 0
|
|
159
|
+
)
|
|
160
|
+
except BaseException as error: # noqa: BLE001 - C callback boundary.
|
|
161
|
+
errors.append(error)
|
|
162
|
+
return 1
|
|
163
|
+
|
|
164
|
+
return receive
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _classification_result(classes, statistics, seconds):
|
|
168
|
+
return NativeClassificationResult(
|
|
169
|
+
tuple(classes),
|
|
170
|
+
statistics.candidates,
|
|
171
|
+
bool(statistics.complete),
|
|
172
|
+
{
|
|
173
|
+
0: None,
|
|
174
|
+
1: "time_limit",
|
|
175
|
+
2: "canonical_node_limit",
|
|
176
|
+
3: "class_limit",
|
|
177
|
+
4: "callback_stop",
|
|
178
|
+
5: "cancelled",
|
|
179
|
+
}[statistics.reason],
|
|
180
|
+
statistics.canonical_nodes,
|
|
181
|
+
seconds,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _cap(value, name):
|
|
186
|
+
if value is None:
|
|
187
|
+
return -1
|
|
188
|
+
if (
|
|
189
|
+
isinstance(value, bool)
|
|
190
|
+
or not isinstance(value, Integral)
|
|
191
|
+
or not 0 < value < 2**63
|
|
192
|
+
):
|
|
193
|
+
raise ValueError(f"{name} must be positive int64 or None")
|
|
194
|
+
return int(value)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class NativeITSBatchClassifier:
|
|
198
|
+
"""Exact attributed ITS classes with the existing SKC1 and class-ID contracts.
|
|
199
|
+
|
|
200
|
+
``properties`` preserves its insertion order and pairs endpoint atom arrays.
|
|
201
|
+
``edge_properties`` pairs dense endpoint attribute matrices. For E/Z, use
|
|
202
|
+
``{"stereo": (reactant_stereo, product_stereo)}``; colors then exactly match
|
|
203
|
+
reaction_search's ``(weight_r, weight_p, stereo_r, stereo_p)``. Elements
|
|
204
|
+
include isotope/type information under the caller's established convention.
|
|
205
|
+
The C++ loop performs all per-candidate construction, exact search, hashing
|
|
206
|
+
and deduplication. Python receives one callback per distinct complete key.
|
|
207
|
+
Counts refer to supplied mappings, never inferred labeled multiplicities.
|
|
208
|
+
Palette preparation memoizes repeated exact typed states within this
|
|
209
|
+
constructor call; tokens, ordering and native certificate bytes are unchanged.
|
|
210
|
+
Inputs above 256 vertices require the library's explicit capacity accessor;
|
|
211
|
+
this implementation supports at most 512 vertices.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
# Keep ABI validation, palettes and their ctypes buffer lifetimes together.
|
|
215
|
+
def __init__( # noqa: C901
|
|
216
|
+
self,
|
|
217
|
+
reactant,
|
|
218
|
+
product,
|
|
219
|
+
elements,
|
|
220
|
+
properties,
|
|
221
|
+
*,
|
|
222
|
+
library_path,
|
|
223
|
+
edge_properties=None,
|
|
224
|
+
identifier_mode="legacy",
|
|
225
|
+
):
|
|
226
|
+
preparation_started = time.perf_counter()
|
|
227
|
+
if identifier_mode not in {"legacy", "packed"}:
|
|
228
|
+
raise ValueError("identifier_mode must be 'legacy' or 'packed'")
|
|
229
|
+
self.identifier_mode = identifier_mode
|
|
230
|
+
a, b = np.asarray(reactant), np.asarray(product)
|
|
231
|
+
self.n = n = len(elements)
|
|
232
|
+
if not 0 <= n <= 512 or a.shape != (n, n) or b.shape != (n, n):
|
|
233
|
+
raise ValueError(
|
|
234
|
+
"Native ITS requires square endpoints with 0..512 vertices"
|
|
235
|
+
)
|
|
236
|
+
# Old libraries retain their qualified 256-vertex limit. Only large
|
|
237
|
+
# inputs load early; the established <=256 preparation order is intact.
|
|
238
|
+
library = None
|
|
239
|
+
if identifier_mode == "packed":
|
|
240
|
+
library = _load(str(Path(library_path).resolve()))
|
|
241
|
+
if not all(
|
|
242
|
+
hasattr(library, name)
|
|
243
|
+
for name in (
|
|
244
|
+
"synkit_mapper_classify_batch_ex",
|
|
245
|
+
"synkit_mapper_solve_classified_ex",
|
|
246
|
+
)
|
|
247
|
+
):
|
|
248
|
+
raise RuntimeError("Native library does not support packed identifiers")
|
|
249
|
+
if n > 256:
|
|
250
|
+
library = _load(str(Path(library_path).resolve()))
|
|
251
|
+
capacity = min(
|
|
252
|
+
512,
|
|
253
|
+
library.synkit_mapper_classification_max_vertices()
|
|
254
|
+
if hasattr(library, "synkit_mapper_classification_max_vertices")
|
|
255
|
+
else 256,
|
|
256
|
+
)
|
|
257
|
+
if n > capacity:
|
|
258
|
+
raise ValueError(
|
|
259
|
+
f"Native ITS library supports at most {capacity} vertices"
|
|
260
|
+
)
|
|
261
|
+
for matrix in (a, b):
|
|
262
|
+
if (
|
|
263
|
+
not np.isfinite(matrix).all()
|
|
264
|
+
or np.any(matrix < 0)
|
|
265
|
+
or not np.array_equal(matrix, matrix.T)
|
|
266
|
+
or np.any(np.diag(matrix))
|
|
267
|
+
):
|
|
268
|
+
raise ValueError(
|
|
269
|
+
"ITS endpoints must be finite nonnegative symmetric and loop-free"
|
|
270
|
+
)
|
|
271
|
+
for name, sides in properties.items():
|
|
272
|
+
if len(sides) != 2 or any(len(side) != n for side in sides):
|
|
273
|
+
raise ValueError(f"Invalid atom property {name}")
|
|
274
|
+
edge_properties = edge_properties or {}
|
|
275
|
+
for name, sides in edge_properties.items():
|
|
276
|
+
if len(sides) != 2 or any(np.shape(side) != (n, n) for side in sides):
|
|
277
|
+
raise ValueError(f"Invalid edge property {name}")
|
|
278
|
+
if any(
|
|
279
|
+
any(side[i][j] != side[j][i] for i in range(n) for j in range(n))
|
|
280
|
+
for side in sides
|
|
281
|
+
):
|
|
282
|
+
raise ValueError(f"Asymmetric edge property {name}")
|
|
283
|
+
# Chemistry repeats a small number of exact atom states across n*n
|
|
284
|
+
# possible pairs. _typed preserves the established literal-type contract.
|
|
285
|
+
left_states = [
|
|
286
|
+
(
|
|
287
|
+
_typed(elements[i]),
|
|
288
|
+
tuple(_typed(sides[0][i]) for sides in properties.values()),
|
|
289
|
+
)
|
|
290
|
+
for i in range(n)
|
|
291
|
+
]
|
|
292
|
+
right_states = [
|
|
293
|
+
tuple(_typed(sides[1][j]) for sides in properties.values())
|
|
294
|
+
for j in range(n)
|
|
295
|
+
]
|
|
296
|
+
node_cache = {
|
|
297
|
+
(left, right): _encode_color(
|
|
298
|
+
(
|
|
299
|
+
left[0],
|
|
300
|
+
tuple(
|
|
301
|
+
(name, x, y) for name, x, y in zip(properties, left[1], right)
|
|
302
|
+
),
|
|
303
|
+
(),
|
|
304
|
+
)
|
|
305
|
+
)
|
|
306
|
+
for left in dict.fromkeys(left_states)
|
|
307
|
+
for right in dict.fromkeys(right_states)
|
|
308
|
+
}
|
|
309
|
+
node_tokens = [
|
|
310
|
+
[node_cache[left, right] for right in right_states] for left in left_states
|
|
311
|
+
]
|
|
312
|
+
states, matrices = [], []
|
|
313
|
+
for side, matrix in enumerate((a, b)):
|
|
314
|
+
# Intern exact tokens rather than Python equality: bool/int and
|
|
315
|
+
# signed floating zero may differ in the certificate contract.
|
|
316
|
+
# Edge attributes use their exact encoder, not repr as a cache key:
|
|
317
|
+
# distinct supported mappings/containers may have equal reprs.
|
|
318
|
+
cache, encoded_states, encoded_rows = {}, {}, []
|
|
319
|
+
for i in range(n):
|
|
320
|
+
row = []
|
|
321
|
+
for j in range(n):
|
|
322
|
+
weight = float(matrix[i, j])
|
|
323
|
+
attrs = tuple(
|
|
324
|
+
values[side][i][j] for values in edge_properties.values()
|
|
325
|
+
)
|
|
326
|
+
key = (weight.hex(), tuple(_encode_color(v) for v in attrs))
|
|
327
|
+
if key not in cache:
|
|
328
|
+
raw = (weight, *attrs)
|
|
329
|
+
token = _encode_color(raw)
|
|
330
|
+
cache[key] = token
|
|
331
|
+
encoded_states[token] = raw
|
|
332
|
+
row.append(cache[key])
|
|
333
|
+
encoded_rows.append(row)
|
|
334
|
+
palette = [encoded_states[token] for token in sorted(encoded_states)]
|
|
335
|
+
if not palette:
|
|
336
|
+
palette = [(0.0,)]
|
|
337
|
+
ids = {_encode_color(value): index for index, value in enumerate(palette)}
|
|
338
|
+
states.append(palette)
|
|
339
|
+
matrices.append(
|
|
340
|
+
np.ascontiguousarray(
|
|
341
|
+
[[ids[v] for v in row] for row in encoded_rows],
|
|
342
|
+
dtype=np.int32,
|
|
343
|
+
).reshape(n, n)
|
|
344
|
+
)
|
|
345
|
+
edge_tokens = []
|
|
346
|
+
for left in states[0]:
|
|
347
|
+
row = []
|
|
348
|
+
for right in states[1]:
|
|
349
|
+
raw = (
|
|
350
|
+
left[0],
|
|
351
|
+
right[0],
|
|
352
|
+
*(v for pair in zip(left[1:], right[1:]) for v in pair),
|
|
353
|
+
)
|
|
354
|
+
row.append(_encode_color(raw) if left[0] or right[0] else None)
|
|
355
|
+
edge_tokens.append(row)
|
|
356
|
+
tokens = sorted(
|
|
357
|
+
{v for row in node_tokens for v in row}
|
|
358
|
+
| {v for row in edge_tokens for v in row if v is not None}
|
|
359
|
+
)
|
|
360
|
+
if len(tokens) >= 65536:
|
|
361
|
+
raise ValueError("Native ITS exact palette exceeds uint16")
|
|
362
|
+
ids = {token: index for index, token in enumerate(tokens)}
|
|
363
|
+
self.node_colors = np.ascontiguousarray(
|
|
364
|
+
[[ids[v] for v in row] for row in node_tokens], dtype=np.int32
|
|
365
|
+
).reshape(n, n)
|
|
366
|
+
self.edge_colors = np.ascontiguousarray(
|
|
367
|
+
[[ids[v] + 1 if v is not None else 0 for v in row] for row in edge_tokens],
|
|
368
|
+
dtype=np.int32,
|
|
369
|
+
)
|
|
370
|
+
self.edge_matrices = matrices
|
|
371
|
+
self.palette = (ct.c_char_p * len(tokens))(
|
|
372
|
+
*(
|
|
373
|
+
json.dumps(token, separators=(",", ":")).encode("ascii")
|
|
374
|
+
for token in tokens
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
self.problem = _Problem(
|
|
378
|
+
n,
|
|
379
|
+
self.node_colors.ctypes.data_as(_INT),
|
|
380
|
+
matrices[0].ctypes.data_as(_INT),
|
|
381
|
+
matrices[1].ctypes.data_as(_INT),
|
|
382
|
+
len(states[0]),
|
|
383
|
+
len(states[1]),
|
|
384
|
+
self.edge_colors.ctypes.data_as(_INT),
|
|
385
|
+
len(tokens),
|
|
386
|
+
self.palette,
|
|
387
|
+
)
|
|
388
|
+
self.library = (
|
|
389
|
+
library if library is not None else _load(str(Path(library_path).resolve()))
|
|
390
|
+
)
|
|
391
|
+
self.preparation_seconds = time.perf_counter() - preparation_started
|
|
392
|
+
|
|
393
|
+
@classmethod
|
|
394
|
+
def from_endpoint_graphs(
|
|
395
|
+
cls,
|
|
396
|
+
endpoint_mols,
|
|
397
|
+
endpoint_graphs,
|
|
398
|
+
*,
|
|
399
|
+
library_path,
|
|
400
|
+
binary=False,
|
|
401
|
+
identifier_mode="legacy",
|
|
402
|
+
):
|
|
403
|
+
"""Prepare the exact existing reaction_search class contract, including E/Z.
|
|
404
|
+
|
|
405
|
+
Preparation still uses RDKit Python, as does the shared chemistry
|
|
406
|
+
frontend. Canonical classification of every subsequent candidate is
|
|
407
|
+
native. Objective anchors/dummies outside a molecule have empty bond
|
|
408
|
+
stereo, matching the historical frontend exactly.
|
|
409
|
+
"""
|
|
410
|
+
from ..slap.lap import _adjacency_and_elements
|
|
411
|
+
|
|
412
|
+
a, elements = _adjacency_and_elements(endpoint_graphs[0], binary)
|
|
413
|
+
b, _ = _adjacency_and_elements(endpoint_graphs[1], binary)
|
|
414
|
+
properties = {
|
|
415
|
+
name: (endpoint_graphs[0].props[name], endpoint_graphs[1].props[name])
|
|
416
|
+
for name in ("charge", "radical", "hcount", "stereo", "dummy")
|
|
417
|
+
}
|
|
418
|
+
stereo = []
|
|
419
|
+
for mol in endpoint_mols:
|
|
420
|
+
matrix = np.full((len(elements), len(elements)), "", dtype=object)
|
|
421
|
+
for bond in mol.GetBonds():
|
|
422
|
+
i, j = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()
|
|
423
|
+
matrix[i, j] = matrix[j, i] = str(bond.GetStereo())
|
|
424
|
+
stereo.append(matrix)
|
|
425
|
+
return cls(
|
|
426
|
+
a,
|
|
427
|
+
b,
|
|
428
|
+
elements,
|
|
429
|
+
properties,
|
|
430
|
+
library_path=library_path,
|
|
431
|
+
edge_properties={"stereo": stereo},
|
|
432
|
+
identifier_mode=identifier_mode,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
def classify(
|
|
436
|
+
self,
|
|
437
|
+
mappings,
|
|
438
|
+
costs2=None,
|
|
439
|
+
*,
|
|
440
|
+
time_limit_seconds=None,
|
|
441
|
+
max_canonical_nodes=None,
|
|
442
|
+
max_classes=None,
|
|
443
|
+
class_callback=None,
|
|
444
|
+
cancel_token=None,
|
|
445
|
+
stream=False,
|
|
446
|
+
):
|
|
447
|
+
"""Classify mappings, optionally delivering each key on discovery.
|
|
448
|
+
|
|
449
|
+
``stream=True`` uses the additive cumulative-count interface when
|
|
450
|
+
available, otherwise the legacy batch API. User callbacks run once
|
|
451
|
+
per new key; final result records merge subsequent count updates.
|
|
452
|
+
Counts in interrupted streaming output are observed lower bounds.
|
|
453
|
+
Legacy default callbacks retain their final batch-count semantics.
|
|
454
|
+
"""
|
|
455
|
+
started = time.perf_counter()
|
|
456
|
+
values = list(mappings)
|
|
457
|
+
if any(len(mapping) != self.n for mapping in values):
|
|
458
|
+
raise ValueError("Mapping width differs from ITS size")
|
|
459
|
+
if any(
|
|
460
|
+
isinstance(v, bool) or not isinstance(v, Integral) or not 0 <= v < self.n
|
|
461
|
+
for mapping in values
|
|
462
|
+
for v in mapping
|
|
463
|
+
):
|
|
464
|
+
raise ValueError("Mappings require valid integer vertex IDs")
|
|
465
|
+
permutations = np.ascontiguousarray(values, dtype=np.int32).reshape(
|
|
466
|
+
len(values), self.n
|
|
467
|
+
)
|
|
468
|
+
costs2 = [0] * len(values) if costs2 is None else list(costs2)
|
|
469
|
+
if len(costs2) != len(values) or any(
|
|
470
|
+
isinstance(v, bool) or not isinstance(v, Integral) or not 0 <= v < 2**63
|
|
471
|
+
for v in costs2
|
|
472
|
+
):
|
|
473
|
+
raise ValueError("costs2 must contain one nonnegative int64 per mapping")
|
|
474
|
+
costs = np.ascontiguousarray(costs2, dtype=np.int64)
|
|
475
|
+
if time_limit_seconds is not None and (
|
|
476
|
+
isinstance(time_limit_seconds, bool)
|
|
477
|
+
or not isinstance(time_limit_seconds, Real)
|
|
478
|
+
or not math.isfinite(time_limit_seconds)
|
|
479
|
+
or time_limit_seconds < 0
|
|
480
|
+
):
|
|
481
|
+
raise ValueError("time_limit_seconds must be finite and nonnegative")
|
|
482
|
+
classes, errors = [], []
|
|
483
|
+
|
|
484
|
+
packed_identifier = self.identifier_mode == "packed"
|
|
485
|
+
updates = stream and (
|
|
486
|
+
packed_identifier
|
|
487
|
+
or hasattr(self.library, "synkit_mapper_classify_batch_updates_with_cancel")
|
|
488
|
+
)
|
|
489
|
+
receive = _records_callback(
|
|
490
|
+
self.n, classes, errors, class_callback, upserts=updates
|
|
491
|
+
)
|
|
492
|
+
function = (
|
|
493
|
+
self.library.synkit_mapper_classify_batch_ex
|
|
494
|
+
if packed_identifier
|
|
495
|
+
else (
|
|
496
|
+
self.library.synkit_mapper_classify_batch_updates_with_cancel
|
|
497
|
+
if updates
|
|
498
|
+
else self.library.synkit_mapper_classify_batch_with_cancel
|
|
499
|
+
)
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
statistics = _Statistics()
|
|
503
|
+
status = function(
|
|
504
|
+
ct.byref(self.problem),
|
|
505
|
+
len(values),
|
|
506
|
+
permutations.ctypes.data_as(_INT),
|
|
507
|
+
costs.ctypes.data_as(_LONG),
|
|
508
|
+
(
|
|
509
|
+
-1
|
|
510
|
+
if time_limit_seconds is None
|
|
511
|
+
else max(0, time_limit_seconds - (time.perf_counter() - started))
|
|
512
|
+
),
|
|
513
|
+
_cap(max_canonical_nodes, "max_canonical_nodes"),
|
|
514
|
+
_cap(max_classes, "max_classes"),
|
|
515
|
+
None if cancel_token is None else cancel_token.pointer,
|
|
516
|
+
receive,
|
|
517
|
+
None,
|
|
518
|
+
ct.byref(statistics),
|
|
519
|
+
*((int(updates), 1) if packed_identifier else ()),
|
|
520
|
+
)
|
|
521
|
+
if errors:
|
|
522
|
+
raise errors[0]
|
|
523
|
+
if status:
|
|
524
|
+
raise RuntimeError(
|
|
525
|
+
self.library.synkit_mapper_classification_error().decode()
|
|
526
|
+
)
|
|
527
|
+
return _classification_result(
|
|
528
|
+
classes, statistics, time.perf_counter() - started
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
def solve_prepared(
|
|
532
|
+
self,
|
|
533
|
+
problem,
|
|
534
|
+
request,
|
|
535
|
+
*,
|
|
536
|
+
max_canonical_nodes=None,
|
|
537
|
+
class_callback=None,
|
|
538
|
+
allowed_domains=None,
|
|
539
|
+
stream=False,
|
|
540
|
+
):
|
|
541
|
+
"""Native search and classification using the shared prepared C structs.
|
|
542
|
+
|
|
543
|
+
``problem`` and ``request`` are ``_native.runtime.Problem/Request``.
|
|
544
|
+
Their input buffers must stay alive for this synchronous call. This
|
|
545
|
+
method copies the request and sets classify=1. The endpoint palette
|
|
546
|
+
preparation is reusable and is reported separately by preparation_seconds.
|
|
547
|
+
No intermediate mapping calls Python. Unsupported resource/backend
|
|
548
|
+
settings are returned explicitly in the returned common Statistics.
|
|
549
|
+
Return ``(NativeClassificationResult, runtime.Statistics)``.
|
|
550
|
+
Optional ``allowed_domains`` is a dense n*n zero/one mask passed intact
|
|
551
|
+
through the restricted native dispatcher. Its proof/completeness scope
|
|
552
|
+
remains the supplied domains; class batching does not relax them.
|
|
553
|
+
``stream=True`` publishes new keys immediately and merges cumulative
|
|
554
|
+
count updates; user callbacks run only on first discovery. Older
|
|
555
|
+
libraries retain batch delivery. The default keeps legacy callbacks.
|
|
556
|
+
"""
|
|
557
|
+
from .runtime import Problem, Request, Statistics
|
|
558
|
+
|
|
559
|
+
started = time.perf_counter()
|
|
560
|
+
if not isinstance(problem, Problem) or not isinstance(request, Request):
|
|
561
|
+
raise TypeError("Expected shared native Problem and Request structs")
|
|
562
|
+
prepared = Request.from_buffer_copy(request)
|
|
563
|
+
prepared.classify = 1
|
|
564
|
+
mask = None
|
|
565
|
+
prefix = [ct.byref(problem), ct.byref(prepared)]
|
|
566
|
+
prefix_types = [ct.POINTER(Problem), ct.POINTER(Request)]
|
|
567
|
+
if allowed_domains is not None:
|
|
568
|
+
values = np.asarray(allowed_domains)
|
|
569
|
+
if (
|
|
570
|
+
values.shape != (problem.n, problem.n)
|
|
571
|
+
or not np.isin(values, [0, 1]).all()
|
|
572
|
+
):
|
|
573
|
+
raise ValueError("allowed_domains must be an n-by-n zero/one mask")
|
|
574
|
+
mask = np.ascontiguousarray(values, dtype=np.uint8)
|
|
575
|
+
mask_pointer = ct.POINTER(ct.c_uint8)
|
|
576
|
+
prefix.append(mask.ctypes.data_as(mask_pointer))
|
|
577
|
+
prefix_types.append(mask_pointer)
|
|
578
|
+
name = (
|
|
579
|
+
"synkit_mapper_solve_classified"
|
|
580
|
+
if mask is None
|
|
581
|
+
else "synkit_mapper_solve_domains_classified"
|
|
582
|
+
)
|
|
583
|
+
packed_identifier = self.identifier_mode == "packed"
|
|
584
|
+
updates = stream and (
|
|
585
|
+
packed_identifier or hasattr(self.library, name + "_updates")
|
|
586
|
+
)
|
|
587
|
+
if packed_identifier:
|
|
588
|
+
# The explicit interface always has a nullable mask argument.
|
|
589
|
+
if mask is None:
|
|
590
|
+
prefix.append(None)
|
|
591
|
+
prefix_types.append(ct.POINTER(ct.c_uint8))
|
|
592
|
+
function = self.library.synkit_mapper_solve_classified_ex
|
|
593
|
+
else:
|
|
594
|
+
function = getattr(self.library, name + "_updates" if updates else name)
|
|
595
|
+
self.delivery_mode = "incremental_discovery" if updates else "legacy_batch"
|
|
596
|
+
function.argtypes = [
|
|
597
|
+
*prefix_types,
|
|
598
|
+
ct.POINTER(_Problem),
|
|
599
|
+
ct.c_int64,
|
|
600
|
+
_CALLBACK,
|
|
601
|
+
ct.c_void_p,
|
|
602
|
+
ct.POINTER(Statistics),
|
|
603
|
+
ct.POINTER(_Statistics),
|
|
604
|
+
*((ct.c_int32, ct.c_int32) if packed_identifier else ()),
|
|
605
|
+
]
|
|
606
|
+
function.restype = ct.c_int
|
|
607
|
+
classes, errors = [], []
|
|
608
|
+
receive = _records_callback(
|
|
609
|
+
self.n, classes, errors, class_callback, upserts=updates
|
|
610
|
+
)
|
|
611
|
+
search_statistics, class_statistics = Statistics(), _Statistics()
|
|
612
|
+
if prepared.seconds >= 0:
|
|
613
|
+
prepared.seconds = max(
|
|
614
|
+
0, prepared.seconds - (time.perf_counter() - started)
|
|
615
|
+
)
|
|
616
|
+
status = function(
|
|
617
|
+
*prefix,
|
|
618
|
+
ct.byref(self.problem),
|
|
619
|
+
_cap(max_canonical_nodes, "max_canonical_nodes"),
|
|
620
|
+
receive,
|
|
621
|
+
None,
|
|
622
|
+
ct.byref(search_statistics),
|
|
623
|
+
ct.byref(class_statistics),
|
|
624
|
+
*((int(updates), 1) if packed_identifier else ()),
|
|
625
|
+
)
|
|
626
|
+
if errors:
|
|
627
|
+
raise errors[0]
|
|
628
|
+
if status:
|
|
629
|
+
core_error = getattr(self.library, "synkit_mapper_core_error", None)
|
|
630
|
+
message = b""
|
|
631
|
+
if core_error is not None:
|
|
632
|
+
core_error.restype = ct.c_char_p
|
|
633
|
+
message = core_error() or b""
|
|
634
|
+
message = message or self.library.synkit_mapper_classification_error()
|
|
635
|
+
raise RuntimeError((message or b"Native classified search failed").decode())
|
|
636
|
+
return (
|
|
637
|
+
_classification_result(
|
|
638
|
+
classes, class_statistics, class_statistics.elapsed_seconds
|
|
639
|
+
),
|
|
640
|
+
search_statistics,
|
|
641
|
+
)
|