Proto commits in Jij-Inc/ommx

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)