mtlearn 1.2.2__tar.gz → 2.0.0__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.
- mtlearn-2.0.0/.github/scripts/repository_promotion.py +599 -0
- mtlearn-2.0.0/.github/scripts/test_ci_policy.py +233 -0
- mtlearn-2.0.0/.github/scripts/test_repository_promotion.py +1233 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/.github/workflows/ci.yml +59 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/.github/workflows/docs.yml +1 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/.github/workflows/notebooks.yml +1 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/.github/workflows/package.yml +1 -0
- mtlearn-2.0.0/.github/workflows/promote-public.yml +67 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/.github/workflows/release.yml +28 -1
- mtlearn-2.0.0/.github/workflows/sync-private.yml +59 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/PKG-INFO +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/development.md +10 -11
- mtlearn-2.0.0/docs/source/guides/datasets.md +482 -0
- mtlearn-2.0.0/docs/source/guides/patch-training-cache.md +411 -0
- mtlearn-2.0.0/external/mmcfilters/AGENTS.md +10 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/README.md +6 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/CMakeLists.txt +5 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/analyze_tree_construction_comparison.py +2 -6
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/AttributeScenarios.cpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/CasfScenarios.cpp +1 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/ConstructionScenarios.cpp +2 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/build_tree_construction_report.py +24 -69
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/distance_transform_sensitivity.py +12 -29
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/distance_transform_timing.py +10 -12
- mtlearn-2.0.0/external/mmcfilters/benchmarks/extremum_residual_tree_by_cts_benchmark.cpp +121 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/python_api_benchmark.py +7 -7
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/bitquad_benchmark.cpp +20 -14
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/tree_construction_comparison_benchmark.cpp +7 -12
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/tree_validation_benchmark.cpp +1 -23
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/workloads/scientific-api.ini +13 -13
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/cmake/mmcfiltersPublicHeaders.cmake +26 -41
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/AttributeRegistry.hpp +21 -7
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/AttributeTypes.hpp +6 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/AreaComputer.hpp +17 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/BitquadAttributeComputer.hpp +16 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/BoundingBoxComputer.hpp +22 -9
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/ContourSideAttributeComputer.hpp +16 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/FilledShapeAttributeComputer.hpp +25 -10
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/GrayLevelStatsComputer.hpp +17 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/MaxDistComputer.hpp +14 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/MaxDistExactComputer.hpp +14 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/MomentBasedAttributeComputer.hpp +85 -28
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/TreeTopologyComputer.hpp +21 -10
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/VolumeComputer.hpp +17 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/BitquadAttributeProjection.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/BitquadConnectivityPolicy.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/BitquadFiniteWindowComputation.hpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/ContourSideAttributeMaterialization.hpp +3 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/MorphologicalTreeDistanceTransform.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/NodeContourSchedule.hpp +1 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/NodeSupportBoxIndex.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/MorphologicalTreeApproximateDistanceTransform.hpp +6 -6
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/MorphologicalTreePropagationEdgeIndex.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/MorphologicalTreeTopologicalLevelIndex.hpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeCapabilityValidation.hpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeFamilyScheduler.hpp +1 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeKernelSupport.hpp +14 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributePipeline.hpp +2 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeProjection.hpp +7 -7
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/MorphologicalTreeConstructionContextQueries.hpp → mtlearn-2.0.0/external/mmcfilters/mmcfilters/attributes/detail/BitquadProjectionAdjacencies.hpp +2 -23
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/NodeAttributeSampleMaterialization.hpp +52 -31
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/ContourTraceComputation.hpp +10 -10
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/ContourLifetimeIndex.hpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/ContourTraversal.hpp +4 -4
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/NodeSupportIndex.hpp +5 -5
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/distanceTransform/DistanceTransformComputation.hpp +150 -0
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/distanceTransform/DistanceTransformProfiles.hpp +113 -0
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/distanceTransform/DistanceTransformTypes.hpp +33 -0
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/distanceTransform/NodeDistanceField.hpp +81 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/AttributeFilters.hpp +52 -43
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/AttributeReconstructionFilters.hpp +67 -37
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/DepthStableRegionComputer.hpp +6 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/ExtinctionValues.hpp +12 -13
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/MSERComputer.hpp +11 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/NodeDecisionMasks.hpp +13 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/NodePreservationStability.hpp +10 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/UltimateAttributeOpening.hpp +8 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/detail/ViterbiDecision.hpp +11 -11
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/localAttributes/ConnectedSubsetTreeLocalizer.hpp +5 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/localAttributes/FiniteWindowLocalAttributeComputer.hpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/localAttributes/FiniteWindowLocalEventCompiler.hpp +7 -7
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/ComponentTreeBuilder.hpp +251 -0
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/ExtremumResidualTreeByCTsBuilder.hpp +443 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/MorphologicalTree.hpp +68 -43
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/MorphologicalTreeFactory.hpp +277 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/MorphologicalTreeSemantics.hpp +4 -18
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/NativeHierarchyOwned.hpp +93 -0
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/NativeHierarchy.hpp → mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/NativeHierarchyView.hpp +5 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/TreeAltitudeAlgorithms.hpp +74 -18
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/TreeEditor.hpp +40 -37
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/TreeOfShapesProducer.hpp → mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/TreeOfShapesBuilder.hpp +142 -107
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/ValuedMorphologicalTree.hpp +39 -36
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/ValuedMorphologicalTreeView.hpp +21 -5
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/detail/DualMinMaxTreeIncrementalFilterLeaf.hpp +658 -0
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/detail/HigraHierarchyDetail.hpp +435 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/detail/MorphologicalTreeConstructionTag.hpp +25 -3
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/CommittedTreeAccess.hpp → mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/detail/TreeKernelAccess.hpp +42 -5
- mtlearn-2.0.0/external/mmcfilters/mmcfilters/trees/detail/TreeNeighborhood.hpp +195 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/saliency/HierarchicalWatershedSaliency.hpp +14 -31
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/saliency/HierarchySaliencyMap.hpp +148 -121
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/saliency/HierarchySaliencyMapProjection.hpp +7 -21
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/saliency/HierarchySaliencyMapValidation.hpp +178 -192
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/saliency/ShapeSpaceSaliency.hpp +75 -89
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/CommittedGridAccess.hpp +5 -5
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/CommittedImageAccess.hpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/Image.hpp +0 -16
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/RegularGridAdjacency2D.hpp +49 -20
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/AdjustBindings.cpp +3 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/AttributeBindings.cpp +17 -45
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/AttributeComputationBindings.hpp +28 -16
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/AttributeFiltersPybind.hpp +120 -61
- mtlearn-2.0.0/external/mmcfilters/pybinds/ContourMapPybind.hpp +130 -0
- mtlearn-2.0.0/external/mmcfilters/pybinds/DistanceTransformBindings.cpp +129 -0
- mtlearn-2.0.0/external/mmcfilters/pybinds/EdgeMapPybind.hpp +149 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/ExtinctionValuesPybind.hpp +14 -31
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/FilterBindings.cpp +52 -145
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/ModuleBindings.hpp +6 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/PybindConversions.hpp +25 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/PythonValuedMorphologicalTree.hpp +1 -1
- mtlearn-2.0.0/external/mmcfilters/pybinds/ShapeSpaceResultsPybind.hpp +124 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/TreeBindings.cpp +94 -437
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/UltimateAttributeOpeningPybind.hpp +11 -11
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/UtilityBindings.cpp +2 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/scripts/validate_notebooks.py +46 -10
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/morphology/AttributeBinding.hpp +79 -22
- mtlearn-2.0.0/mtlearn/bindings/morphology/AttributeFiltersBinding.hpp +285 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/morphology/BindingSupport.hpp +11 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/morphology/WeightedTreeBinding.hpp +4 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/include/mtlearn/detail/morphology_backend.hpp +6 -7
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/include/mtlearn/morphology.hpp +3 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/__init__.py +3 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_backends/_mtlearn.py +8 -24
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_dataset_contracts.py +160 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/_explicit_pairs.py +34 -2
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/_image_ops.py +18 -2
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_manifest_dataset.py +34 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_pair_audit.py +135 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/_paired_image.py +94 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_sample_ids.py +37 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_split_ids.py +184 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_split_manifest.py +293 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/_datasets/_suffix_pairs.py +64 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_version.py +3 -3
- mtlearn-2.0.0/mtlearn/python/mtlearn/datasets.py +42 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/cfp_preprocessor.py +1 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/serialization/config_deserializer.py +2 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/morphology.py +16 -69
- mtlearn-2.0.0/mtlearn/python/mtlearn/patches/__init__.py +19 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/patches/_geometry.py +229 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/patches/_reconstruction.py +62 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/training/__init__.py +5 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/training/_patch_backward.py +294 -0
- mtlearn-2.0.0/mtlearn/python/mtlearn/training/_patch_diagnostics.py +76 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/CMakeLists.txt +2 -3
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/cpp/public_morphology.cpp +6 -0
- mtlearn-2.0.0/mtlearn/tests/python/fixtures/mmcfilters_v8/v1.3.0-float32-cache.pt.gz +0 -0
- mtlearn-2.0.0/mtlearn/tests/python/fixtures/mmcfilters_v8/v1.3.0-float64-cache.pt.gz +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_bindings.py +9 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_deterministic.py +1 -1
- mtlearn-2.0.0/mtlearn/tests/python/test_dataset_pair_audit.py +176 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_dataset_split_ids.py +121 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_dataset_split_manifest.py +297 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_gradchecks.py +1 -1
- mtlearn-2.0.0/mtlearn/tests/python/test_mmcfilters_v8.py +208 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_mmcfilters_v8_cache.py +107 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_morphology_api.py +47 -51
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_morphology_attribute_groups.py +9 -8
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_morphology_bounding_box_width.py +21 -10
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_morphology_gray_level.py +5 -5
- mtlearn-2.0.0/mtlearn/tests/python/test_notebook_mmcfilters_v8.py +93 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_patch_backward.py +325 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_patch_cfp_integration.py +119 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_patch_geometry.py +85 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_patch_reconstruction.py +63 -0
- mtlearn-2.0.0/mtlearn/tests/python/test_suffix_paired_dataset.py +90 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/pyproject.toml +1 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p0.py +3 -3
- mtlearn-2.0.0/scripts/benchmarks/patch_backward.py +129 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/smoke_test_release.py +1 -1
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/validate_notebooks.py +2 -2
- mtlearn-1.2.2/external/mmcfilters/benchmarks/README.md +0 -323
- mtlearn-1.2.2/external/mmcfilters/benchmarks/min_max_residual_tree_benchmark.cpp +0 -190
- mtlearn-1.2.2/external/mmcfilters/benchmarks/validation-sensitive.md +0 -71
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/MorphologicalTreeFactory.hpp +0 -472
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/adjust/DualMinMaxTreeIncrementalFilterLeaf.hpp +0 -1417
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/ComponentTreeProducerDetail.hpp +0 -125
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/ComponentTreeUnionFind.hpp +0 -155
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/HierarchyCapabilityValidation.hpp +0 -49
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/HigraExportLayoutDetail.hpp +0 -138
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/HigraHierarchyAdapterDetail.hpp +0 -130
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/HigraImportLayoutDetail.hpp +0 -103
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/NativeHierarchyValidationDetail.hpp +0 -631
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/TreeAttributeSamplingNeighborhood.hpp +0 -227
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/TreeStabilityNeighborhood.hpp +0 -273
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/detail/TreeTraversalDetail.hpp +0 -66
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/ResidualEvolution.hpp +0 -274
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/ResidualTreeBuildStatistics.hpp +0 -24
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/ResidualTreePolicies.hpp +0 -37
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/SaturatedResidualTreeBuilder.hpp +0 -90
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/UnrestrictedResidualTreeBuilder.hpp +0 -82
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/FlatZonePartition.hpp +0 -397
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeCandidateAgenda.hpp +0 -191
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeCandidateContext.hpp +0 -59
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeCandidatePreparation.hpp +0 -117
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeCandidateTypes.hpp +0 -21
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeEventAssembler.hpp +0 -294
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeMaterialization.hpp +0 -59
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/ResidualTreeRegionTypes.hpp +0 -13
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/SaturatedDynamicLca.hpp +0 -722
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/SaturatedResidualEligibility.hpp +0 -338
- mtlearn-1.2.2/external/mmcfilters/mmcfilters/trees/sdrt/detail/SynchronizedResidualTreeEvolution.hpp +0 -607
- mtlearn-1.2.2/external/mmcfilters/pybinds/AttributeReconstructionFiltersPybind.hpp +0 -152
- mtlearn-1.2.2/mtlearn/bindings/morphology/AttributeFiltersBinding.hpp +0 -303
- mtlearn-1.2.2/mtlearn/python/mtlearn/datasets.py +0 -21
- {mtlearn-1.2.2 → mtlearn-2.0.0}/CMakeLists.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/LICENSE +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/Pipfile +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/README.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/cmake/mtlearnConfig.cmake.in +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/assets/cfp-class-architecture.svg +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/cfp-architecture.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/cfp-loss-design.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/cfp-regularization-design.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/cfp-score-constraint-design.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/cfp-scoring-design.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/installation.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/_static/.gitkeep +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/_templates/.gitkeep +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/cfp_preparation.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/data.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/datasets.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/index.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/layers.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/morphology.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/api/python/native.rst +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/concepts/attributes.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/concepts/morphology.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/conf.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/guides/custom-attributes-filter-specs.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/guides/getting-started.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/guides/index.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/guides/morphology.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/guides/pytorch-integration.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/docs/source/index.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/environment.yml +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/.clang-format +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/.editorconfig +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/.gitattributes +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/CMakeLists.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/LICENSE +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/adjacency_iteration_benchmark.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/analyze_scientific_experiment.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/ApiBenchmark.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/EditingScenarios.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/FilterScenarios.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/InteroperabilityScenarios.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/PipelineScenarios.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/WorkloadManifest.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/api/api_benchmark.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/compare_validation_modes.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/scientific_pipeline_benchmark.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/analyze_results.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/bitquad_exactness_validation.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/correctness.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/dataset-manifest.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/experiment.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/raw-1080p.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/raw-480p.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/raw-720p.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/run-1080p.log +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/run-480p.log +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/run-720p.log +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/speedups.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/summary.csv +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/reference-results/table.tex +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/sibgrapi2026/run_experiment.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/summarize_scientific_campaign.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/support/ScientificBenchmark.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/support/stb_image_read.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/validation_sensitive_algorithms_benchmark.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/benchmarks/workloads/distance-transform-contract.ini +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/cmake/mmcfiltersConfig.cmake.in +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/CMakeLists.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/AttributeComputation.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/AttributeNames.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/AttributeResultTypes.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/Attributes.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/AttributeComputerDomain.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/AttributeComputerFamily.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/AttributeComputerRegistry.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/BitquadAttributeData.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/ContourSideAttributeData.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/ContourSideFiniteWindowComputation.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/DistanceFieldHistogram.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/DistanceFieldMoments.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/DistanceWeightedSpatialMoments.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/ExactSquaredEuclideanDistanceTransform2D.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform/NodeDistanceFieldProvider.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/AdaptiveSquaredEuclideanDIFT2D.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/DynamicDistanceFieldMoments2D.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/DynamicDistanceFieldStatistics2D.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/computers/detail/distance_transform_approx/SquaredDistanceBucketQueue.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeDependencyCache.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeNumericPolicy.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/AttributeRequestUtils.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/attributes/detail/TopologyAttributeBackend.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/ContourComputation.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/ContourTrace.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/ContourBoundaryTracer.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/ContourEdgeDeltaStore.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/contours/detail/ContourTraceTraversal.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/dataStructure/FastQueue.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/dataStructure/FastStack.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/filters/detail/VariationMeasure.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/localAttributes/LocalEventModel.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/ProperPartDomain.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/adjust/CasfComponentTrees.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/adjust/DualMinMaxTreeIncrementalFilter.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/trees/adjust/DynamicTreeAttributeComputer.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/Altitude.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/Assert.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/Common.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/Contract.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/mmcfilters/utils/GenerationStampSet.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/ContourBindings.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/ContourTraceBindings.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/pybinds/DepthStableRegionComputerPybind.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/external/mmcfilters/scripts/execute_notebooks.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/CMakeLists.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/MtlearnModule.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/cfp/TreeTensorsBinding.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/bindings/cfp/TreeTraversalBinding.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_backends/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/_generated_target.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_datasets/_split.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/_native.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/data.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/_helpers.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/component_registries.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/connected_filter_preprocessing_layer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/constraints/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/constraints/base.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/constraints/preserve_root.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/normalization/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/normalization/attribute_normalizer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/normalization/attribute_statistics.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/normalization/statistics_snapshot.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/normalization/stats_serializer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_calibration_measurement.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_disk_preparation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_identity.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_loader_memory.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_parallel_preparation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_persistent_preparation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_preparation_progress.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_prepared_reader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_process_reader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_read_diagnostics.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_reader_process.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_shared_batch.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_statistics_fitter.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/_threaded_reader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/calibration.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/dataset_cache.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/dataset_diagnostics.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/dataset_source.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/preparation_result.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/prepared_batch.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/prepared_dataloader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/prepared_dataset.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/preparation/prepared_morphology.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/_tree_info.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/attribute_order_score_monotonicity.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/base.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/edge_score_monotonicity.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/regularization/path_score_monotonicity.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/_prepared_lifetime.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/batch_input.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/cache_input_contract.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/cached_dataloader_builder.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/context.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/forward_executor.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/implicit_jacobian_function.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/training_sample_inspector.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/tree_payload_cache.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/tree_payload_provider.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/runtime/tree_reconstructor.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/scoring/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/scoring/_layer_owned_linear_parameter_initializer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/scoring/base.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/scoring/linear_sigmoid.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/scoring/mlp.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/serialization/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/serialization/config_serializer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/serialization/persistent_state_manager.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/feature_spec.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/filter_spec.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/filter_spec_normalizer.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/normalized_filter_spec.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/spec_registry.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/specs/tree_spec.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/__init__.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_disk_format.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_manifest.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_manifest_inspection.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_read_validation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_storages.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/_writer_lock.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/disk_store.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/memory_store.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/cfp/storage/null_store.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/python/mtlearn/layers/checkpoint.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/src/CMakeLists.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/src/mtlearn/cfp/tree_tensors.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/src/mtlearn/cfp/tree_traversal.hpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/src/mtlearn/morphology.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/cmake/installed_consumer_test.cmake +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/cpp/test_interpreter.cpp +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/_paired_dataset_reference.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/cfp_reference_names.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/README.md +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/baseline.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/manifest.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_minmax01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_minmax01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_zscore.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_dataset_zscore.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_none.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_linear_none.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_minmax01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_minmax01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_zscore.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_dataset_zscore.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_none.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/max-tree_mlp_none.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/min-tree_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/min-tree_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/min-tree_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/min-tree_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/tree-of-shapes_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/tree-of-shapes_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/tree-of-shapes_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0/tree-of-shapes_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/baseline.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/manifest.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_minmax01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_minmax01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_zscore.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_dataset_zscore.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_none.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_linear_none.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_minmax01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_minmax01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_zscore.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_dataset_zscore.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_none.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/max-tree_mlp_none.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/min-tree_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/min-tree_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/min-tree_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/min-tree_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/tree-of-shapes_linear_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/tree-of-shapes_linear_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/tree-of-shapes_mlp_dataset_clipped_zscore01.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p0_mmcfilters_v5_2_0/tree-of-shapes_mlp_dataset_clipped_zscore01.stats.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p1/statistics.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_cache_p5/notebook_before_p5.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_linear_sigmoid_max-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_linear_sigmoid_min-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_linear_sigmoid_tree-of-shapes.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_mlp_max-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_mlp_min-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/legacy_mlp_tree-of-shapes.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/manifest.json +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_linear_sigmoid_max-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_linear_sigmoid_min-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_linear_sigmoid_tree-of-shapes.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_mlp_max-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_mlp_min-tree.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/fixtures/cfp_disk_cache_e0/memory_mlp_tree-of-shapes.pt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_cache.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_cache_baseline.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_cache_calibration.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_cache_compatibility.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_checkpoint_independence.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_components.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_dataset_cache.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_dataset_diagnostics.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_dataset_source.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_disk_cache.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_disk_cache_e0.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_disk_cache_validation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_disk_preparation_flow.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_jacobian_intervals.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_mps_reconstruction.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_notebook_cache_budget.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_notebook_streaming.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_parallel_preparation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_preparation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_prepared_dataloader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_prepared_runtime.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_process_dataloader.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_uint32_pixel_map.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_cfp_validation.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_data.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_paired_dataset_characterization.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_reusable_paired_dataset.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/mtlearn/tests/python/test_version.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/requirements.txt +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p1.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p2.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p3.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p4.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p5.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p6.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_cache_p6_finalize.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/benchmarks/cfp_jacobian_intervals.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/download_data.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/install_release_dependencies.py +0 -0
- {mtlearn-1.2.2 → mtlearn-2.0.0}/scripts/resolve_package_version.py +0 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Publish approved private PRs and reconcile the two repository histories.
|
|
3
|
+
|
|
4
|
+
Operational limits:
|
|
5
|
+
- Until scheduled executions are verified, start an idle publication queue after
|
|
6
|
+
merging private work with:
|
|
7
|
+
gh workflow run promote-public.yml --repo wonderalexandre/MTLearn
|
|
8
|
+
A successful private synchronization resumes the remaining queue automatically.
|
|
9
|
+
- Closing a publication PR without merging blocks later publications. Reopen it
|
|
10
|
+
to continue; closing it does not cancel the change already in private main.
|
|
11
|
+
- Development PRs require squash merges; synchronization PRs require merge commits.
|
|
12
|
+
- If conflict resolution leaves a public PR with no content changes, completion
|
|
13
|
+
requires manual review. Do not assume GitHub can squash an empty PR or silently
|
|
14
|
+
treat the original private change as published. Cancellation is not automated.
|
|
15
|
+
- A conflicting expected tree can use the original promotion tree only when both
|
|
16
|
+
sides agree on every path changed by already-integrated public commits. Other
|
|
17
|
+
cases require manual synchronization; an unguarded historical base can lose fixes.
|
|
18
|
+
- Public main supplies the running controller. The PR introducing a new version
|
|
19
|
+
still uses the previous controller until merged. A blocked rollout can require
|
|
20
|
+
a separate public maintenance PR, with public CI and normal review.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
import re
|
|
28
|
+
import subprocess
|
|
29
|
+
from urllib.parse import urlencode
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
PUBLIC = "wonderalexandre/MTLearn"
|
|
33
|
+
PRIVATE = "wonderalexandre/MTLearn-dev"
|
|
34
|
+
SYNC_BRANCH = "sync/public-main"
|
|
35
|
+
PROMOTION_PREFIX = "promotion/private-pr-"
|
|
36
|
+
MARKER = re.compile(r"<!-- mtlearn-promotion: (\{[^\n]+\}) -->")
|
|
37
|
+
PUBLISHED_MARKER = re.compile(r"<!-- mtlearn-already-published: (\{[^\n]+\}) -->")
|
|
38
|
+
APPROVED_MERGE_RECOVERIES = {
|
|
39
|
+
"5fa238708ab0a903d1c4e8a9e80520ba1a91ade6": (
|
|
40
|
+
8,
|
|
41
|
+
"47e9d95b98e84034c3cda2dc34ea297144a01b7b",
|
|
42
|
+
"fa09ef45af13afee38c07512441d72d372ba3c28",
|
|
43
|
+
),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PromotionError(RuntimeError):
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class MergeConflict(PromotionError):
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def command(args, *, cwd=None, data=None, check=True):
|
|
56
|
+
result = subprocess.run(args, cwd=cwd, input=data, text=True, capture_output=True)
|
|
57
|
+
if check and result.returncode:
|
|
58
|
+
raise PromotionError(result.stderr.strip() or result.stdout.strip())
|
|
59
|
+
return result
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class GitHub:
|
|
63
|
+
def api(self, path, method="GET", data=None):
|
|
64
|
+
args = ["gh", "api", "--method", method, path]
|
|
65
|
+
if data is not None:
|
|
66
|
+
args += ["--input", "-"]
|
|
67
|
+
result = command(args, data=json.dumps(data) if data is not None else None)
|
|
68
|
+
return json.loads(result.stdout) if result.stdout.strip() else None
|
|
69
|
+
|
|
70
|
+
def pages(self, path, **query):
|
|
71
|
+
rows = []
|
|
72
|
+
for page in range(1, 10001):
|
|
73
|
+
batch = self.api(path + "?" + urlencode(dict(query, per_page=100, page=page)))
|
|
74
|
+
rows.extend(batch)
|
|
75
|
+
if len(batch) < 100:
|
|
76
|
+
return rows
|
|
77
|
+
raise PromotionError("Pagination limit exceeded.")
|
|
78
|
+
|
|
79
|
+
def pull(self, repo, number):
|
|
80
|
+
return self.api(f"repos/{repo}/pulls/{number}")
|
|
81
|
+
|
|
82
|
+
def find_pull(self, repo, branch, state="all"):
|
|
83
|
+
rows = self.pages(
|
|
84
|
+
f"repos/{repo}/pulls", state=state, base="main",
|
|
85
|
+
head=f"{repo.split('/')[0]}:{branch}",
|
|
86
|
+
)
|
|
87
|
+
if len(rows) > 1:
|
|
88
|
+
raise PromotionError(f"Multiple PRs use {repo}:{branch}; resolve them first.")
|
|
89
|
+
return rows[0] if rows else None
|
|
90
|
+
|
|
91
|
+
def auto_merge(self, repo, pull, method):
|
|
92
|
+
args = ["gh", "pr", "merge", str(pull["number"]), "--repo", repo,
|
|
93
|
+
"--" + method, "--match-head-commit", pull["head"]["sha"]]
|
|
94
|
+
if repo == PUBLIC:
|
|
95
|
+
if pull.get("auto_merge"):
|
|
96
|
+
return
|
|
97
|
+
args.append("--auto")
|
|
98
|
+
elif repo != PRIVATE or pull["head"]["ref"] != SYNC_BRANCH or method != "merge":
|
|
99
|
+
raise PromotionError("Only the reserved private synchronization PR can merge directly.")
|
|
100
|
+
# Private returns have no required CI; GitHub rejects --auto when already clean.
|
|
101
|
+
command(args)
|
|
102
|
+
|
|
103
|
+
def request_sync(self):
|
|
104
|
+
self.api(f"repos/{PUBLIC}/dispatches", "POST", {"event_type": "sync-private"})
|
|
105
|
+
|
|
106
|
+
def resume_queue(self):
|
|
107
|
+
self.api(f"repos/{PUBLIC}/dispatches", "POST", {"event_type": "resume-promotion"})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Git:
|
|
111
|
+
def __init__(self, root="."):
|
|
112
|
+
self.root = root
|
|
113
|
+
|
|
114
|
+
def run(self, *args, check=True):
|
|
115
|
+
return command(["git", *args], cwd=self.root, check=check)
|
|
116
|
+
|
|
117
|
+
def text(self, *args):
|
|
118
|
+
return self.run(*args).stdout.strip()
|
|
119
|
+
|
|
120
|
+
def url(self, repo):
|
|
121
|
+
return f"https://github.com/{repo}.git"
|
|
122
|
+
|
|
123
|
+
def fetch_main(self, repo, name):
|
|
124
|
+
self.run("fetch", "--no-tags", self.url(repo),
|
|
125
|
+
f"+refs/heads/main:refs/remotes/{name}/main")
|
|
126
|
+
return self.text("rev-parse", f"refs/remotes/{name}/main")
|
|
127
|
+
|
|
128
|
+
def ancestor(self, older, newer):
|
|
129
|
+
result = self.run("merge-base", "--is-ancestor", older, newer, check=False)
|
|
130
|
+
if result.returncode not in (0, 1):
|
|
131
|
+
raise PromotionError(result.stderr.strip())
|
|
132
|
+
return result.returncode == 0
|
|
133
|
+
|
|
134
|
+
def tree(self, commit):
|
|
135
|
+
return self.text("rev-parse", commit + "^{tree}")
|
|
136
|
+
|
|
137
|
+
def changed_paths(self, left, right):
|
|
138
|
+
result = self.run("diff", "--name-only", "-z", "--no-renames", left, right, "--")
|
|
139
|
+
return {path for path in result.stdout.split("\0") if path}
|
|
140
|
+
|
|
141
|
+
def parents(self, commit):
|
|
142
|
+
return self.text("show", "-s", "--format=%P", commit).split()
|
|
143
|
+
|
|
144
|
+
def remote_branch(self, repo, branch):
|
|
145
|
+
result = self.run("ls-remote", "--exit-code", "--heads",
|
|
146
|
+
self.url(repo), "refs/heads/" + branch,
|
|
147
|
+
check=False)
|
|
148
|
+
if result.returncode == 2:
|
|
149
|
+
return None
|
|
150
|
+
if result.returncode:
|
|
151
|
+
raise PromotionError(result.stderr.strip())
|
|
152
|
+
self.run("fetch", "--no-tags", self.url(repo),
|
|
153
|
+
"refs/heads/" + branch)
|
|
154
|
+
return self.text("rev-parse", "FETCH_HEAD")
|
|
155
|
+
|
|
156
|
+
def pull_head(self, repo, number):
|
|
157
|
+
# GitHub retains this ref after deleting the merged publication branch.
|
|
158
|
+
self.run("fetch", "--no-tags", self.url(repo), f"refs/pull/{number}/head")
|
|
159
|
+
return self.text("rev-parse", "FETCH_HEAD")
|
|
160
|
+
|
|
161
|
+
def merge_tree(self, left, right, *, base=None, context="Merge"):
|
|
162
|
+
args = ["merge-tree", "--write-tree"]
|
|
163
|
+
if base is not None:
|
|
164
|
+
args.append("--merge-base=" + base)
|
|
165
|
+
result = self.run(*args, left, right, check=False)
|
|
166
|
+
details = "\n".join(part.strip() for part in (result.stdout, result.stderr) if part.strip())
|
|
167
|
+
if result.returncode == 1:
|
|
168
|
+
raise MergeConflict(f"{context} has conflicts; resolve them manually.\n{details}")
|
|
169
|
+
if result.returncode:
|
|
170
|
+
raise PromotionError(f"Git merge-tree failed during {context.lower()} "
|
|
171
|
+
f"(exit {result.returncode}).\n{details}")
|
|
172
|
+
return result.stdout.splitlines()[0]
|
|
173
|
+
|
|
174
|
+
def commit_merge(self, left, right, tree, message):
|
|
175
|
+
return self.text("commit-tree", tree, "-p", left, "-p", right, "-m", message)
|
|
176
|
+
|
|
177
|
+
def checkout(self, branch, base):
|
|
178
|
+
self.run("checkout", "-B", branch, base)
|
|
179
|
+
|
|
180
|
+
def replay(self, source, base, *, mainline=None):
|
|
181
|
+
self.checkout("automation-replay", base)
|
|
182
|
+
args = ["cherry-pick", "-x"]
|
|
183
|
+
if mainline is not None:
|
|
184
|
+
args += ["--mainline", str(mainline)]
|
|
185
|
+
result = self.run(*args, source, check=False)
|
|
186
|
+
if result.returncode:
|
|
187
|
+
self.run("cherry-pick", "--abort", check=False)
|
|
188
|
+
raise PromotionError(
|
|
189
|
+
"The approved change cannot be applied to public main. "
|
|
190
|
+
"Resolve the conflict or an already-applied change before retrying.\n"
|
|
191
|
+
+ result.stderr.strip()
|
|
192
|
+
)
|
|
193
|
+
return self.text("rev-parse", "HEAD")
|
|
194
|
+
|
|
195
|
+
def push(self, repo, branch, commit, previous=None):
|
|
196
|
+
args = ["-c", "push.followTags=false", "push"]
|
|
197
|
+
# A lease also prevents overwriting a branch created after the initial read.
|
|
198
|
+
args += [f"--force-with-lease=refs/heads/{branch}:{previous or ''}"]
|
|
199
|
+
args += [self.url(repo), f"{commit}:refs/heads/{branch}"]
|
|
200
|
+
self.run(*args)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def read_record(pull, marker, required, optional=()):
|
|
204
|
+
matches = marker.findall(pull.get("body") or "")
|
|
205
|
+
if len(matches) != 1:
|
|
206
|
+
raise PromotionError("Missing or ambiguous promotion metadata.")
|
|
207
|
+
try:
|
|
208
|
+
result = json.loads(matches[0])
|
|
209
|
+
except json.JSONDecodeError as error:
|
|
210
|
+
raise PromotionError("Invalid promotion metadata.") from error
|
|
211
|
+
if (not isinstance(result, dict) or not set(required) <= set(result)
|
|
212
|
+
or not set(result) <= set(required) | set(optional)):
|
|
213
|
+
raise PromotionError("Invalid promotion metadata.")
|
|
214
|
+
if type(result["private_pr"]) is not int or result["private_pr"] <= 0:
|
|
215
|
+
raise PromotionError("Invalid private PR number.")
|
|
216
|
+
for key in set(result) - {"private_pr"}:
|
|
217
|
+
if not isinstance(result[key], str) or not re.fullmatch(r"[0-9a-f]{40}", result[key]):
|
|
218
|
+
raise PromotionError("Invalid promotion object ID.")
|
|
219
|
+
return result
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def metadata(pull):
|
|
223
|
+
return read_record(pull, MARKER, {"private_pr", "source", "public_base", "tree"},
|
|
224
|
+
{"promotion_commit"})
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def promotion_body(record):
|
|
228
|
+
return (
|
|
229
|
+
"Publish changes approved in the private development repository.\n\n"
|
|
230
|
+
"The public checks must pass before this PR can merge.\n\n"
|
|
231
|
+
"Resolve conflicts with public main in this branch, preserving the original "
|
|
232
|
+
"promotion commit. Closing this PR without merging blocks later publications.\n\n"
|
|
233
|
+
"<!-- mtlearn-promotion: " + json.dumps(record, sort_keys=True) + " -->\n"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def merged(pull):
|
|
238
|
+
return bool(pull.get("merged_at"))
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def approved_source_base(git, source, number):
|
|
242
|
+
parents = git.parents(source)
|
|
243
|
+
if len(parents) == 1:
|
|
244
|
+
return parents[0]
|
|
245
|
+
recovery = APPROVED_MERGE_RECOVERIES.get(source)
|
|
246
|
+
if len(parents) != 2 or recovery != (number, *parents):
|
|
247
|
+
return None
|
|
248
|
+
expected = git.merge_tree(parents[0], parents[1], context="Approved merge recovery")
|
|
249
|
+
return parents[0] if expected == git.tree(source) else None
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def promotion_origin(git, head, source, number, public_tip, record=None):
|
|
253
|
+
"""Validate or recover the original cherry-pick, including interrupted runs."""
|
|
254
|
+
if record and (record["source"] != source or record["private_pr"] != number):
|
|
255
|
+
raise PromotionError("The public PR refers to another private change.")
|
|
256
|
+
source_base = approved_source_base(git, source, number)
|
|
257
|
+
if source_base is None:
|
|
258
|
+
raise PromotionError("The publication source is not an approved private change.")
|
|
259
|
+
public_history = set(git.text("rev-list", "--first-parent", public_tip).splitlines())
|
|
260
|
+
candidates = ([record["promotion_commit"]] if record and "promotion_commit" in record
|
|
261
|
+
else git.text("rev-list", head, "--not", public_tip).splitlines())
|
|
262
|
+
origins = []
|
|
263
|
+
for candidate in candidates:
|
|
264
|
+
parents = git.parents(candidate)
|
|
265
|
+
trailer = f"(cherry picked from commit {source})"
|
|
266
|
+
if (len(parents) != 1 or parents[0] not in public_history
|
|
267
|
+
or not git.ancestor(candidate, head)
|
|
268
|
+
or trailer not in git.text("show", "-s", "--format=%B", candidate).splitlines()):
|
|
269
|
+
continue
|
|
270
|
+
if record and (parents[0] != record["public_base"]
|
|
271
|
+
or git.tree(candidate) != record["tree"]):
|
|
272
|
+
continue
|
|
273
|
+
expected = git.merge_tree(parents[0], source, base=source_base,
|
|
274
|
+
context="Promotion origin reconstruction")
|
|
275
|
+
if git.tree(candidate) == expected:
|
|
276
|
+
origins.append(dict(private_pr=number, source=source, public_base=parents[0],
|
|
277
|
+
tree=expected, promotion_commit=candidate))
|
|
278
|
+
if len(origins) != 1:
|
|
279
|
+
raise PromotionError("The publication history has no unique valid promotion origin; "
|
|
280
|
+
"preserve and review the branch.")
|
|
281
|
+
return origins[0]
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def already_published(git, source_pr, public_tip):
|
|
285
|
+
"""A durable receipt is accepted only with its original content proof."""
|
|
286
|
+
if "<!-- mtlearn-already-published:" not in (source_pr.get("body") or ""):
|
|
287
|
+
return False
|
|
288
|
+
record = read_record(source_pr, PUBLISHED_MARKER,
|
|
289
|
+
{"private_pr", "source", "public_commit", "tree"})
|
|
290
|
+
source = source_pr["merge_commit_sha"]
|
|
291
|
+
public = record["public_commit"]
|
|
292
|
+
source_base = approved_source_base(git, source, source_pr["number"])
|
|
293
|
+
if (record["private_pr"] != source_pr["number"] or record["source"] != source
|
|
294
|
+
or public not in git.text("rev-list", "--first-parent", public_tip).splitlines()
|
|
295
|
+
or source_base is None
|
|
296
|
+
or record["tree"] != git.tree(public)
|
|
297
|
+
or git.merge_tree(public, source, base=source_base,
|
|
298
|
+
context="Already-published verification") != record["tree"]):
|
|
299
|
+
raise PromotionError("Invalid already-published record on the private PR.")
|
|
300
|
+
return True
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def record_already_published(git, github, source_pr, public_tip):
|
|
304
|
+
number, source = source_pr["number"], source_pr["merge_commit_sha"]
|
|
305
|
+
current = github.pull(PRIVATE, number)
|
|
306
|
+
if not merged(current) or current["merge_commit_sha"] != source:
|
|
307
|
+
raise PromotionError("The private PR changed while recording publication; retry.")
|
|
308
|
+
if already_published(git, current, public_tip):
|
|
309
|
+
return
|
|
310
|
+
record = dict(private_pr=number, source=source, public_commit=public_tip,
|
|
311
|
+
tree=git.tree(public_tip))
|
|
312
|
+
body = (current.get("body") or "").rstrip()
|
|
313
|
+
body += "\n\n<!-- mtlearn-already-published: " + json.dumps(record, sort_keys=True) + " -->\n"
|
|
314
|
+
github.api(f"repos/{PRIVATE}/pulls/{number}", "PATCH", {"body": body})
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def publication_base(git, source, private_tip, public_history):
|
|
318
|
+
"""Find an integrated base on which the original change can still be reviewed.
|
|
319
|
+
|
|
320
|
+
The caller limits history to bases containing every earlier publication.
|
|
321
|
+
A later manual synchronization may have resolved away the original change;
|
|
322
|
+
that is not proof that the change was published and must not skip its review.
|
|
323
|
+
"""
|
|
324
|
+
for base in public_history:
|
|
325
|
+
if not git.ancestor(base, private_tip):
|
|
326
|
+
continue
|
|
327
|
+
try:
|
|
328
|
+
tree = git.merge_tree(base, source, base=git.parents(source)[0],
|
|
329
|
+
context="Approved change publication")
|
|
330
|
+
except MergeConflict:
|
|
331
|
+
continue
|
|
332
|
+
if tree != git.tree(base):
|
|
333
|
+
return base
|
|
334
|
+
raise PromotionError("The approved change has no usable integrated public base "
|
|
335
|
+
"containing all earlier publications; review its history manually.")
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def promote(git, github, private_tip, public_tip):
|
|
339
|
+
pulls = github.pages(f"repos/{PRIVATE}/pulls", state="closed", base="main")
|
|
340
|
+
pulls = [p for p in pulls if merged(p) and p["head"]["ref"] != SYNC_BRANCH]
|
|
341
|
+
order = git.text("rev-list", "--first-parent", "--reverse", private_tip).splitlines()
|
|
342
|
+
positions = {sha: i for i, sha in enumerate(order)}
|
|
343
|
+
if any(p["merge_commit_sha"] not in positions for p in pulls):
|
|
344
|
+
raise PromotionError("A merged private PR is outside the main history.")
|
|
345
|
+
pulls.sort(key=lambda p: positions[p["merge_commit_sha"]])
|
|
346
|
+
public_history = git.text("rev-list", "--first-parent", public_tip).splitlines()
|
|
347
|
+
public_positions = {sha: i for i, sha in enumerate(public_history)}
|
|
348
|
+
earlier_publications = set()
|
|
349
|
+
|
|
350
|
+
for source_pr in pulls:
|
|
351
|
+
number = source_pr["number"]
|
|
352
|
+
source = source_pr["merge_commit_sha"]
|
|
353
|
+
if already_published(git, source_pr, public_tip):
|
|
354
|
+
earlier_publications.add(read_record(
|
|
355
|
+
source_pr, PUBLISHED_MARKER,
|
|
356
|
+
{"private_pr", "source", "public_commit", "tree"})["public_commit"])
|
|
357
|
+
continue
|
|
358
|
+
branch = PROMOTION_PREFIX + str(number)
|
|
359
|
+
public_pr = github.find_pull(PUBLIC, branch)
|
|
360
|
+
old_record = None
|
|
361
|
+
if public_pr:
|
|
362
|
+
old_record = metadata(public_pr)
|
|
363
|
+
if old_record["source"] != source or old_record["private_pr"] != number:
|
|
364
|
+
raise PromotionError("The public PR refers to another private change.")
|
|
365
|
+
if merged(public_pr):
|
|
366
|
+
published = public_pr["merge_commit_sha"]
|
|
367
|
+
if published not in public_positions:
|
|
368
|
+
raise PromotionError("An earlier publication is outside public main history.")
|
|
369
|
+
earlier_publications.add(published)
|
|
370
|
+
continue
|
|
371
|
+
if public_pr["state"] != "open":
|
|
372
|
+
raise PromotionError(f"Public PR #{public_pr['number']} was closed without merging. "
|
|
373
|
+
"Reopen it to continue; publication cancellation is not supported.")
|
|
374
|
+
if approved_source_base(git, source, number) is None:
|
|
375
|
+
raise PromotionError(f"Private PR #{number} must use squash merge.")
|
|
376
|
+
if any(not git.ancestor(commit, private_tip) for commit in earlier_publications):
|
|
377
|
+
github.request_sync()
|
|
378
|
+
return "Waiting for earlier public promotions to be reconciled into private main."
|
|
379
|
+
previous = git.remote_branch(PUBLIC, branch)
|
|
380
|
+
if public_pr and previous != public_pr["head"]["sha"]:
|
|
381
|
+
raise PromotionError("The publication branch changed or disappeared; retry with a fresh PR head.")
|
|
382
|
+
if previous:
|
|
383
|
+
record = promotion_origin(git, previous, source, number, public_tip, old_record)
|
|
384
|
+
candidate = previous
|
|
385
|
+
else:
|
|
386
|
+
try:
|
|
387
|
+
expected = git.merge_tree(public_tip, source, base=git.parents(source)[0],
|
|
388
|
+
context="Already-published comparison")
|
|
389
|
+
except MergeConflict:
|
|
390
|
+
# A conflict is not an already-published proof. Open a reviewable
|
|
391
|
+
# promotion on a compatible historical base instead.
|
|
392
|
+
expected = None
|
|
393
|
+
if expected == git.tree(public_tip):
|
|
394
|
+
record_already_published(git, github, source_pr, public_tip)
|
|
395
|
+
earlier_publications.add(public_tip)
|
|
396
|
+
continue
|
|
397
|
+
latest_publication_index = min((public_positions[c] for c in earlier_publications),
|
|
398
|
+
default=len(public_history) - 1)
|
|
399
|
+
base = publication_base(git, source, private_tip,
|
|
400
|
+
public_history[:latest_publication_index + 1])
|
|
401
|
+
if len(git.parents(source)) == 1:
|
|
402
|
+
candidate = git.replay(source, base)
|
|
403
|
+
else:
|
|
404
|
+
candidate = git.replay(source, base, mainline=1)
|
|
405
|
+
record = dict(private_pr=number, source=source, public_base=base,
|
|
406
|
+
tree=git.tree(candidate), promotion_commit=candidate)
|
|
407
|
+
if candidate != previous:
|
|
408
|
+
git.push(PUBLIC, branch, candidate, previous)
|
|
409
|
+
if public_pr:
|
|
410
|
+
if old_record != record:
|
|
411
|
+
body = MARKER.sub(lambda _: MARKER.search(promotion_body(record))[0],
|
|
412
|
+
public_pr["body"])
|
|
413
|
+
github.api(f"repos/{PUBLIC}/pulls/{public_pr['number']}", "PATCH", {"body": body})
|
|
414
|
+
public_pr = github.pull(PUBLIC, public_pr["number"])
|
|
415
|
+
else:
|
|
416
|
+
public_pr = github.api(f"repos/{PUBLIC}/pulls", "POST", {
|
|
417
|
+
"head": branch, "base": "main", "title": source_pr["title"],
|
|
418
|
+
"body": promotion_body(record),
|
|
419
|
+
})
|
|
420
|
+
# Keep the original branch and PR available even when updating conflicts.
|
|
421
|
+
# Waiting for all public changes to enter private first would deadlock.
|
|
422
|
+
if not git.ancestor(public_tip, candidate):
|
|
423
|
+
try:
|
|
424
|
+
tree = git.merge_tree(candidate, public_tip, context="Publication branch update")
|
|
425
|
+
except MergeConflict as error:
|
|
426
|
+
raise MergeConflict(
|
|
427
|
+
f"Public PR #{public_pr['number']} needs conflict resolution: "
|
|
428
|
+
f"{public_pr['html_url']}\n{error}"
|
|
429
|
+
) from error
|
|
430
|
+
updated = git.commit_merge(candidate, public_tip, tree, "Merge public main into promotion")
|
|
431
|
+
if not git.ancestor(candidate, updated):
|
|
432
|
+
raise PromotionError("A publication update must preserve the existing branch history.")
|
|
433
|
+
git.push(PUBLIC, branch, updated, candidate)
|
|
434
|
+
candidate = updated
|
|
435
|
+
public_pr = github.pull(PUBLIC, public_pr["number"])
|
|
436
|
+
if git.tree(candidate) == git.tree(public_tip):
|
|
437
|
+
raise PromotionError(
|
|
438
|
+
f"Public PR #{public_pr['number']} has no remaining content changes: "
|
|
439
|
+
f"{public_pr['html_url']}\nEmpty promotion completion requires manual review; "
|
|
440
|
+
"it is not automatically marked as published or cancelled."
|
|
441
|
+
)
|
|
442
|
+
github.auto_merge(PUBLIC, public_pr, "squash")
|
|
443
|
+
return f"Publication pending: {public_pr['html_url']}"
|
|
444
|
+
return "All merged private PRs have been published."
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def verify_published_change(git, github, commit, private_tip, pull, integrated_public):
|
|
448
|
+
"""Return the expected tree at the last integrated public main commit.
|
|
449
|
+
|
|
450
|
+
The original marker remains immutable. The integration base can be newer,
|
|
451
|
+
or precede the squash parent when the squash resolves a blocked public change.
|
|
452
|
+
"""
|
|
453
|
+
record = metadata(pull)
|
|
454
|
+
source_pr = github.pull(PRIVATE, record["private_pr"])
|
|
455
|
+
source = record["source"]
|
|
456
|
+
source_base = approved_source_base(git, source, record["private_pr"])
|
|
457
|
+
if (not merged(source_pr) or source_pr["base"]["ref"] != "main"
|
|
458
|
+
or source_pr["head"]["ref"] == SYNC_BRANCH
|
|
459
|
+
or source_pr["merge_commit_sha"] != source
|
|
460
|
+
or pull["head"]["ref"] != PROMOTION_PREFIX + str(record["private_pr"])
|
|
461
|
+
or len(git.parents(commit)) != 1
|
|
462
|
+
or source_base is None
|
|
463
|
+
or not git.ancestor(source, private_tip)
|
|
464
|
+
or not git.ancestor(record["public_base"], integrated_public)
|
|
465
|
+
or not git.ancestor(integrated_public, private_tip)
|
|
466
|
+
or not git.ancestor(integrated_public, git.parents(commit)[0])):
|
|
467
|
+
raise PromotionError("The public squash does not match approved private history.")
|
|
468
|
+
head = git.pull_head(PUBLIC, pull["number"])
|
|
469
|
+
if head != pull["head"]["sha"]:
|
|
470
|
+
raise PromotionError("The retained public PR head does not match the merged PR.")
|
|
471
|
+
promotion_origin(git, head, source, record["private_pr"], git.parents(commit)[0], record)
|
|
472
|
+
published = git.merge_tree(git.parents(commit)[0], head, context="Public squash verification")
|
|
473
|
+
if published != git.tree(commit):
|
|
474
|
+
raise PromotionError("The public squash content does not match the merged PR head.")
|
|
475
|
+
try:
|
|
476
|
+
return git.merge_tree(integrated_public, source, base=source_base,
|
|
477
|
+
context="Expected promotion reconstruction")
|
|
478
|
+
except MergeConflict as error:
|
|
479
|
+
# Manual private synchronization can resolve the same conflict later
|
|
480
|
+
# resolved in the public PR. The old base is safe only on paths where
|
|
481
|
+
# these already-integrated public changes now agree on both sides.
|
|
482
|
+
integrated_paths = git.changed_paths(record["public_base"], integrated_public)
|
|
483
|
+
differing_paths = integrated_paths & git.changed_paths(private_tip, commit)
|
|
484
|
+
if differing_paths:
|
|
485
|
+
paths = ", ".join(repr(path) for path in sorted(differing_paths))
|
|
486
|
+
raise MergeConflict(
|
|
487
|
+
"Expected promotion reconstruction has conflicts and the prior public "
|
|
488
|
+
f"changes still differ on: {paths}. Resolve synchronization manually."
|
|
489
|
+
) from error
|
|
490
|
+
return record["tree"]
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def synchronize(git, github, private_tip, public_tip):
|
|
494
|
+
if git.ancestor(public_tip, private_tip):
|
|
495
|
+
github.resume_queue()
|
|
496
|
+
return "Private main already includes public main."
|
|
497
|
+
git.checkout("automation-sync", private_tip)
|
|
498
|
+
commits = git.text("rev-list", "--first-parent", "--reverse",
|
|
499
|
+
private_tip + ".." + public_tip).splitlines()
|
|
500
|
+
history = git.text("rev-list", "--first-parent", public_tip).splitlines()
|
|
501
|
+
integrated_public = next((c for c in history if git.ancestor(c, private_tip)), None)
|
|
502
|
+
if integrated_public is None:
|
|
503
|
+
raise PromotionError("Private main has no integrated public main history.")
|
|
504
|
+
publications = {}
|
|
505
|
+
for commit in commits:
|
|
506
|
+
associated = github.pages(f"repos/{PUBLIC}/commits/{commit}/pulls")
|
|
507
|
+
promotions = [p for p in associated if merged(p)
|
|
508
|
+
and p["merge_commit_sha"] == commit and p["base"]["ref"] == "main"
|
|
509
|
+
and p["head"]["ref"].startswith(PROMOTION_PREFIX)]
|
|
510
|
+
if len(promotions) > 1:
|
|
511
|
+
raise PromotionError("Ambiguous public promotion history.")
|
|
512
|
+
if promotions:
|
|
513
|
+
publications[commit] = promotions[0]
|
|
514
|
+
index = 0
|
|
515
|
+
while index < len(commits):
|
|
516
|
+
# Integrate through the next verified promotion as one unit. Its squash
|
|
517
|
+
# includes preceding public commits and any reviewed conflict resolution.
|
|
518
|
+
# Splitting that unit can conflict before reaching the resolution, or make
|
|
519
|
+
# the original feature impossible to reconstruct on an intermediate base.
|
|
520
|
+
following = next((i for i in range(index, len(commits))
|
|
521
|
+
if commits[i] in publications), None)
|
|
522
|
+
if following is not None:
|
|
523
|
+
index = following
|
|
524
|
+
commit = commits[index]
|
|
525
|
+
current = git.text("rev-parse", "HEAD")
|
|
526
|
+
equivalent = False
|
|
527
|
+
if commit in publications:
|
|
528
|
+
expected = verify_published_change(git, github, commit, current,
|
|
529
|
+
publications[commit], integrated_public)
|
|
530
|
+
equivalent = expected == git.tree(commit)
|
|
531
|
+
if not equivalent:
|
|
532
|
+
tree = git.merge_tree(current, commit, base=expected,
|
|
533
|
+
context="Public corrections and private work")
|
|
534
|
+
else:
|
|
535
|
+
tree = git.merge_tree(current, commit, context="Public synchronization")
|
|
536
|
+
message = "Sync public main: " + commit
|
|
537
|
+
if equivalent:
|
|
538
|
+
git.run("merge", "--strategy=ours", "--no-ff", "-m", message, commit)
|
|
539
|
+
else:
|
|
540
|
+
candidate = git.commit_merge(current, commit, tree, message)
|
|
541
|
+
git.checkout("automation-sync", candidate)
|
|
542
|
+
integrated_public = commit
|
|
543
|
+
index += 1
|
|
544
|
+
candidate = git.text("rev-parse", "HEAD")
|
|
545
|
+
previous = git.remote_branch(PRIVATE, SYNC_BRANCH)
|
|
546
|
+
if (previous and git.ancestor(private_tip, previous) and git.ancestor(public_tip, previous)
|
|
547
|
+
and git.tree(previous) == git.tree(candidate)):
|
|
548
|
+
candidate = previous
|
|
549
|
+
if candidate != previous:
|
|
550
|
+
git.push(PRIVATE, SYNC_BRANCH, candidate, previous)
|
|
551
|
+
sync_pr = github.find_pull(PRIVATE, SYNC_BRANCH, state="open")
|
|
552
|
+
if not sync_pr:
|
|
553
|
+
sync_pr = github.api(f"repos/{PRIVATE}/pulls", "POST", {
|
|
554
|
+
"head": SYNC_BRANCH, "base": "main", "title": "chore: sync public main",
|
|
555
|
+
"body": "Reconcile public main into private main.\n\n"
|
|
556
|
+
"Use a merge commit to retain the public ancestry. "
|
|
557
|
+
"This reserved branch is excluded from publication.\n",
|
|
558
|
+
})
|
|
559
|
+
else:
|
|
560
|
+
sync_pr = github.pull(PRIVATE, sync_pr["number"])
|
|
561
|
+
github.auto_merge(PRIVATE, sync_pr, "merge")
|
|
562
|
+
# The reserved private PR merges directly, without --auto. Dispatch only
|
|
563
|
+
# after that operation succeeds; private Actions cannot wake the public queue.
|
|
564
|
+
github.resume_queue()
|
|
565
|
+
return f"Synchronization completed; publication queue resumed: {sync_pr['html_url']}"
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def write_summary(message):
|
|
569
|
+
if os.environ.get("GITHUB_STEP_SUMMARY"):
|
|
570
|
+
with Path(os.environ["GITHUB_STEP_SUMMARY"]).open("a", encoding="utf-8") as stream:
|
|
571
|
+
stream.write(message + "\n")
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def main():
|
|
575
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
576
|
+
parser.add_argument("mode", choices=("promote", "sync"))
|
|
577
|
+
args = parser.parse_args()
|
|
578
|
+
if os.environ.get("GITHUB_REPOSITORY") != PUBLIC:
|
|
579
|
+
raise PromotionError("Repository automation must run in the public repository.")
|
|
580
|
+
git, github = Git(), GitHub()
|
|
581
|
+
if git.text("status", "--porcelain", "--untracked-files=no"):
|
|
582
|
+
raise PromotionError("The automation checkout must be clean.")
|
|
583
|
+
private_tip = git.fetch_main(PRIVATE, "private")
|
|
584
|
+
public_tip = git.fetch_main(PUBLIC, "public")
|
|
585
|
+
try:
|
|
586
|
+
message = (promote if args.mode == "promote" else synchronize)(
|
|
587
|
+
git, github, private_tip, public_tip)
|
|
588
|
+
except PromotionError as error:
|
|
589
|
+
write_summary(str(error))
|
|
590
|
+
raise
|
|
591
|
+
print(message)
|
|
592
|
+
write_summary(message)
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
if __name__ == "__main__":
|
|
596
|
+
try:
|
|
597
|
+
main()
|
|
598
|
+
except PromotionError as error:
|
|
599
|
+
raise SystemExit(str(error))
|