hypertopos 0.6.0__tar.gz → 0.6.2__tar.gz
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.
- {hypertopos-0.6.0 → hypertopos-0.6.2}/CHANGELOG.md +188 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/LICENSE.md +1 -1
- {hypertopos-0.6.0 → hypertopos-0.6.2}/PKG-INFO +1 -1
- {hypertopos-0.6.0 → hypertopos-0.6.2}/README.md +13 -1
- hypertopos-0.6.2/ROADMAP.md +89 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/SECURITY.md +1 -1
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/api-reference.md +7 -3
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/architecture.md +2 -2
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/concepts.md +1 -1
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/configuration.md +20 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/builder.py +5721 -5399
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/mapping.py +72 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/build.py +19 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/schema.py +55 -1
- hypertopos-0.6.2/hypertopos/engine/adjacency.py +457 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/edge_features.py +156 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/hop_predicate.py +221 -90
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/model/sphere.py +52 -6
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/navigation/navigator.py +13491 -13284
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/reader.py +15 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/writer.py +962 -965
- {hypertopos-0.6.0 → hypertopos-0.6.2}/pyproject.toml +1 -1
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_adjacency.py +4 -3
- hypertopos-0.6.2/tests/test_adjacency_vectorized.py +202 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder.py +3 -3
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_derived.py +1416 -1416
- hypertopos-0.6.2/tests/test_distinct_neighbor_count.py +191 -0
- hypertopos-0.6.2/tests/test_edge_dim_aggregations.py +173 -0
- hypertopos-0.6.2/tests/test_edge_dim_aggregations_builder.py +373 -0
- hypertopos-0.6.2/tests/test_edge_dim_aggregations_chain.py +386 -0
- hypertopos-0.6.2/tests/test_edge_dim_aggregations_engine.py +303 -0
- hypertopos-0.6.2/tests/test_edge_dim_aggregations_roundtrip.py +109 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_potential.py +1 -1
- hypertopos-0.6.2/tests/test_find_motif_by_hops.py +470 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_fts.py +5 -7
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_hop_predicate_engine.py +220 -3
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_motif.py +2 -1
- hypertopos-0.6.2/tests/test_neighbors_window.py +119 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_root_cause_trace.py +1 -1
- hypertopos-0.6.2/tests/test_schema_chain_eda_validation.py +128 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_storage.py +31 -33
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_trajectory_ann.py +4 -2
- hypertopos-0.6.0/ROADMAP.md +0 -100
- hypertopos-0.6.0/hypertopos/engine/adjacency.py +0 -119
- hypertopos-0.6.0/tests/test_find_motif_by_hops.py +0 -130
- {hypertopos-0.6.0 → hypertopos-0.6.2}/.github/workflows/publish-pypi.yml +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/.gitignore +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/README.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/LICENSE +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/README.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/README.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/SUMMARY.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r1/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r2/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r3/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r4/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r5/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/results/0.1.0/r6/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_accounts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_cpty_banks.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_districts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_loan_accounts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_operations.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_orders.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_transactions.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/prepare_tx_types.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/berka/sphere/sphere.yaml +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/README.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/_layer2_cross_eval.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/_layer3_cross_eval.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_accounts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_currencies.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_payment_formats.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/hi_small_sphere/prepare_transactions.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/hi_small_sphere/sphere.yaml +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/layer1_passive_scan.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/layer2_xgboost_sweep.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/layer3_typology_filter.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_accounts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_currencies.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_payment_formats.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/li_small_sphere/prepare_transactions.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/li_small_sphere/sphere.yaml +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/ibm-aml/passive-scan-calibration.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/README.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/SUMMARY.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-exp-c-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r1/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-exp-c-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r2/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-a-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-a-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-b-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-b-scoring.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-exp-c-report.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/results/0.1.0/r3/0.1.0-settings.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/sphere/prepare_trips.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmark/nyc-taxi/sphere/sphere.yaml +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/benchmarks.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/data-format.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/build-pipeline.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/core-objects.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/cutting-plane.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/directory-layout.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/hypertopos-overview.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/model-lifecycle.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/navigation-primitives.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/images/three-scales.svg +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/introduction.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/docs/quickstart.md +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/_bootstrap.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/_bregman.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/_scatter.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/_stats.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/_writer.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/derived.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/builder/dim_blocks.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/__main__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/info.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/main.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/cli/sources.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/aggregation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/calibration.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/chains.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/composition.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/density_gaps.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/fdr.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/forecast.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/geometry.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/graph_algorithms.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/heredity.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/invalidation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/investigation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/lance_sql_agg.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/selection.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/engine/structuring.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/model/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/model/manifest.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/model/objects.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/navigation/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/navigation/scanner.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/sphere.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/_schemas.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/cache.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/storage/calibration_history.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/utils/__init__.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/hypertopos/utils/arrow.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/.gitkeep +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/conftest.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/fixtures/generate_fixtures.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_aggregation_engine.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_arrow_utils.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_bootstrap.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_bregman.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_alias.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_chunking.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_contagion.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_edges.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_rolling_z.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_scatter.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_builder_temporal_perf.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_cache.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_calibration.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_calibration_drift.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_calibration_history.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_calibration_history_builder.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_calibration_history_reader.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_chains.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_cli.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_cli_alias.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_cli_sources.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_compaction.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_composition.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_continuous_event_dims.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_data_quality_prop.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_decompose_drift.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_density_gaps_engine.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_detection.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_dim_blocks.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_dimensions_builder.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_dimensions_yaml.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_features.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_features_reader.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_edge_table.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_engine.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_fdr.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_find_calibration_influencers.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_find_density_gaps.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_find_lead_lag.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_find_lead_lag_significance.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_forecast.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_geometric_path.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_geometry_stats.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_gradient_alignment.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_graph_algorithms.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_heredity.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_hybrid_search.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_incremental.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_invalidation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_investigation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_kind_detect.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_lance_sql_agg.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_mapping.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_model.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_mvcc_session.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_navigation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_navigator_alerts.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_navigator_fdr_select.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_observability.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_precision_stack.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_profile_motif_perf_smoke.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_reputation.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_row_id_cache.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_scanner.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_selection.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_sphere.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_sphere_overview_perf.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_stats_guard.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_streaming_reads.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_structuring_engine.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_temporal_centroids.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_witness_cohort.py +0 -0
- {hypertopos-0.6.0 → hypertopos-0.6.2}/tests/test_witness_set.py +0 -0
|
@@ -7,6 +7,194 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.2] — 2026-05-05
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Chain-anchor `edge_dim_aggregations:` regime — third `anchor_kind`
|
|
14
|
+
alongside `single` (account-style) and `pair` (k=2 composite). Chain
|
|
15
|
+
anchor patterns auto-emitted from `chain_lines:` config can declare
|
|
16
|
+
`edge_dim_aggregations: { from: <event_pid>, dims: [...] }` directly
|
|
17
|
+
in the `chain_lines.<id>:` block; the builder forwards it to the
|
|
18
|
+
auto-emitted `<id>_pattern`. Aggregation reads the source event
|
|
19
|
+
pattern's edge_features sidecar and bakes per-chain `<source_dim>_mean`
|
|
20
|
+
and `<source_dim>_max` columns into the chain anchor polygon's
|
|
21
|
+
`shape_snapshot`. New `_chain_lines: set[str]` registry on `GDSBuilder`
|
|
22
|
+
for regime detection. `aggregate_edge_dims_for_anchor` gains a
|
|
23
|
+
`chain_events: list[str] | None` keyword for the chain regime
|
|
24
|
+
(comma-joined event_keys per anchor; engine performs explosion + join
|
|
25
|
+
+ groupby). Cross-block parse-time validation enforces
|
|
26
|
+
`chain_lines.<id>.event_line == src_pat.edge_table.event_line`;
|
|
27
|
+
zero-extracted-chains with declared aggregations raise loudly at
|
|
28
|
+
build dispatch. Sphere format stays at 2.4 — `chain_events` property
|
|
29
|
+
column on the chain anchor line is the existing membership source.
|
|
30
|
+
Aggregated dims surface automatically in every existing anchor-pattern
|
|
31
|
+
primitive (`find_anomalies`, `explain_anomaly`, `find_clusters`,
|
|
32
|
+
`find_calibration_influencers`, `decompose_drift`) via
|
|
33
|
+
`dimension_kinds` source-of-truth — no new tools, no MCP API change.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- `AdjacencyIndex.neighbors_out_window` and
|
|
37
|
+
`AdjacencyIndex.neighbors_in_window` — column-selective neighbor
|
|
38
|
+
accessors. Return a per-column dict (`{col: list[Any]}`) for any subset
|
|
39
|
+
of `("to_key" / "from_key", "timestamp", "amount", "event_key")` with
|
|
40
|
+
an optional `ts_min` window predicate applied at the pyarrow C++ layer
|
|
41
|
+
before materialization. Useful for callers that need only key + timestamp
|
|
42
|
+
without paying the cost of materializing `amount` / `event_key`.
|
|
43
|
+
- `AdjacencyIndex.distinct_neighbors_out`,
|
|
44
|
+
`AdjacencyIndex.distinct_neighbors_in`, and
|
|
45
|
+
`AdjacencyIndex.max_amount_out_excl_self` — O(1) public accessors over
|
|
46
|
+
precomputed per-`from_key` aggregates (distinct-out-neighbor count,
|
|
47
|
+
distinct-in-neighbor count, max-amount-excluding-self). Self-loop
|
|
48
|
+
semantics preserved; null amounts skipped.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- Cold-call latency on motif enumeration tools (`find_high_potential_motifs`,
|
|
52
|
+
`score_motif`, `find_motif_by_hops`) reduced across `bipartite_burst`,
|
|
53
|
+
`fan_out`, `fan_in`, and `cycle_2` motif types. No public API change.
|
|
54
|
+
- `AdjacencyIndex.pair_counts()` first-call cost on hub-graph workloads
|
|
55
|
+
reduced. The aggregate is now precomputed at adjacency build time and
|
|
56
|
+
surfaced in O(1) on first call. Self-loop semantics preserved
|
|
57
|
+
(`pair_counts` includes self-pairs; distinct counts skip them).
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- `AdjacencyIndex` cold load path is faster on edge-table-backed
|
|
61
|
+
patterns; motif tools' first-call latency drops materially. No format
|
|
62
|
+
bump, no persisted artifact, no public API change — every public method
|
|
63
|
+
(`neighbors_out`, `neighbors_in`, `degree_out`, `degree_in`, `all_nodes`,
|
|
64
|
+
`all_edges`, `node_count`, `edge_count`, `pair_counts`) preserves its
|
|
65
|
+
signature and observable behavior.
|
|
66
|
+
|
|
67
|
+
## [0.6.1] — 2026-05-01
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
- `find_motif_by_hops` `score=True` now functional on event patterns. The
|
|
71
|
+
scoring branch was previously dead code (gated on
|
|
72
|
+
`pattern_type != "event"`, but the function rejects non-event patterns
|
|
73
|
+
upstream), so passing `score=True` had no observable effect since the
|
|
74
|
+
declarative motif API shipped. Scoring now resolves the event pattern's
|
|
75
|
+
anchor companion via `_resolve_anchor_pattern_for_scoring` and uses the
|
|
76
|
+
anchor pattern's per-entity geometry (entity-level deltas) rather than
|
|
77
|
+
the event pattern's per-transaction polygons. Each scored motif carries
|
|
78
|
+
a new `anchor_pattern_id` provenance field. Raises `GDSNavigationError`
|
|
79
|
+
when no anchor companion is configured for the event pattern; per-motif
|
|
80
|
+
scoring failures (endpoint missing in anchor geometry) leave the motif
|
|
81
|
+
unscored without breaking the call. Output ordering: descending on
|
|
82
|
+
score, unscored motifs at tail.
|
|
83
|
+
- Motif scoring kernel (`_score_motif_from_edges`, `_lean_score_motif`)
|
|
84
|
+
now event-aware via opt-in `event_keys` + `event_pattern_id` arguments.
|
|
85
|
+
Previously `edge_potential = delta_distance × (1/effective_pair_count)`
|
|
86
|
+
depended only on the node pair, so multiple distinct transactions
|
|
87
|
+
between the same `(from, to)` accounts produced identical motif scores
|
|
88
|
+
— turning ranked `find_motif_by_hops(score=True)` output into "5–10
|
|
89
|
+
distinct ranks with the rest as ties" whenever motifs shared a node
|
|
90
|
+
sequence. With the new arguments the kernel batch-reads the event
|
|
91
|
+
pattern's per-event polygons and multiplies each edge's potential by
|
|
92
|
+
`(1 + ||event_polygon[event_key]||)`; events sitting at the population
|
|
93
|
+
centroid (norm 0) keep the legacy score, anomalous events boost above.
|
|
94
|
+
Per-edge `score_breakdown` carries a new `event_factor` field when
|
|
95
|
+
event-aware. Backward compatible: legacy callers (`score_motif`,
|
|
96
|
+
`find_high_potential_motifs`, any external caller of
|
|
97
|
+
`_score_motif_from_edges` without event_keys) see unchanged scores.
|
|
98
|
+
`find_motif_by_hops` passes both arguments automatically and hoists
|
|
99
|
+
both anchor and event delta reads out of the per-motif loop (one
|
|
100
|
+
batched scan per pattern across the union of all motifs, vs.
|
|
101
|
+
per-motif reads pre-hoist) so the per-call I/O cost stays O(1) in
|
|
102
|
+
motif count.
|
|
103
|
+
- `Pattern.dim_labels` and `Pattern.delta_dim()` now include aggregated
|
|
104
|
+
edge-dim names from `edge_dim_aggregations` so callers don't see a
|
|
105
|
+
stale 33-element view of a 37-element delta. Previously the property
|
|
106
|
+
returned only `relations + event_dimensions + prop_columns` — but the
|
|
107
|
+
builder appends `(source_dim)_mean` and `(source_dim)_max` columns to
|
|
108
|
+
the polygon delta when an anchor pattern declares
|
|
109
|
+
`edge_dim_aggregations: { from: <event>, dims: [...] }`. The mismatch
|
|
110
|
+
produced two visible failure classes on patterns with aggregations
|
|
111
|
+
declared:
|
|
112
|
+
- `anomaly_summary` raised `operands could not be broadcast together
|
|
113
|
+
with shapes (33,) (37,) (33,)` because `dim_sq_totals` was sized
|
|
114
|
+
from `len(pattern.dim_labels)` (33) but cluster delta vectors had
|
|
115
|
+
length 37 (33 base + 4 aggregated).
|
|
116
|
+
- `find_clusters.dim_profile`, `find_anomalies.anomaly_dimensions`,
|
|
117
|
+
`explain_anomaly` top-dim labels, `contrast_populations`
|
|
118
|
+
effect-size labels and other label-resolving paths returned
|
|
119
|
+
`dim_35` / `dim_36` placeholders for the aggregated dims instead
|
|
120
|
+
of the build-time names (`find_motif_structuring_mean`,
|
|
121
|
+
`pair_edge_count_max`, etc.).
|
|
122
|
+
Both classes are resolved by the model property fix; the aggregated
|
|
123
|
+
name convention follows `f"{source_dim}_{agg}"` for each
|
|
124
|
+
`agg ∈ AGGREGATE_NAMES = ("mean", "max")` in
|
|
125
|
+
`engine/edge_features.py`. `parse_edge_dim_aggregations` now requires
|
|
126
|
+
`dims` to be a non-empty list — the previous `dims=None` shorthand
|
|
127
|
+
("aggregate every applicable dim") was a latent build-vs-runtime
|
|
128
|
+
inconsistency: builder appended columns from the source event
|
|
129
|
+
pattern, but the runtime model had no record of which columns. Users
|
|
130
|
+
must now declare dims explicitly. Backward compatible for spheres
|
|
131
|
+
with explicit `dims:` on disk (AML HI-small etc.); spheres that
|
|
132
|
+
somehow built with `dims=None` fail loudly at re-load and need a
|
|
133
|
+
rebuild with explicit declaration. Closes the F1.d follow-up
|
|
134
|
+
(human-readable aggregated-dim labels) and the F6 stress-test
|
|
135
|
+
wildcard for the broadcast regression.
|
|
136
|
+
|
|
137
|
+
### Changed
|
|
138
|
+
- `find_motif_by_hops` engine: replaced the recursive DFS walk with an
|
|
139
|
+
iterative BFS-by-level enumerator. Lifts the per-call hop count cap
|
|
140
|
+
from 6 to 8 (matches the `chain_k` motif vocabulary). Adds an optional
|
|
141
|
+
`time_window_hours: float | None` top-level parameter for total-
|
|
142
|
+
chain-span cap (independent semantic from per-hop
|
|
143
|
+
`time_delta_max_hours`; both apply when both are set). API surface
|
|
144
|
+
preserved: same enumeration output shape, all existing tests pass.
|
|
145
|
+
Cites the Paranjape-Benson-Leskovec delta-temporal motif algorithm as
|
|
146
|
+
prior art for sliding-window enumeration; the implementation is a
|
|
147
|
+
pragmatic level-synchronous BFS (PBL counts fixed-template motifs
|
|
148
|
+
without per-edge predicates, which does not fit the enumerate-with-
|
|
149
|
+
arbitrary-predicates use case).
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
- `HopPredicate.require_anomalous_entity: bool` — new per-hop predicate
|
|
153
|
+
field for the declarative motif API (closes the X1 predicate set
|
|
154
|
+
alongside `amount_ratio_to_prev`). When `True` on hop `i`, the
|
|
155
|
+
destination entity (`nodes[i+1]` of the resulting motif) must satisfy
|
|
156
|
+
`is_anomaly=True` in the resolved anchor companion pattern's geometry.
|
|
157
|
+
Multiple hops can set this independently; constraints AND across hops.
|
|
158
|
+
Filter runs at the navigator layer after BFS enumeration but before
|
|
159
|
+
scoring (saves scoring work on motifs that get dropped). The seed
|
|
160
|
+
(`nodes[0]`) is never checked — pre-filter `seed_keys` upfront if seed
|
|
161
|
+
coverage is needed. `max_results` applies AFTER the filter, so a
|
|
162
|
+
restrictive filter can return fewer than `max_results` motifs. Raises
|
|
163
|
+
`GDSNavigationError` when no anchor companion is configured for the
|
|
164
|
+
queried event pattern, or when the anchor pattern has no `is_anomaly`
|
|
165
|
+
column (calibration must run first). Default `False` is a no-op,
|
|
166
|
+
preserving prior behavior. Reuses the same anchor-companion lookup
|
|
167
|
+
wired by F5; no sphere format change, no rebuild required.
|
|
168
|
+
- `HopPredicate.amount_ratio_to_prev: float | None` — new per-hop predicate
|
|
169
|
+
field for the declarative motif API. When set on hop `i ≥ 1`, the engine
|
|
170
|
+
rejects a candidate edge unless `current_amount / prev_hop_amount ≤
|
|
171
|
+
ratio`. Bounds `0 < ratio ≤ 1.0` enforced at validation; `hops[0]` must
|
|
172
|
+
leave the field None (no previous amount). Edges where either amount is
|
|
173
|
+
≤ 0 are silently skipped, matching the existing `find_motif_structuring`
|
|
174
|
+
convention. Use case: declarative structuring / layering chain detection
|
|
175
|
+
without baking absolute amount thresholds (`amount_min` / `amount_max`).
|
|
176
|
+
- Anchor-pattern aggregation of edge-derived dimensions (S1 extension).
|
|
177
|
+
An anchor pattern can declare `edge_dim_aggregations: { from: <event_pid>, dims: [...] }`
|
|
178
|
+
in its YAML stanza; the builder reads the event pattern's edge_features
|
|
179
|
+
sidecar and bakes per-anchor-entity `_mean` and `_max` aggregates of
|
|
180
|
+
the named source dims into the anchor polygon's `shape_snapshot`.
|
|
181
|
+
Aggregation handles two anchor regimes — `single` (anchor PK matches
|
|
182
|
+
edge `from_key` OR `to_key`, account-style) and `pair` (anchor PK
|
|
183
|
+
encoded as `<from>__<to>`, composite-pair-style); chain anchors
|
|
184
|
+
raise `NotImplementedError` and ship in 0.6.2. New
|
|
185
|
+
`EdgeDimAggregationsConfig` builder dataclass, `EdgeDimAggregationsRef`
|
|
186
|
+
runtime dataclass on `Pattern`, and
|
|
187
|
+
`engine.edge_features.aggregate_edge_dims_for_anchor` engine entry
|
|
188
|
+
point. Builder switches to a two-phase build (event patterns first,
|
|
189
|
+
anchor patterns second) when any pattern declares
|
|
190
|
+
`edge_dim_aggregations` so the sidecar dependency holds without a
|
|
191
|
+
topo sort. New aggregated dims surface automatically in every
|
|
192
|
+
existing anchor-pattern primitive (`find_anomalies`,
|
|
193
|
+
`explain_anomaly`, `find_clusters`, `find_calibration_influencers`,
|
|
194
|
+
`decompose_drift`) via the `dimension_kinds` source-of-truth — no
|
|
195
|
+
new tools, no MCP API change. Sphere format stays at 2.4; spheres
|
|
196
|
+
without the new YAML block are byte-identical.
|
|
197
|
+
|
|
10
198
|
## [0.6.0] — 2026-04-30
|
|
11
199
|
|
|
12
200
|
### Theme
|
|
@@ -26,7 +26,7 @@ For purposes of this License:
|
|
|
26
26
|
- **Internal use** within an organization is not a competitive offering. Your
|
|
27
27
|
organization includes entities under common control.
|
|
28
28
|
|
|
29
|
-
**Change Date:** 2029-
|
|
29
|
+
**Change Date:** 2029-05-05
|
|
30
30
|
|
|
31
31
|
**Change License:** Apache License, Version 2.0
|
|
32
32
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypertopos
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Understand the structure of your data — without training machine learning models
|
|
5
5
|
Project-URL: Homepage, https://github.com/hypertopos/hypertopos-py
|
|
6
6
|
Project-URL: Documentation, https://github.com/hypertopos/hypertopos-py/tree/main/docs
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://arrow.apache.org/docs/python/)
|
|
9
9
|
[](https://github.com/lance-format/lance)
|
|
10
10
|
[](https://modelcontextprotocol.io)
|
|
11
|
-
[](pyproject.toml)
|
|
12
12
|
|
|
13
13
|
hypertopos is not a database, and not a machine learning model. It is a layer that turns relational data into a coordinate system where every entity gets a position derived from its relationships and the population around it.
|
|
14
14
|
|
|
@@ -59,6 +59,16 @@ Each capability below emerges from treating entities as points in a shared, popu
|
|
|
59
59
|
| Structural motif scoring | Product of `edge_potential` across closed-vocab motifs (fan_out, cycle_2, cycle_3, structuring) | Graph DB motif matching has no geometric rarity score | `0.5.0` |
|
|
60
60
|
| Extended motif catalog | `fan_in` (sink-centric concentrator) and `chain_k` (open directed chain, 3 ≤ k ≤ 8) extend the motif vocabulary; window-filter correctness fix on fan_out/cycle_2/cycle_3 | Prior motifs silently ignored declared `time_window_hours` in production | `0.5.1` |
|
|
61
61
|
| Bipartite motif catalog | `split_recombine` (diamond scatter-gather S → k intermediaries → D, forward/backward seed anchoring) and `bipartite_burst` (complete K_{k,m} bipartite subgraph in tight window) cover scatter-gather smurfing, parallel layering, and coordinated-burst atoms | Closed-vocabulary atomic queries — no manual graph inversion or per-side enumeration glue | `0.5.2` |
|
|
62
|
+
| Multi-epoch calibration audit | `compare_calibrations(v_from, v_to)` — per-dim μ/σ/θ drift between two retained calibration epochs of one pattern | Drift detectors compare model predictions; nothing compares the underlying coordinate system itself | `0.6.0` |
|
|
63
|
+
| Intrinsic vs extrinsic drift decomposition | `decompose_drift` splits an entity's geometric drift into its own movement vs population recalibration; `intrinsic_fraction ∈ [0, 1]` | Drift magnitude alone — population shift and entity behaviour change confound | `0.6.0` |
|
|
64
|
+
| Hidden-influencer matrix | `find_calibration_influencers` — 4-cell classification (`hidden` / `distorter` / `standard_anomaly` / `normal`) via exact leave-one-out impact on calibration | SHAP / counterfactual: explain a prediction, not the coordinate system itself | `0.6.0` |
|
|
65
|
+
| Cross-pattern temporal lead-lag | `find_lead_lag(pattern_a, pattern_b)` — cross-correlates differenced population-centroid drift; peak lag, Bonferroni-adjusted significance, per-dim FDR matrix | Granger causality on raw metrics — not on population-relative geometry | `0.6.0` |
|
|
66
|
+
| Anomaly by absence | `find_density_gaps` — joint-density gaps under independence null with BH-corrected q-values; surfaces under-populated cells in named delta-space ranges | Outlier detection finds extremes; gap detection finds *missing* combinations | `0.6.0` |
|
|
67
|
+
| Declarative motif API | `find_motif_by_hops(pattern_id, hops, *, seed_keys)` — caller passes per-hop `HopPredicate`s (amount / time-delta / direction / edge-dim filters); navigator walks chains of length 1..8 with optional total-span cap (`time_window_hours`) | Closed-vocab motif registry — no escape hatch for ad-hoc structural shapes | `0.6.0` |
|
|
68
|
+
| Anchor-pattern aggregation of edge-derived dims | Anchor patterns declare `edge_dim_aggregations:` to bake per-edge sidecar signals (`pair_edge_count`, `find_motif_structuring`, …) into per-anchor `_mean` / `_max` columns; surfaces in every anchor primitive (`find_anomalies`, `explain_anomaly`, `find_clusters`) | Hand-rolled SQL roll-up + manual feature engineering | `0.6.1` |
|
|
69
|
+
| Richer hop predicates | `HopPredicate.amount_ratio_to_prev` (decreasing-chain ratio) and `require_anomalous_entity` (filter chains routing through calibrated-anomalous nodes) extend the declarative motif API | Closed-vocab motif library has fixed amount thresholds and no anomaly-routing filter | `0.6.1` |
|
|
70
|
+
| Event-aware motif scoring | `find_motif_by_hops(score=True)` ranks motifs by the product of event-aware `edge_potential` across edges (uses both the anchor companion's per-entity geometry and the event pattern's per-transaction polygons); distinct transactions between the same accounts produce distinct scores | Pure node-pair scoring collapses ranks when motifs share a node sequence | `0.6.1` |
|
|
71
|
+
| Chain-anchor aggregation | Chain anchor patterns auto-emitted from `chain_lines:` declare `edge_dim_aggregations:` to bake per-event sidecar signals into per-chain `_mean` / `_max` columns; closes the third `anchor_kind` after `single` and `pair` | Per-chain manual aggregation outside the geometry, or no chain-level edge-dim summary at all | `0.6.2` |
|
|
62
72
|
|
|
63
73
|
### What changes in practice
|
|
64
74
|
|
|
@@ -77,6 +87,8 @@ The same problems look different when graph, time, and statistics are unified:
|
|
|
77
87
|
| Root-cause an anomaly | Manual chain: explain → counterparties → contagion → hub check, 4+ tool calls | `trace_root_cause(entity)` — single call returns bounded DAG of evidence |
|
|
78
88
|
| Detect relationship layering | Custom rule engine or manual rare-pair SQL queries | `edge_potential(A, B)` — per-edge score combining endpoint distance and pair rarity |
|
|
79
89
|
| Match AML typology patterns | Graph DB subgraph queries + separate risk scoring | `find_motif(type="structuring", …)` — structural pattern + geometric rarity product |
|
|
90
|
+
| Match ad-hoc structural chains | Custom subgraph queries per shape, no built-in scoring | `find_motif_by_hops(hops=[HopPredicate(...)])` — declarative per-hop predicates (amount, time, direction, edge-dim, ratio-to-prev, anomaly filter) with event-aware geometric scoring on the same call |
|
|
91
|
+
| Account-level transaction layering recall | Hand-rolled SQL roll-ups of per-edge signals into account features | `edge_dim_aggregations:` on the anchor pattern bakes per-edge structuring / pair-recurrence / chain-depth signals into anchor geometry — read off `find_anomalies` like any other dim |
|
|
80
92
|
| Direction of behavioural drift | Drift magnitude alone — no toward/away-from-centre signal | `attract_drift` returns `drift_direction ∈ {normalizing, deteriorating, neutral}` |
|
|
81
93
|
|
|
82
94
|
## Benchmarks
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# hypertopos — Roadmap
|
|
2
|
+
|
|
3
|
+
> Planned direction. Priorities may change based on feedback.
|
|
4
|
+
|
|
5
|
+
## 0.6.0
|
|
6
|
+
|
|
7
|
+
Architecture-emergent analytics, properly enabled — calibration is now versioned, and patent-aligned analytics ride on that versioning.
|
|
8
|
+
|
|
9
|
+
- **0.6.0** — multi-epoch calibration retention, `compare_calibrations`, intrinsic / extrinsic drift decomposition, hidden-influencer matrix (`find_calibration_influencers`), cross-pattern temporal lead-lag (`find_lead_lag`), edge-derived event-pattern dimensions, joint density gap detection (`find_density_gaps`), declarative motif API (`find_motif_by_hops`, bounded MVP). Sphere format 2.4.
|
|
10
|
+
- **0.6.1** — anchor-pattern aggregation of edge-derived dimensions (`edge_dim_aggregations:`); BFS-by-level enumerator on `find_motif_by_hops` with hop count cap raised 6→8 and global `time_window_hours`; declarative motif API completion via `HopPredicate.amount_ratio_to_prev` and `require_anomalous_entity`; functional anchor-companion + event-aware scoring on `find_motif_by_hops(score=True)`; broadcast-safe `Pattern.dim_labels` on patterns with aggregated edge-dim names. Additive only — no sphere format bump, no new tools.
|
|
11
|
+
- **0.6.2** — chain-anchor `edge_dim_aggregations:` regime closes the third `anchor_kind` after single (account-style) and pair (k=2 composite); vectorized `AdjacencyIndex` load path (pyarrow `group_by` + lazy per-key materialization) for cold-start latency cleanup; column-selective `neighbors_*_window` accessors with motif enumerator migration for `bipartite_burst`, `fan_out`, `fan_in`, `cycle_2`; new project skill `profile-before-plan` gating hot-path refactors on real-data cProfile. Additive only — sphere format stays at 2.4 (the originally proposed persisted-artifact path was empirically refuted; vectorized loader ships without any on-disk change).
|
|
12
|
+
|
|
13
|
+
See [CHANGELOG](CHANGELOG.md) for the full feature list.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 0.5.0
|
|
18
|
+
|
|
19
|
+
Detection-quality and investigation-workflow push.
|
|
20
|
+
|
|
21
|
+
- **0.5.0** — Storey adaptive π₀ FDR; drift direction on `π9_attract_drift`; multi-hop root-cause tracing (`trace_root_cause` DAG); geometric edge potential; structural motif scoring (`fan_out`, `cycle_2`, `cycle_3`, `structuring`).
|
|
22
|
+
- **0.5.1** — `fan_in` and `chain_k` motifs.
|
|
23
|
+
- **0.5.2** — `split_recombine` and `bipartite_burst` motifs; perf-hardening pass on the catalog.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 0.4.0
|
|
28
|
+
|
|
29
|
+
Distribution-aware geometry, calibration fidelity, and graph acceleration.
|
|
30
|
+
|
|
31
|
+
- **0.4.0** — Distribution-aware Bregman divergence with per-dim kind tags; per-dimension anomaly threshold; in-memory adjacency index.
|
|
32
|
+
- **0.4.1** — Native graph algorithms as build-time dimensions (PageRank, betweenness, community, clustering, components); bidirectional BFS rewrite of `find_geometric_path`.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 0.3.0
|
|
37
|
+
|
|
38
|
+
Lance perf upgrade, FDR control, builder intelligence.
|
|
39
|
+
|
|
40
|
+
- **0.3.0** — Aggregate engine rewrite on Lance SQL; precomputed contagion stats; format 2.2.
|
|
41
|
+
- **0.3.1** — Benjamini-Hochberg FDR control; submodular facility location; vectorized build with adaptive memory chunking.
|
|
42
|
+
- **0.3.2** — NumPy graph features; chunked pre-computation; geometric heredity (`find_novel_entities`).
|
|
43
|
+
- **0.3.3** — Agent navigation policy; dimension-selective similarity.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 0.2.0
|
|
48
|
+
|
|
49
|
+
Graph meets geometry — edge table, runtime traversal, contagion/influence.
|
|
50
|
+
|
|
51
|
+
- **0.2.0** — Edge table; +11 navigator functions; contagion/influence primitives.
|
|
52
|
+
- **0.2.1** — Witness cohort discovery; investigative peer ranking.
|
|
53
|
+
- **0.2.2** — As-of graph reconstruction; `detect_cross_pattern_discrepancy` latency fix.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 0.1.0
|
|
58
|
+
|
|
59
|
+
First public release — full GDS stack, π1–π12, builder, MCP server, validation suite.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Future
|
|
64
|
+
|
|
65
|
+
**Detection quality**
|
|
66
|
+
- Robust estimators, multi-scale resolution — trimmed means / MAD-based σ, hierarchical build at daily/weekly/full granularity.
|
|
67
|
+
- Chains as first-class geometric entities — external chains declared as anchor lines with a membership table, plus chain-aware geometric primitives (anomaly propagation inside a chain, coherent-anomaly filter, chain drift trajectory).
|
|
68
|
+
|
|
69
|
+
**Builder evolution**
|
|
70
|
+
- Incremental rebuild — geometry-only without `--force` wipe.
|
|
71
|
+
|
|
72
|
+
**PassiveScanner evolution**
|
|
73
|
+
- Native temporal source support for direct temporal inputs, without requiring manual dataset plumbing in benchmark scripts.
|
|
74
|
+
- Optional weighted scoring mode that uses continuous intensity instead of binary counts.
|
|
75
|
+
- **SphereProfiler** — autonomous sphere scanner that profiles all patterns, runs calibration sweeps across source combinations, proposes optimal PassiveScanner composition for Layer 1 surveillance.
|
|
76
|
+
|
|
77
|
+
**Code refactoring**
|
|
78
|
+
- Break up oversized modules into smaller, domain-focused components (post-0.5.0 `navigator.py` is over 11k lines and is the obvious first target; per-pattern parallelism and AdjacencyIndex reuse in 0.4.0/0.5.0 reduced some coupling but the module itself did not shrink).
|
|
79
|
+
- Consolidate repeated orchestration logic into shared helpers.
|
|
80
|
+
|
|
81
|
+
**Cross-sphere capabilities**
|
|
82
|
+
- Cross-sphere comparison — dimensionless metrics across independently calibrated coordinate spaces.
|
|
83
|
+
- What-if analysis — hypothetical edge changes producing modified coordinate vectors.
|
|
84
|
+
|
|
85
|
+
**Enterprise / governance**
|
|
86
|
+
- Dimension access control — per-agent visibility constraints on delta dimensions.
|
|
87
|
+
|
|
88
|
+
**Tooling**
|
|
89
|
+
- Runtime latency benchmarks in package docs.
|
|
@@ -270,15 +270,16 @@ nav.find_motif_by_hops(
|
|
|
270
270
|
*,
|
|
271
271
|
seed_keys: list[str] | None = None,
|
|
272
272
|
max_results: int = 100,
|
|
273
|
-
score: bool =
|
|
273
|
+
score: bool = False,
|
|
274
|
+
time_window_hours: float | None = None,
|
|
274
275
|
) -> dict
|
|
275
276
|
```
|
|
276
277
|
|
|
277
|
-
Declarative motif API — power-user escape hatch from the closed-vocab `find_motif` registry. Caller passes a list of `HopPredicate`s describing per-hop constraints (`amount_min`, `amount_max`, `time_delta_max_hours`, `direction` (`"forward"` / `"reverse"` / `"any"`), `edge_dim_predicates: dict[str, tuple[op, value]]`); the navigator walks the in-memory `AdjacencyIndex` for matching chains. `seed_keys=None` enumerates from all `from_key` nodes (capped at `max_results`). Returns `{pattern_id, n_results, motifs}` with each motif carrying `nodes`, `edges` (event_keys), `timestamps`, `amounts`, `dim_values_per_hop` (only when `edge_dim_predicates` were used),
|
|
278
|
+
Declarative motif API — power-user escape hatch from the closed-vocab `find_motif` registry. Caller passes a list of `HopPredicate`s describing per-hop constraints (`amount_min`, `amount_max`, `time_delta_max_hours`, `amount_ratio_to_prev`, `direction` (`"forward"` / `"reverse"` / `"any"`), `edge_dim_predicates: dict[str, tuple[op, value]]`); the navigator walks the in-memory `AdjacencyIndex` for matching chains via level-synchronous BFS. `seed_keys=None` enumerates from all `from_key` nodes (capped at `max_results`). `time_window_hours` (optional, default `None`) caps the total chain span: when set, every hop after the first must satisfy `abs(current_edge_ts - first_edge_ts) <= time_window_hours`; independent of per-hop `time_delta_max_hours`, both apply when both are set. When `score=True`, the navigator resolves the event pattern's anchor companion via `_resolve_anchor_pattern_for_scoring` and scores each motif as the product of event-aware `edge_potential` (`delta_distance × (1/effective_pair_count) × (1 + event_norm)`) across its edges. The `event_norm` factor (norm of the event pattern's per-transaction polygon for each edge's `event_key`) breaks ties between motifs that share a node sequence but use different transactions. Scored motifs gain `score`, `score_breakdown` (per-edge entries carry `edge_potential`, `delta_distance`, `pair_tx_count`, `effective_weight`, `event_factor`), and `anchor_pattern_id` fields together (sorted descending on score, unscored motifs at tail). Returns `{pattern_id, n_results, motifs}` with each motif carrying `nodes`, `edges` (event_keys), `timestamps`, `amounts`, `dim_values_per_hop` (only when `edge_dim_predicates` were used), and the score triple when `score=True` succeeds. Raises on anchor pattern (event-only), unknown pattern, empty hops, hop count outside `1..8`, non-positive `time_window_hours`, `max_results<1`, or `score=True` with no anchor companion configured for the pattern.
|
|
278
279
|
|
|
279
280
|
### `HopPredicate` (dataclass, frozen)
|
|
280
281
|
|
|
281
|
-
Fields: `amount_min`, `amount_max`, `time_delta_max_hours`, `direction` (Literal["forward", "reverse", "any"], default `"forward"`), `edge_dim_predicates` (`dict[str, tuple[str, float]]`, e.g. `{"pair_edge_count": (">=", 20.0)}`). Operators: `<`, `<=`, `>`, `>=`, `==`.
|
|
282
|
+
Fields: `amount_min`, `amount_max`, `time_delta_max_hours`, `amount_ratio_to_prev` (`float | None`, decreasing-chain ratio in `(0, 1.0]`; rejects edge unless `current_amount / prev_hop_amount ≤ ratio`; must be `None` on `hops[0]`; edges with non-positive amounts are silently skipped), `direction` (Literal["forward", "reverse", "any"], default `"forward"`), `edge_dim_predicates` (`dict[str, tuple[str, float]]`, e.g. `{"pair_edge_count": (">=", 20.0)}`). Operators: `<`, `<=`, `>`, `>=`, `==`. `require_anomalous_entity` (`bool`, default `False`) — when `True` on hop `i`, the destination entity (`nodes[i+1]`) must satisfy `is_anomaly=True` in the resolved anchor companion pattern's geometry; constraints AND across hops; filter runs at the navigator post-BFS, pre-scoring; `max_results` applies AFTER the filter; raises `GDSNavigationError` when no anchor companion is configured.
|
|
282
283
|
|
|
283
284
|
### Density Gaps Engine (`hypertopos.engine.density_gaps`)
|
|
284
285
|
|
|
@@ -337,6 +338,9 @@ names in user-supplied `dim_pairs`.
|
|
|
337
338
|
|--------|-------------|
|
|
338
339
|
| `EdgeDimensionsConfig(dims: dict[str, dict])` | Parsed `edge_dimensions:` block — frozen dataclass attached to `PatternMapping.edge_dimensions` |
|
|
339
340
|
| `parse_edge_dimensions(raw_list, *, pattern_type)` | Parse + validate the YAML list of dim entries (bare strings or single-key dicts). Raises `ValueError` on anchor pattern, `min_position < 3`, `cv_threshold` outside `(0, 1]`, `min_count < 2`, non-positive `amt1_min` / `amt2_max` / `time_window_hours`, negative `burst_seconds`, duplicate or unknown dim names, malformed entries |
|
|
341
|
+
| `EdgeDimAggregationsConfig(from_event_pattern: str, dims: tuple[str, ...])` | Parsed `edge_dim_aggregations:` block on an anchor pattern — frozen dataclass attached to `PatternMapping.edge_dim_aggregations`. `dims` is a non-empty tuple of source dim names |
|
|
342
|
+
| `parse_edge_dim_aggregations(raw_dict, *, pattern_type)` | Parse + validate the YAML mapping. Raises `ValueError` on event pattern, missing `from`, missing or empty `dims` (non-empty list required), non-list `dims`, or unknown dim name |
|
|
343
|
+
| `aggregate_edge_dims_for_anchor(*, anchor_keys, edges, sidecar, dims, anchor_kind, pair_separator, chain_events)` | Aggregate per-edge sidecar dim values up to per-anchor `_mean` / `_max` columns. `anchor_kind` ∈ `{single, pair, chain}`. For chain regime, pass `chain_events: list[str]` of comma-joined event_keys per anchor (one per `anchor_keys` entry); `edges` arg is ignored. Returns a `pa.Table` keyed by `primary_key` |
|
|
340
344
|
|
|
341
345
|
### Calibration History (GDSReader)
|
|
342
346
|
|
|
@@ -30,7 +30,7 @@ The core package is split into a few layers:
|
|
|
30
30
|
- **Builder**: transforms source data into a complete sphere
|
|
31
31
|
- **CLI**: builds and inspects spheres from the command line
|
|
32
32
|
|
|
33
|
-
The `hypertopos-mcp` package sits on top of this core library and exposes the same capabilities to agents via
|
|
33
|
+
The `hypertopos-mcp` package sits on top of this core library and exposes the same capabilities to agents via 80 MCP tools.
|
|
34
34
|
|
|
35
35
|
The split is deliberate:
|
|
36
36
|
|
|
@@ -175,7 +175,7 @@ graph LR
|
|
|
175
175
|
ST --> E["Engine\ngeometry, delta,\nclustering, DTW"]
|
|
176
176
|
E --> N["Navigator\nπ1–π12, detect_*"]
|
|
177
177
|
N --> PS["PassiveScanner\nmulti-source\nbatch screening"]
|
|
178
|
-
N --> MCP["MCP Server\
|
|
178
|
+
N --> MCP["MCP Server\n80 tools\nstdio transport"]
|
|
179
179
|
MCP --> Agent["AI Agent"]
|
|
180
180
|
CT["CalibrationTracker\nonline drift\nWelford stats"] -.-> E
|
|
181
181
|
M["Manifest\nMVCC version pin"] -.-> ST
|
|
@@ -238,7 +238,7 @@ Event patterns can declare an `edge_dimensions:` block in YAML to add up to five
|
|
|
238
238
|
| `pair_amount_zscore` (LOW_VAR pairs only) | gaussian | signed z-score of amount within `(from_key, to_key)` pairs whose CV(amount) < `cv_threshold`; HIGH_VAR pairs and pairs below `min_count` write 0.0 — direction-agnostic outlier signal on locked-amount pairs |
|
|
239
239
|
| `find_motif_structuring` | bernoulli | 1.0 if the edge participates in any A→B→C→D structuring motif within `time_window_hours` with hop1 ≥ `amt1_min` and hops 2/3 ≤ `amt2_max` |
|
|
240
240
|
|
|
241
|
-
These dims are computed at edge-table emission time, written to the `_gds_meta/edge_features/{pid}/data.lance` sidecar keyed by `event_key`, AND merged into the event polygon `shape_snapshot` (one extra dim per declared entry). Downstream primitives (`find_anomalies`, `find_similar_entities`, `find_clusters`) automatically include them in `delta` / `delta_norm` / classification — no new query API. Reject `min_position < 3` at YAML parse time. Anchor patterns reject the block
|
|
241
|
+
These dims are computed at edge-table emission time, written to the `_gds_meta/edge_features/{pid}/data.lance` sidecar keyed by `event_key`, AND merged into the event polygon `shape_snapshot` (one extra dim per declared entry). Downstream primitives (`find_anomalies`, `find_similar_entities`, `find_clusters`) automatically include them in `delta` / `delta_norm` / classification — no new query API. Reject `min_position < 3` at YAML parse time. Anchor patterns reject the `edge_dimensions:` block directly; to expose these per-edge signals on anchor entities, declare `edge_dim_aggregations:` on the anchor pattern instead — see `configuration.md` for the YAML stanza and supported aggregates (`_mean` / `_max`). For chain anchor patterns auto-emitted from `chain_lines:` config, declare `edge_dim_aggregations:` directly inside the `chain_lines.<id>:` block — same `from: <event_pid>` and `dims: [...]` schema as on regular anchor patterns; the builder forwards it to the auto-emitted `<id>_pattern`.
|
|
242
242
|
|
|
243
243
|
## Chain Interpretation
|
|
244
244
|
|
|
@@ -373,6 +373,7 @@ patterns:
|
|
|
373
373
|
| `description` | string | `null` | Human-readable description. Stored in sphere.json — visible to agents via `get_sphere_info`. |
|
|
374
374
|
| `edge_table` | dict | `null` | Explicit edge table config (see below). Auto-emitted for event patterns with 2+ FK relations to same anchor line. |
|
|
375
375
|
| `edge_dimensions` | list | `null` | Build-time per-edge dims for event patterns. Each item is either a bare dim name or a single-key dict with overrides. Five dims available: `pair_edge_count`, `position_in_chain` (`min_position` ≥ 3, default 5), `time_since_pair_last_edge`, `pair_amount_zscore` (LOW_VAR pairs only), `find_motif_structuring`. |
|
|
376
|
+
| `edge_dim_aggregations` | dict | `null` | **Anchor patterns only.** Aggregate per-edge sidecar dims of an event pattern up to per-anchor `_mean` / `_max` columns baked into the anchor polygon. `from: <event_pid>` is required and must reference an event pattern that declares `edge_dimensions:`. `dims: [...]` is required — must be a non-empty list of source dim names from the referenced sidecar (the previous "omit `dims` to aggregate everything" shorthand was removed; explicit declaration prevents build-vs-runtime label drift). Anchor regimes: `single` (account-style, anchor PK matches edge `from_key` OR `to_key`) and `pair` (composite-key, anchor PK = `<from>__<to>`); `chain` raises `NotImplementedError`. Builder switches to a two-phase build (events first, anchors second) when this block is present. |
|
|
376
377
|
| `bootstrap_iterations` | int | `200` | Number of bootstrap resamples used to compute `anomaly_confidence` per entity. Skipped automatically for N > 50K, `group_by_property`, or `use_mahalanobis`. |
|
|
377
378
|
|
|
378
379
|
### Edge Table
|
|
@@ -733,6 +734,25 @@ Automatically creates an anchor line + pattern (`{line_id}_pattern`).
|
|
|
733
734
|
| `bidirectional` | bool | `true` | Follow edges in both directions. |
|
|
734
735
|
| `anomaly_percentile` | float | `95.0` | Theta for the auto-created chain pattern. |
|
|
735
736
|
| `description` | string | `null` | Description for chain line + pattern. |
|
|
737
|
+
| `edge_dim_aggregations` | dict | `null` | Aggregate per-edge sidecar dims of an event pattern up to per-chain `_mean` / `_max` columns baked into the chain anchor polygon. `from: <event_pid>` is required and must reference an event pattern that declares `edge_dimensions:` and whose `edge_table.event_line` matches this `chain_lines.<id>.event_line` (validated at parse time). `dims: [...]` is required — non-empty list of source dim names from the referenced sidecar. The chain anchor pattern's polygon shape grows by `2 * len(dims)` columns; downstream primitives (`find_anomalies`, `explain_anomaly`, `find_clusters`) surface the new dims transparently. |
|
|
738
|
+
|
|
739
|
+
**Example with edge-dim aggregation on chain anchor:**
|
|
740
|
+
|
|
741
|
+
```yaml
|
|
742
|
+
chain_lines:
|
|
743
|
+
tx_chains:
|
|
744
|
+
event_line: transactions
|
|
745
|
+
from_col: from_account
|
|
746
|
+
to_col: to_account
|
|
747
|
+
features: [hop_count, is_cyclic, time_span_hours]
|
|
748
|
+
edge_dim_aggregations:
|
|
749
|
+
from: tx_pattern # event pattern declaring edge_dimensions
|
|
750
|
+
dims: [find_motif_structuring, position_in_chain]
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
The chain anchor `tx_chains_pattern` then exposes `find_motif_structuring_mean`,
|
|
754
|
+
`find_motif_structuring_max`, `position_in_chain_mean`, `position_in_chain_max`
|
|
755
|
+
in `find_anomalies` response and `Pattern.dim_labels`.
|
|
736
756
|
|
|
737
757
|
---
|
|
738
758
|
|