ommx 3.0.0-alpha.1

Open Mathematical prograMming eXchange (OMMX)
Documentation
# Constraints

Constraints define the feasible region of optimization problems. Constraints can be equality
or inequality types, and can be temporarily removed while preserving their definition.

```rust
use ommx::{Constraint, Function, Linear, linear, coeff};

// Create constraints: x1 + x2 <= 10 (as x1 + x2 - 10 <= 0)
let constraint_expr = coeff!(1.0) * linear!(1) + coeff!(1.0) * linear!(2) + Linear::from(coeff!(-10.0));
let constraint = Constraint::less_than_or_equal_to_zero(Function::from(constraint_expr));

// Equality constraint: x1 - x2 = 0 (as f(x) = 0)
let eq_expr = coeff!(1.0) * linear!(1) - coeff!(1.0) * linear!(2);
let eq_constraint = Constraint::equal_to_zero(Function::from(eq_expr));
```

## Constraint Type System

OMMX supports four first-class constraint types:

- **[`Constraint`]crate::Constraint** — standard equality / inequality
  constraints on a [`Function`]crate::Function.
- **[`IndicatorConstraint`]crate::IndicatorConstraint**  `indicator_variable = 1 → f(x) {=,<=} 0`, keyed by
  [`IndicatorConstraintID`]crate::IndicatorConstraintID.
- **[`OneHotConstraint`]crate::OneHotConstraint** — exactly one of a
  set of binary variables is 1, keyed by
  [`OneHotConstraintID`]crate::OneHotConstraintID.
- **[`Sos1Constraint`]crate::Sos1Constraint** — at most one of a set
  of variables is non-zero, keyed by
  [`Sos1ConstraintID`]crate::Sos1ConstraintID.

Each constraint type also has its own independent ID type to prevent
accidental cross-type lookups, and each ID lives on the enclosing
[`BTreeMap`](std::collections::BTreeMap) key rather than on the
constraint struct.

### Stage parameter

Each constraint type follows the **Stage pattern** — parameterized by
lifecycle phase, with three inhabited stages:

- `Created` — the constraint as defined in the problem, carrying its
  [`Function`]crate::Function.
- `Evaluated` — the result of evaluating the constraint against a
  single [`State`]crate::v1::State; carries `evaluated_value`,
  `feasible`, `dual_variable`, and the set of variable IDs it used.
- `Sampled` — the result of evaluating against a
  [`Sampled<State>`]crate::Sampled; carries per-sample evaluated
  values and feasibility.

Each constraint type implements the
[`ConstraintType`](crate::ConstraintType) trait, which maps all three
stages as associated types — a defunctionalization of `Stage → Type`
since Rust lacks HKTs. "Removed" is **not** a stage: removal is
collection-level metadata tracked as a
[`RemovedReason`](crate::RemovedReason) paired with the original
`Created` constraint.

### Collections

Three generic collection wrappers handle constraints uniformly:

- [`ConstraintCollection`]crate::ConstraintCollection  active + removed, used in [`Instance`]crate::Instance. Removed
  constraints are stored as `(T::Created, RemovedReason)` tuples.
- [`EvaluatedCollection`]crate::EvaluatedCollection — evaluation
  results, used in [`Solution`]crate::Solution.
- [`SampledCollection`]crate::SampledCollection — sampled results,
  used in [`SampleSet`]crate::SampleSet.

To add a new constraint type, see the docs on
[`ConstraintType`](crate::ConstraintType).