These 70 commits are when the Protocol Buffers files have changed:
| Commit: | a583f8a | |
|---|---|---|
| Author: | Toshiki Teramura | |
Keep violation semantics independent of protobuf schema changes
The documentation is generated from this commit.
| Commit: | e091832 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Derive constraint feasibility from scalar violations
| Commit: | 00d983e | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Reintroduce composed Function operations with sparse evaluation (#1178) ## Summary - Reintroduce the composed `Function` operations originally added in #1158 on top of the current `main` branch. - Keep compact polynomial evaluation proportional to the function's sparse support instead of the size of the caller's complete state. - Preserve expression-wide missing-state reporting, finite-result checks, sample grouping, and typed `FunctionEvaluationError` propagation through acyclic assignments. - Add an isolated unrelated-state scaling guardrail and keep heavyweight MIPLIB diagnostic benchmarks out of the regular Python test matrix. ## Background #1158 was reverted after `Function::evaluate` caused a severe evaluation and workflow-time regression. The regression came from materializing every state ID into a `BTreeSet` for every objective and constraint evaluation. Sparse instances therefore changed from work proportional to their nonzero structure to repeated whole-state scans. This pull request reapplies the reverted feature after #1176 and moves validation back to the domain boundary that owns it: compact polynomial evaluators inspect their own terms, while composed expressions validate only their own required IDs before executing the RPN program. ## Benchmark policy The Rust guardrail now isolates the specific regression by holding the compact function support fixed while increasing unrelated state entries geometrically. The existing instance scalar and single-sample benchmarks continue to guard sparse instance scaling. Python's normal test task runs only persistent benchmark guardrails; the `supportcase10` workloads remain available in the explicit full diagnostic suite.
The documentation is generated from this commit.
| Commit: | 84c2609 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Revert "Revert "Add composed operations to Function (#1158)"" This reverts commit 8bef30e83fb0498a2e639f24feee43a40b7f2920.
The documentation is generated from this commit.
| Commit: | 8bef30e | |
|---|---|---|
| Author: | Toshiki Teramura | |
Revert "Add composed operations to Function (#1158)" This reverts commit bbfcf7cf328adae8a1b08830e544c883e98274fa.
| Commit: | bbfcf7c | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add composed operations to Function (#1158) ## Summary - Extend `Function` beyond compact polynomials with absolute value, signum, pointwise minimum and maximum, division, and signed 32-bit integer powers. - Represent every non-polynomial composition as one validated flat reverse Polish notation (RPN) program in both the Rust SDK and protobuf. Compact polynomial values are atoms; unary operations consume one value and associative or non-associative binary operations consume two. - Preserve explicit grouping, operand order, partial-function behavior, and floating-point error order without recursive expression nodes or common-subexpression sharing. - Evaluate, partially evaluate, substitute, format, compare, bound, serialize, bridge, and reduce binary powers by iterating over the same instruction stream. - Expose the operations through Rust and Python, including `abs(f)`, `signum()`, `minimum()`, `maximum()`, division, `f.powi(n)`, and integer-only `f ** n`. - Make polynomial capability explicit across `Function`, `InstanceFacts`, `InstanceClass`, MPS, and the bundled adapters instead of assigning composed expressions a misleading degree. - Add `FunctionParameters` so property-test callers can choose the full expression language or a polynomial-only domain, and make exact-nonzero coefficient generators include tiny normal and subnormal values. - Thread caller-selected `ATol` through interval bounds and transformations that consume them, including Indicator Big-M lowering and integer-slack conversion. - Update the generated Python stubs and API metadata, PyO3 bridge fixtures, migration guides, user guides, adapter documentation, and Rust/Python release notes. ## Representation and validation `ommx.v1.Function` gains an additive flat-expression payload that is reused by v2 roots. The Rust `Function::Expression` representation uses the same RPN shape, so the former protobuf/tree recursion-depth boundary is removed on both sides of the wire. The expression parser validates stack underflow, the final stack height, unknown operators, missing or unexpected operator parameters, and malformed `Powi` exponents. N-ary input is deliberately represented as successive binary applications, retaining grouping such as `(a + b) + c` versus `a + (b + c)`. Older protobuf readers reject the new `Function` oneof variant rather than silently interpreting a weaker model. Deep expressions are encoded and reconstructed iteratively across the PyO3 bridge. Reconstruction endpoints remain binding-private, while canonical `ommx` Python objects cross extension-module boundaries. ## Evaluation semantics - At point evaluation, `abs(value) <= atol` is classified as zero, including the boundary. `signum` returns zero in that interval; division by such a denominator and raising such a value to a negative integer power return typed evaluation errors. - Zero-sensitive nodes are not folded during construction or substitution. Partial evaluation specializes assigned operands but retains these nodes so a later `evaluate(..., atol)` call owns the tolerance-dependent decision. - Polynomial normalization removes only an exact floating-point zero produced by arithmetic. It never treats a merely small finite coefficient as zero; approximate cleanup remains a separate explicit operation. - Integer powers evaluate their operand before applying the exponent, including exponent zero. `0^0` is one. Function-valued, reverse, and floating-point exponentiation are intentionally not supported. - Apart from tolerance-independent identities and finite constant folding, `powi` remains composed and therefore has no compact polynomial degree. - Division by a constant or `Coefficient` also remains composed. Existing compact normalization paths are retained for polynomial addition, subtraction, multiplication, and negation. `Function::evaluate_bound` now receives the same `ATol` as point evaluation. Its zero-domain analysis follows `signum`, division, and negative-`powi` semantics through nested expressions. Interval endpoints are rounded outward, and an operation that overflows from finite endpoints returns `FunctionEvaluationError::NonFiniteResult`; unbounded interval sentinels and unattained reciprocal limits remain valid bounds. Indicator Big-M conversion and special-constraint lowering receive that tolerance explicitly in Rust and through an optional keyword in Python. The tolerance applies to the Indicator function body; the Big-M identities still assume an exactly discrete 0/1 indicator value and do not snap approximate solver output. Integer-slack conversion classifies infeasible and trivial inequalities from the original, unscaled bound using the same strict `f(x) < atol` rule as constraint evaluation. Exact coefficient normalization therefore cannot change the feasibility threshold. The fallback inequality-preserving slack path uses the same caller tolerance and validates the planned coefficient before mutating the instance. ## Polynomial capability model Composed functions report `None` from degree and term-count inspection, and coefficient-map access raises the documented non-polynomial error. `InstanceFacts` records these functions as `NonPolynomial`; `InstanceClassClause` uses `RequirePolynomial` with an optional degree bound rather than treating “any degree” as including non-polynomials. MPS preflight owns an MPS-specific `InstanceClass` and performs validation through the shared membership mechanism. All bundled solver adapters likewise declare polynomial input classes and reject composed objectives or constraints at their capability boundary. ## Python example ```python from ommx import DecisionVariable, Function x = Function(DecisionVariable.continuous(1)) y = Function(DecisionVariable.continuous(2)) z = Function(DecisionVariable.continuous(3)) f = abs(x - 2).maximum(y) / (z + 1) g = f**2 h = f.powi(-2) ``` The Python v2-to-v3 migration guide documents optional degree and term-count results, non-polynomial coefficient access, and explicit multiplication for callers that require a compact polynomial power.
The documentation is generated from this commit.
| Commit: | bedcd6f | |
|---|---|---|
| Author: | Toshiki Teramura | |
Merge remote-tracking branch 'origin/main' into codex/function-composed-operations # Conflicts: # docs/api/api_reference.json # docs/en/release_note/ommx-3.0.md # docs/ja/release_note/ommx-3.0.md # python/ommx-pyscipopt-adapter/ommx_pyscipopt_adapter/adapter.py # python/ommx/ommx/_ommx_rust/__init__.pyi # python/ommx/src/function.rs # python/ommx/src/instance.rs # python/ommx/src/parametric_instance.rs # rust/ommx/doc/tutorial/error_handling.md # rust/ommx/src/instance/parse.rs
The documentation is generated from this commit.
| Commit: | acdfa91 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add output objective semantics to Instance and ParametricInstance (#1167) ## Summary - Add a v2 `OutputObjective` to `Instance` and `ParametricInstance` so the active solver formulation can differ from the objective reported by `evaluate()` and `evaluate_samples()`. Parameter materialization and state reconstruction preserve that output meaning; v1 serialization rejects models that it cannot represent losslessly. - Make objective conversion an explicit Preparation phase, add canonical QUBO/HUBO input classes and policy factories, and define `to_qubo()` / `to_hubo()` as in-place Preparation followed by format extraction. Whole-problem `as_minimization_problem()` / `as_maximization_problem()` conversions keep their original meaning. - Map solver optimality through the output-objective contract in the HiGHS, PySCIPOpt, and Python-MIP adapters. A finite-penalty optimum remains `Optimality.Unspecified` when it does not prove optimality for the reported objective. ## Behavior change QUBO/HUBO conversion now keeps the prepared minimization energy as the active `Instance`, while evaluated results retain the input instance's output semantics: ```python from ommx import DecisionVariable, Instance, Sense x = DecisionVariable.binary(0) instance = Instance.from_components( sense=Sense.Maximize, objective=x, decision_variables=[x], constraints={0: x == 1}, ) qubo, offset = instance.to_qubo(uniform_penalty_weight=2.0) state = {0: 0.0} # Solver-facing energy: minimize -x + 2 (x - 1)^2. assert instance.sense == Sense.Minimize assert instance.objective.evaluate(state) == 2.0 # User-facing output: the input Maximize / x objective. solution = instance.evaluate(state) sample_set = instance.evaluate_samples({0: state}) assert solution.sense == Sense.Maximize assert solution.objective == 0.0 assert sample_set.sense == Sense.Maximize assert sample_set.objectives[0] == 0.0 ``` This intentionally corrects the Python SDK v2 behavior, which restored the active sense but evaluated the final penalized energy. Returned QUBO/HUBO coefficients retain their existing meaning. The equivalent editable workflow is `prepare(InstanceClass.qubo(), PreparationPolicy.for_qubo(...))` followed by `as_qubo_format()`; HUBO has matching helpers.
| Commit: | 0a9c60d | |
|---|---|---|
| Author: | Toshiki Teramura | |
Harden output objective contracts
| Commit: | db0482e | |
|---|---|---|
| Author: | Toshiki Teramura | |
Use required features only as compatibility gate
| Commit: | c925bee | |
|---|---|---|
| Author: | Toshiki Teramura | |
Specify output objective contracts with doctests
| Commit: | fb9d9da | |
|---|---|---|
| Author: | Toshiki Teramura | |
Tighten output objective contracts
| Commit: | b86059a | |
|---|---|---|
| Author: | Toshiki Teramura | |
Move OutputObjective to the instance schema
| Commit: | 6b79d90 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Allocate protobuf numbers from the PR base
| Commit: | 7dd94fa | |
|---|---|---|
| Author: | Toshiki Teramura | |
Define output optimality over active states
| Commit: | ec79218 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Keep output objectives inactive during state rewrites
| Commit: | 75fc6e8 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Extend output objectives to parametric instances
| Commit: | 79e73b9 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Track output optimality transport
| Commit: | e9444e4 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Track output optimality transport
| Commit: | 66e5e94 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Add output objective semantics to Instance
| Commit: | 3f96103 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Make solver adapter APIs preparation-aware
| Commit: | e3285cd | |
|---|---|---|
| Author: | Toshiki Teramura | |
Represent composed functions as flat RPN programs
| Commit: | 00b0256 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Model integer powers as unary Function operations
| Commit: | 0042edd | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | Toshiki Teramura | |
Add composed operations to Function
| Commit: | 8deb8f3 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Deprecate legacy v2 dependency encoding
| Commit: | 662cc4b | |
|---|---|---|
| Author: | Toshiki Teramura | |
Clarify dependent expression feature
| Commit: | a9bac48 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Use evaluation tolerance for dependent indicators
| Commit: | 70fa077 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Preserve SOS1 promotion history with dependent expressions
| Commit: | b22746e | |
|---|---|---|
| Author: | Yu Yamashiro | |
Add finite-domain decision variables
| Commit: | fee0b4d | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Harden legacy ConstraintHints deserialization (#1058) ## Summary - treat legacy v1 `ConstraintHints` as advisory metadata during `Instance` and `ParametricInstance` deserialization - preserve active and removed regular constraints, their contexts, and the caller's capability boundary - stop unverified OneHot/SOS1 promotion and remove the obsolete private conversion module - clarify the v1 protobuf contract, migration guides, and Rust/Python release notes ## Why The v1 schema defines constraint hints as solver-oriented information derived from regular constraints. The current v3 parser instead constructs first-class special constraints directly from hint IDs and deletes the referenced regular rows without checking their equations, Big-M links, selector isolation, or equivalence. A malformed hint can therefore change the feasible set and required capabilities while leaving no auditable transformation record. This first workstream slice is deliberately fail-closed: regular constraints remain the source of truth until the common proof and reduction framework in #1057 can perform explicit, caller-authorized promotion. ## Validation - `task format` - `cargo test -p ommx instance::parse::tests --lib` (29 passed) - `task rust:test` (902 passed; one existing local-registry test hit a read-only database) - the affected registry test passed with an isolated `OMMX_LOCAL_REGISTRY_ROOT` - `cargo clippy -p ommx --all-targets -- -D warnings -A clippy::needless_question_mark -A clippy::explicit_counter_loop` - `task rust:doc:check` - `git diff --check` ## Tracking Part of #1057.
| Commit: | 95802b0 | |
|---|---|---|
| Author: | Toshiki Teramura | |
Harden legacy constraint hint deserialization
| Commit: | 7187371 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add OMMX v2 protobuf round-trip support (#984) ## Summary Part of #958. This PR completes Rust-side OMMX v2 protobuf round-trip support for the normalized SDK roots. It adds: - v2 byte encoders and decoders for `Instance`, `ParametricInstance`, `Solution`, and `SampleSet` - v2 parse paths that rebuild normalized decision-variable, parameter, named-function, and constraint collection owners - feature-based forward-compatibility checks through `required_features` - root-boundary validation for sidecar ownership, removed-reason ownership, structural special-constraint IDs, fixed/dependent partitions, sample-ID axes, and stored feasibility fields - `feasibility_atol` on v2 `Solution` and `SampleSet` so stored feasibility columns can be checked without re-evaluating the model - round-trip and malformed-payload coverage for special constraints, named functions, parameters, labels/context, required features, and v2 root decoding The v2 serializer remains infallible from normalized Rust SDK data. The decoder is fallible because protobuf payloads are an external boundary and can violate table, collection, or root invariants.
| Commit: | c73e3ab | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add ommx.v2 top-level protobuf schema (#982) ## Summary This PR adds the first full `ommx.v2` top-level protobuf schema shape. - Adds v2 shared components for `Feature` and `ModelingLabel`, while keeping constraint-specific sidecars (`ConstraintContext`, `RemovedReason`, and `Provenance`) with the v2 constraint schema. - Adds normalized v2 owner wrappers for decision variables, parameters, named functions, and regular/indicator/one-hot/SOS1 constraint families. - Adds v2 top-level roots for `Instance`, `ParametricInstance`, `Solution`, and `SampleSet`. - Adds root-level `required_features` as the first field, so readers can reject payloads requiring wire-level semantics they do not understand instead of silently ignoring future fields. - Keeps unchanged protobuf components referenced from `ommx.v1`, including `Function`, `Bound`, `Equality`, `DecisionVariable.Kind`, `Instance.Sense`, `Optimality`, `Relaxation`, `SampledValues`, `ProcessMetadata`, `Instance.Description`, and `Parameters`. - Leaves `format_version` out of v2 roots; backward compatibility is handled by protobuf evolution and Buf breaking-change checks, while forward-incompatible changes should move to a new package/media type. - Regenerates `rust/ommx/src/ommx.v2.rs`. This intentionally does not implement Rust parse/write conversion or Artifact media-type routing yet. Those should land root-by-root after this schema boundary is reviewed. Refs #958.
| Commit: | c4d9d29 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add protobuf v2 generation and breaking checks (#980) ## Summary This PR adds the first protobuf v2 generation scaffold for the upcoming `ommx.v2` wire-format work. - Adds `proto/ommx/v2/named_function.proto` as a minimal v2 message that references the existing `ommx.v1.Function` leaf schema. - Generates `rust/ommx/src/ommx.v2.rs`, confirming the Rust module layout can resolve v2-to-v1 leaf references through sibling generated modules. - Exposes the generated module as `ommx::v2`. - Updates `protogen` so it no longer assumes only `ommx.v1.rs` exists, formats every generated `ommx.*.rs` file, and fails when `rustfmt` fails. - Adds a Buf breaking-change job that checks the current `proto` schema against `origin/main` using the existing `FILE` policy. This intentionally does not add v2 top-level roots, parse/write implementation, or Artifact media types yet. It only establishes the generation/module boundary and compatibility guard needed before the full schema work. Refs #958. Closes #409.
| Commit: | 0aa862c | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Unify OMMX annotations across protobuf and artifacts (#939) ## Summary - Makes OMMX domain objects the source of truth for annotations, with protobuf payloads carrying OMMX metadata fields and user extension annotations. - Projects domain annotations into OCI layer descriptors when writing artifacts, and merges legacy descriptor-only annotations back into domain objects when reading artifacts. - Updates Rust and Python SDK APIs so typed metadata is accessed through domain fields, user annotations are read-only mapping views with explicit replacement/add helpers, and raw v1 artifact add paths are removed. - Extends Instance, ParametricInstance, Solution, and SampleSet protobuf schemas and generated bindings to persist user annotations and process metadata. - Updates dataset/catalog helpers, experiments, examples, tests, and documentation to use the unified annotation model. ## Notes - Descriptor annotations remain a compatibility and OCI projection layer; protobuf/domain metadata wins when both protobuf and descriptor data provide the same OMMX-defined field. - Low-level raw artifact layer APIs still accept explicit descriptor annotations, while high-level user annotation helpers reject the reserved `org.ommx.v1.*` namespace.
| Commit: | 71288b2 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add format_version field and forward compatibility check (v3 port) (#838) ## Summary Ports the `format_version` forward-compatibility check from the v2 maintenance release (#835, on `dev-2.x`) onto the v3 main branch, so v3 ships with the same infrastructure for rejecting data produced by future SDKs with semantic-breaking format changes. ## Forward compatibility policy - `ommx.v1` backward compatibility is unchanged — old data remains readable by new SDKs. - Non-semantic-breaking proto additions continue to rely on protobuf's standard forward compatibility (unknown fields are ignored). - Semantic-breaking format changes bump `format_version` (major-only, single `uint32`; no minor/patch). - A single `CURRENT_FORMAT_VERSION` constant serves both sides: the SDK writes that value on all outgoing messages and accepts any `<= CURRENT_FORMAT_VERSION` on parse. Data with a higher `format_version` produces `RawParseError::UnsupportedFormatVersion` with a clear upgrade message. ## Changes - Proto: add `uint32 format_version = 100` to `Instance`, `Solution`, `SampleSet`, `ParametricInstance`. - Rust: add `pub const CURRENT_FORMAT_VERSION: u32 = 0`, the `UnsupportedFormatVersion { data_version, current_version }` variant on `RawParseError`, and a `check_format_version` helper called at the start of each of the four `Parse` implementations. All three writer sites (`From<Instance>`, `From<ParametricInstance>`, `From<Solution>` for their v1 counterparts) stamp `format_version: crate::CURRENT_FORMAT_VERSION` rather than a literal so bumping the version is a one-line change. - Tests: four new Rust tests verify that `format_version = 1` is rejected with the expected error message on each message type. ## Naming difference vs. #835 The v2 maintenance PR (#835) introduced this constant as `ACCEPTED_FORMAT_VERSION`. Review feedback on this PR pointed out that the written and accepted versions are equal by construction, so they were unified into one constant and renamed to `CURRENT_FORMAT_VERSION` here. The v2 side is left as-is (released API surface); only v3 uses the new name. ## v3-specific adjustments during cherry-pick - `rust/ommx/src/instance/parse.rs`: conflicts resolved to keep v3's `constraint_hints: None` in `From<Instance>` / `From<ParametricInstance>` (v3 absorbs hints into first-class `OneHot`/`SOS1` collections and does not currently serialize them back to the v1 proto), while adding `format_version: crate::CURRENT_FORMAT_VERSION`. - The v2 patch touched `rust/ommx/src/v1_ext/parametric_instance.rs` and the generated `python/ommx/ommx/v1/*_pb2.py*` stubs; neither exists in v3 (v1_ext removed; Python-side protobuf dependency removed), so those file changes were dropped. ## Note on the writer-side `format_version` This PR keeps `CURRENT_FORMAT_VERSION = 0` — matching the v2 maintenance release exactly. Whether v3 should bump it to `1` depends on whether any of the v3 changes constitute a semantic-breaking format change (as opposed to purely in-memory API changes). That decision is intentionally deferred to a follow-up; when it is made, flipping the constant is a single-line change and all three writer sites update together. ## Test plan - [x] `cargo test -p ommx --lib` passes (463 tests). - [x] `task python:test` passes. - [x] `task format` applied. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| Commit: | e68db01 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add format_version field and forward compatibility check (#835) ## Summary Introduces a `format_version` field on the four top-level OMMX exchange messages (`Instance`, `Solution`, `SampleSet`, `ParametricInstance`) and a corresponding reader-side check, so that future SDKs that ship semantic-breaking format changes cannot be silently misread by this SDK. This is the v2 maintenance release that must ship before v3 so that users upgrading to v3-produced data get a clear error rather than a silently-wrong parse. ## Forward compatibility policy - `ommx.v1` backward compatibility is unchanged — old data remains readable by new SDKs. - Non-semantic-breaking proto additions continue to rely on protobuf's standard forward compatibility (unknown fields are ignored). - Semantic-breaking format changes bump `format_version` (major-only, single `uint32`; no minor/patch). - Each SDK declares an `ACCEPTED_FORMAT_VERSION` constant. Reading data with a higher `format_version` produces `RawParseError::UnsupportedFormatVersion` with a clear upgrade message. ## Changes - Proto: add `uint32 format_version = 100` to `Instance`, `Solution`, `SampleSet`, `ParametricInstance`. Field number 100 is reserved across all four messages for future coherence with v3. - Rust: add `pub const ACCEPTED_FORMAT_VERSION: u32 = 0`, a `UnsupportedFormatVersion { data_version, accepted_version }` variant on `RawParseError`, and a `check_format_version` helper invoked at the start of each of the four `Parse` implementations. - Tests: four new Rust tests verify that `format_version = 1` is rejected with the expected error message on each message type. ## Test plan - [x] `cargo test -p ommx --lib` passes (429 tests). - [x] `task rust:test` passes (including doctests). - [x] `task python:test` passes (pyright + ruff + pytest for main package and all adapters). - [x] `task format` applied. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| Commit: | 81caf0f | |
|---|---|---|
| Author: | Hiromi Ishii | |
| Committer: | GitHub | |
Introduces `NamedFunction` to instance, solution, sample_set, and parametric_instance (#748) ## Summary Introduces `NamedFunction` to track and evaluate named mathematical functions within optimization instances. This allows users to define auxiliary functions (e.g., costs, penalties, metrics) that are evaluated alongside the main objective and constraints. ## Changes ### Protocol Buffers - Add `NamedFunction`, `EvaluatedNamedFunction`, `SampledNamedFunction` messages - Integrate into `Instance`, `ParametricInstance`, `Solution`, `SampleSet` - Fix typos in `constraint.proto` ("constains" → "contains", "evalute" → "evaluate") ### Rust SDK **New Types:** - `NamedFunction`: A named function with ID, name, subscripts, parameters, and a `Function` body - `EvaluatedNamedFunction`: A named function evaluated at a specific state - `SampledNamedFunction`: A named function evaluated across multiple samples **Instance Integration:** - Add `named_functions` field to `Instance` and `ParametricInstance` - Support in `evaluate()`, `partial_evaluate()`, `evaluate_samples()` - Builder methods: `add_named_function()`, `get_named_function_by_name()` **Solution Integration:** - Add `evaluated_named_functions` field - Extract methods: `named_function_ids()`, `named_function_names()`, `extract_named_functions()`, `extract_all_named_functions()` **SampleSet Integration:** - Add `named_functions` field - Extract methods similar to Solution - **API Change**: Deprecate `SampleSet::new()` in favor of `SampleSet::builder().build()` (consistent with `Solution`) - Add `SampleSetBuilder::build_unchecked()` for construction without validation - Add key/id consistency validation **Invariants:** - `named_functions` keys must match value's `id()` - `named_functions` may contain fixed or dependent variable IDs (like `removed_constraints`) - Variable IDs in `named_functions` must be registered in `decision_variables` - **Important**: `named_functions` are NOT included in the "used" set calculation (similar to `removed_constraints`) ### Python SDK - Add `NamedFunction`, `EvaluatedNamedFunction`, `SampledNamedFunction` classes - Add `__repr__`, `__copy__`, `__deepcopy__` methods for all named function classes - Add `used_decision_variable_ids` getter to `EvaluatedNamedFunction` and `SampledNamedFunction` - Add `named_functions_df` property to `Instance`, `ParametricInstance`, `Solution`, `SampleSet` - Add `NamedFunction._as_pandas_entry()` for DataFrame integration - Integrate with `Instance`, `Solution`, `SampleSet` ## Breaking Changes - `SampleSet::new()` is now deprecated (use `SampleSet::builder().build()`) ## Test Plan - [x] Rust unit tests for NamedFunction evaluate/partial_evaluate - [x] Rust tests for SampleSet extract methods - [x] Rust test for named functions with fixed/dependent/irrelevant variables - [x] Property-based tests for Instance with NamedFunction - [x] SampledNamedFunction serialization round-trip test - [x] Python integration tests 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Toshiki Teramura <toshiki.teramura@gmail.com>
| Commit: | 7858e2a | |
|---|---|---|
| Author: | NY57 | |
| Committer: | GitHub | |
Add the `.sense` property to `ommx.v1.Solution` and `ommx.v1.SampleSet`. (#530) Co-authored-by: Toshiki Teramura <toshiki.teramura@gmail.com>
| Commit: | d6a63f2 | |
|---|---|---|
| Author: | Hiromi Ishii | |
fix: updates docs
| Commit: | d6595be | |
|---|---|---|
| Author: | Devin AI | |
| Committer: | Devin AI | |
Fix buf.yaml version and format protobuf files Co-Authored-By: h.ishii@j-ij.com <h.ishii@j-ij.com>
| Commit: | b6f0cd2 | |
|---|---|---|
| Author: | Devin AI | |
| Committer: | Devin AI | |
Add support for k-hot constraints Co-Authored-By: h.ishii@j-ij.com <h.ishii@j-ij.com>
| Commit: | e540d20 | |
|---|---|---|
| Author: | Hiromi Ishii | |
| Committer: | GitHub | |
Supports SOS1 Detection (#301) This adds the following things: - [x] Adds slots for SOS1 constraints - [x] Adds SOS1 support in PySCIPOpt We DID NOT add SOS1 support for `Python-MIP` for the time being.
| Commit: | 4a651ee | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Deprecate `feasible_unrelaxed` in `*.proto`, and introduce `feasible_relaxed` (#280) - The meaning of `feasible` changed - Before this PR, `feasible` field in `ommx.v1.Solution` and `ommx.v1.SampleSet` means the feasibility about the remaining constraint in `ommx.v1.Instance`, ignoring `removed_constraints` in `ommx.v1.Instance` - After this PR, previous `feasible` field is renamed into `feasible_relaxed`, and `feasible` field means unrelaxed feasibility, i.e. it also looks `removed_constraints`. In other words, `feasible_unrelaxed` is renamed into `feasible`. - The `feasible_unrelaxed` field in `*.proto` becomes deprecated. - On API level, `feasible_unrelaxed` is kept.
| Commit: | 2754571 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add `decision_variable_dependency` to represent polynomial dependency between decision variables (#257) Ready for binary encoding of integer variables. - When an integer variable $x \in [0, 3]$ is binary encoded as $x = b_1 + 2 b_2$ with $b_1, b_2 \in \{0, 1\}$, $x$ will disappear from objective function and constraints. - Thus, $x$ is not passed to solver which only solve with $b_1$ and $b_2$. So we have to reconstruct $x$ from $b_1$ and $b_2$, but how? - `decision_variable_dependency` field in `ommx.v1.Instance` stores this relation, i.e. $x = b_1 + 2 b_2$ as a set of the ID of $x$ and a polynomial $b_1 + 2 b_2$.
| Commit: | 47d2894 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
`feasible_unrelaxed` field representing the feasibility including the removed constraints (#251) - As removed constraints has been introduced in #189, this PR adds `feasible_unrelaxed` field in `ommx.v1.Solution` and `SampleSet` to represent the `State` is feasible in terms of removed constraints. - `Instance.relax_constraint` and `Instance.restore_constraint` has been exposed in Python SDK
| Commit: | fc54992 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
OMMX Adapter for OpenJij, introduce `ommx.v1.SampleSet` (#236) OMMX Message Schema -------------------- - Introduce `ommx.v1.SampleSet`, `ommx.v1.Samples`, its components including `SampledValue`. Python SDK ---------- - Add `ommx-openjij-adapter` as a reference for QUBO sampler Rust SDK ---------- - Add `Evaluate::evaluate_samples`
| Commit: | e2bba8c | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Removed constraints (#189) - Introduce `ommx.v1.RemovedConstraint` message - This consists of `ommx.v1.Constraint` and removed reason, and stored in `ommx.v1.Instance` and `ommx.v1.ParametricInstance`. - This is created when the constraint is relaxed. This PR introduces new API `Instance::relax_constraint` to create a relaxed instance, and revert it with `Instance::restore_constraint`. - Removed reason is stored as short string `removed_reason` and string-string pair `removed_reason_parameters` because these are designed for human-readability rather than API re-usability - `Instance::evaluate` converts `RemovedConstraint` into `EvaluatedConstraint` as usual `Constraint`s. These are merged into `ommx.v1.Solution` since users would also want to show the breakage of removed constraints with non-removed constraints
| Commit: | 6362b56 | |
|---|---|---|
| Author: | Hiromi Ishii | |
| Committer: | GitHub | |
feat: adds `constraint_hints` field to instance and provide a scheme for one-hot constraints (#180) This PR adds the following field to `ommx.v1.instance`: - `constraint_hints`: A list of constraint hints to be used by solver to gain performance. They are derived from one-or-more constraints in the instance and typically contains information of special types of constraints (e.g. one-hot, SOS, ...). This is expressed as a `ConstraintHint` messag, which is a pair of originating constraints and parameters specific to each special constraint types. Currently, there is only one constraint type supported: `OneHot`, which expresses a one-hot constraint. --------- Co-authored-by: Toshiki Teramura <toshiki.teramura@gmail.com>
| Commit: | 36d227d | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
`substituted_value` in `ommx.v1.DecisionVariable` (#173) This field stores the value within the `partial_evaluate`
| Commit: | e6099be | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
ParametricInstance (#146) - Introduce `ommx.v1.ParametricInstance` message to represent QUBO without fixing penalty weight.
| Commit: | 912bf96 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Revert "`dual_variable` and `penalty_weight` in `Constraint` message for QUBO (#144)" (#149) This reverts commit a0d0707a01c953988381b76243b7c18ef8b3586c #144 - The strategy for implementing QUBO and PUBO conversion has been changed to use #146, which conflicts with #144
| Commit: | a0d0707 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
`dual_variable` and `penalty_weight` in `Constraint` message for QUBO (#144) # Summary - Add optional fields, `dual_variable` and `penalty_weight` in `Constraint` message. - This will be used in #143 to create unconstrained problem. #143 will support two way to create QUBO and PUBO, penalty method and augmented Lagrangian method # Detail For a problem $$ \begin{align*} \min & f(x) \\ \text{s.t.} & g(x) = 0 \end{align*} $$ - Penalty method try to minimize $f(x) + \rho |g(x)|^2$, where $\rho$ is called penalty weight. - Augmented Lagrangian method try to minimize $f(x) + \lambda g(x) + \rho |g(x)|^2$, where $\lambda$ is current dual variable and $\rho$ is also a penalty weight. `dual_variable` field is intended to store $\lambda$, and `penalty_weight` stores $\rho$ in this sense.
| Commit: | 64ecf6e | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add `subscripts` field into `Constraint` message (#92) Split from #88 It is rather natural also for `Constraint` message to use `subscripts` for integer parameter and `parameters` for string parameters as `DecisionVariable` does.
| Commit: | 7dab7ef | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Store dual variable in `EvaluatedConstraint` (#78) - `EvaluatedConstraint.dual_variable` to store Lagrangian dual variables - `ommx_python_mip_adapter.solve` stores the dual variable if `mip.Constr.pi` exists.
| Commit: | b598637 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Introduce `ommx.v1.Result` and `Optimality` enum (#77) - ⚠️ `option bool optimal` is encoded into single `bool` in Python, i.e. `None` and `False` are not distinguished. Instead, this PR introduces `Optimality` enum to explicitly distinguish them. - To represent the error case of solvers, `ommx.v1.Result` has been introduced. `ommx_python_mip_adapter.solve` returns this object.
| Commit: | 5411563 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Flatten descriptions of decision variables and constraints (#71) - `DecisionVariable.Description` and `ConstraintDescription` are flattened. - New `description` fields are added to `DecisionVariable` and `Constraint` to write long human-readable description - `subscripts` are split from `parameters` in `DecisionVariable`
| Commit: | 193d2d8 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add document for quadratic function (#46) Resolve #45
| Commit: | 0b69c90 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Store decision variable IDs used to evaluating constraint (#39)
| Commit: | 57bab47 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Rename `RawSolution` to `State` (#38) - `RawSolution` is renamed into `State` - `SolutionList` and `RawSolutionList` are removed
| Commit: | d5bfb9f | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Store descriptions of decision variables and constraints in Solution (#37) - Move `EvaluatedConstraint` message from `Solution.*` to `ommx.v1.*` - Move `Constraint.Description` into `ommx.v1.ConstraintDescription`, and revise `forall` field into `parameters` which stores string-string map instead of `repeated int64` - Add `decision_variables` in `Solution` message
| Commit: | 1ed91b1 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Move feasible and optimal fields to Solution message instead of RawSolution (#36) Fix of #32, split from #34 - Make `RawSolution` "pure" solution state
| Commit: | 209d05c | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Add evaluated values in `Solution` message, rename old message as `RawSolution` (#32) - Rename current `Solution` into `RawSolution` - New `Solution` is added. This contains `RawSolution` and the objective and constraints values evaluated with the `RawSolution`. - Evaluated constraints consist of evaluated value of `Function` and its equality, not the violation of constraint. - For example, it has different meaning if a constraint `f(x) = 0` is violated as `f(x) = 1` and `f(x) = -1`. We should keep this difference on `Solution` level, and thus it is stored as a pair (`1`, `=0`) or (`-1`, `=0`).
| Commit: | e0f5114 | |
|---|---|---|
| Author: | NY57 | |
| Committer: | GitHub | |
Add `sense` field to `Instance` (#28) # 変更点 OMMX::Instanceが意味する最適化問題が最小化問題であるか最大化問題であるかが判別できないという課題があった為、senseを追加しました。 # 確認事項 こちらの変更後、Pythonパッケージをv0.1.2として、Rustクレートをv0.1.1としてリリースしても良いでしょうか?(バージョニングは適切でしょうか?) --------- Co-authored-by: Toshiki Teramura <toshiki.teramura@gmail.com>
| Commit: | 148ca07 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Brush up `ommx::v1::Instance` design in Rust side (#10) - Add `decision_variables` in `Instance` message - Add `Bound` message in `DecisionVariable` message - Integrate `SparseMatrix` message into `Quadratic` since only this message uses it
| Commit: | 7c59e07 | |
|---|---|---|
| Author: | NY57 | |
| Committer: | GitHub | |
Prototyping OMMX::Result (#11)
| Commit: | 3ac3e16 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
`Instance` message (#5)
| Commit: | e3babc1 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Revise directory structure of `proto` based on `buf` default settings (#4) - Reconstruct `proto/` directory as `buf` does - `ommx.v1` namespace is created. - Setup workflow to check `proto/**/*.proto` files using `buf` - Breaking change check is omitted since it is not released.
| Commit: | f55391b | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Schema for decision variable attributes, better protogen (#2)
| Commit: | 2b30bb0 | |
|---|---|---|
| Author: | Toshiki Teramura | |
| Committer: | GitHub | |
Setup Rust workspace and GitHub Actions (#1)