Changelog
All notable changes to omeco are documented here. This file is the single authoritative changelog; the mdBook appendix page includes it verbatim. omeco adheres to Semantic Versioning.
Unreleased
Breaking: treesa::anneal_surgery_rounds is removed; use
anneal_refine_rounds(seed, code, sizes, config, rounds, &RoundsOptions::default())
for identical behavior.
- Added
treesa::RoundsOptionsandanneal_refine_rounds, including an exactly work-matched cold-only control (surgery: false) and an incumbent ratchet that makes the loop monotone in its round count. - Added opt-in
treesa::RoundsSchedule(RoundsOptions::schedule). The defaultColdvariant is the historical span-gated fine-tuning pass;BandReheatThenFront { switch_fraction }reheats the waist cost band and then descends a continuous log-span freeze-out front, with the switch clamped between two band epochs and a fixed fraction of the planned sweeps. - Waist-surgery side rebuilds now initialize from the restricted incumbent
topology (
warm-restricted), which the surgery ablation campaign showed strictly better than the historical greedy seed;SurgeryScope::Localis opt-in and rebuilds only a bounded ancestor around a deep waist. Defaults are warm-restricted +Root. RoundsReport::fine_tune_sweeps_totalexposes deterministic fine-tuning work, andoptimize_treesa_seededsupports matched optimizer repetitions. The resumablesurgery_ablationexample reports quality against both node visits and wall time with a Markdown summarizer; campaign artifacts are gitignored.- Moved the companion paper’s benchmark manifests, canonical instances,
provenance gate, semantic verifiers, runners, generated artifacts, and CI
checks to the
contraction-order-frontiersrepository. OMECO retains its reusable waist-surgery,RoundTrace, and opt-in waist-trace APIs and tests.
0.2.7 — 2026-07-29
Default behavior change: TreeSA now runs the structural
simplification front-end by default (preprocess: true) — output trees
may differ from 0.2.6 (same contraction result, typically equal or better
cost). Restore the old behavior with preprocess: false.
- New
TreeSA.surgery_iters(default0/off): number of interleaved anneal–surgery rounds (Algorithm 1 of the companion paper) run on the reduced-network tree. Each round is one waist-surgery iteration followed by a cold span-gated fine-tuning pass with an incumbent ratchet. After splice-back, the candidate is guarded against the rounds-off baseline; the standalone reduced-network loop is monotone in its round count. Fully deterministic — rounds are counted, never timed — and auto-skipped forDecompositionType::Pathconfigs, which the loop cannot preserve.TreeSAhas no wall-clock knob; the low-levelwaist_surgery::refine/refine_cappedAPIs are unchanged and keep theirDurationbudget for power users. - New
TreeSA.surgery_probability(default0.0/off): mixes waist surgery directly into TreeSA. At each sweep, the configured probability replaces the local sweep with one waist-guided leaf prune-and-regraft move, accepted at the current inverse temperature. The rule never restarts cooling, invokes a timer, or launches a nested anneal; Rust and Python expose the same setting. - New
treesa::anneal_surgery_rounds+RoundsReport: the same interleaved loop as a standalone function, with separate per-round surgery candidate, raw fine-tuning endpoint, and retained-incumbent traces. - Python:
TreeSA(preprocess=..., surgery_iters=..., surgery_probability=...),simplify_then_optimize,waist_refine,SimplifyReport,WaistReport. - Fixed Python
TreeSA()to delegate its default β schedule to RustTreeSA::default()(0..300); the previous duplicate used1..=300and could shift benchmark quality by several bits. - Committed paper-benchmark artifact under
benchmarks/paper/(manifest, instances, deterministic runner, checker), plus a CI job that re-derives the smallciset on every PR and fails on a single changed field. A dedicatedfigure2bset checks the paper mechanism and renders a static SVG. - New opt-in waist-call trace:
RoundTrace.waist(waist_surgery::WaistCallTrace) records each round’s exactly rescored incumbent and best FM waist cuts. Off in ordinary runs and behavior-neutral — no change to the proposal rule, RNG, acceptance, orWaistReport. Awaist_tracebenchmark set (five deterministic relabelings each ofsurfacecode_d21andksg, 128 rounds each) regenerates the paper’s dense mechanism evidence viamake paper-waist-trace. RoundTracegainsscore_before/score_retained: the configured multi-objective TreeSA score of the retained incumbent, which is the quantity the rounds ratchet actually guarantees is monotone (tc_retainedcan rise when another weighted term improves). Paper-benchmark artifacts emit the fields when the manifest setstrace_scores: true(implied bytrace_cuts), and thefigure2b/waist_traceverifiers now check the configured-score ratchet instead of rawtc.Labelnow requiresOrd(all built-in label types already qualify).- The Julia behavioral-alignment rule is retired; JSON interop is unchanged.
0.2.5 — 2026-06-30
Added
- Comprehensive mdBook documentation following tropical-gemm standard
- Pretty printing for Python
NestedEinsumwith ASCII tree visualization - PyTorch integration guide and examples
- GPU optimization guide with
rw_weightconfiguration - Slicing strategy guide for memory-constrained environments
- Troubleshooting guide with common issues and solutions
- API reference for Python and Rust APIs
- Performance benchmarks comparing Rust vs Julia
- Algorithm comparison guide (Greedy vs TreeSA)
Changed
- Migrated documentation from scattered markdown files to structured mdBook
- Improved Python bindings with better
__str__and__repr__methods
Deprecated
- Legacy
docs/score_function_guide.md(migrated to mdBook)
0.2.1 — 2024-01
Fixed
- Issue #6: Hyperedge index preservation in contraction operations (PR #7)
- Fixed
contract_tree!macro to correctly preserve tensor indices during contraction - Added regression tests to verify hyperedge handling
- Ensures contraction order matches input tensor order specified in
ixs
- Fixed
Added
- Test suite for hyperedge index preservation
- CI improvements for better test coverage
0.2.0 — 2024-01
Added
- TreeSA (Tree-based Simulated Annealing) optimizer
TreeSA.fast()preset for quick high-quality optimization- Slicing support with
TreeSASlicerfor memory reduction ScoreFunctionfor configurable optimization objectivescontraction_complexityandsliced_complexityfunctions- Python bindings via PyO3
optimize_codegeneric function accepting optimizer instances- Read-write complexity (rwc) metric for GPU optimization
Changed
- Improved API ergonomics with preset methods
- Better default parameters for optimizers
Performance
- 1.4-1.5x faster than Julia OMEinsumContractionOrders.jl on benchmarks
- Efficient TreeSA implementation with better exploration
0.1.0 — 2023
Added
- Initial release
- GreedyMethod optimizer
- Basic contraction order optimization
- Support for tensor networks with arbitrary indices
- Complexity calculation (time and space)
- Rust core library
- Basic documentation
Features
- Greedy algorithm with configurable parameters
- Stochastic variants for improved solutions
- Efficient index handling with generic types
- HashMap-based dimension tracking
Migration Guides
Migrating from 0.1.x to 0.2.x
Major Changes:
-
New
optimize_codefunction: Unified API for all optimizers# Old (0.1.x) tree = optimize_greedy(ixs, out, sizes) tree = optimize_treesa(ixs, out, sizes) # New (0.2.x) - unified interface from omeco import optimize_code, GreedyMethod, TreeSA tree = optimize_code(ixs, out, sizes) # Uses GreedyMethod by default tree = optimize_code(ixs, out, sizes, TreeSA.fast()) -
ScoreFunction configuration:
# New in 0.2.x from omeco import ScoreFunction, TreeSA score = ScoreFunction(tc_weight=1.0, sc_weight=1.0, rw_weight=10.0, sc_target=30.0) tree = optimize_code(ixs, out, sizes, TreeSA(score=score)) -
Slicing support:
# New in 0.2.x from omeco import slice_code, TreeSASlicer sliced = slice_code(tree, ixs, sizes, TreeSASlicer.fast())
Breaking Changes:
- Removed
optimize_greedy()andoptimize_treesa()from Python exports - Use
optimize_code(...)instead withGreedyMethod()orTreeSA()optimizers - Rust API unchanged
Migrating from Julia OMEinsumContractionOrders.jl
Index Differences:
- Julia: 1-based indexing
- Rust/Python: 0-based indexing (or use arbitrary hashable types)
# Julia
ixs = [[1, 2], [2, 3], [3, 1]]
sizes = Dict(1 => 10, 2 => 20, 3 => 10)
# Python (0-based)
ixs = [[0, 1], [1, 2], [2, 0]]
sizes = {0: 10, 1: 20, 2: 10}
Function Names:
| Julia | omeco (Python/Rust) |
|---|---|
optimize_greedy | optimize_code(..., GreedyMethod()) |
optimize_treesa | optimize_code(..., TreeSA.fast()) |
contraction_complexity | contraction_complexity |
slicing | slice_code |
API Compatibility: Most functions have similar signatures and behavior.