Why this is needed
Almost every combinatorial optimization problem uses numbers: vertex indices, set sizes, weights, costs, capacities, deadlines, objective values, and bounds. The repository currently uses usize, i32, i64, u64, and f64, but it does not have one written rule explaining when each type should be used.
Using several number types is not itself a problem. The problem is that contributors currently have to guess:
- Should a size be
usize or u64?
- If each weight is
i32, what type should hold the sum of many weights?
- When may code use
as, and when must it check that a conversion fits?
- What should happen when an addition or multiplication is too large?
- Should a value saved in JSON use
usize or a fixed-size type such as u64?
- When is
f64 acceptable, and when must a result remain an exact integer?
Different parts of the current repository answer these questions differently. That makes boundary bugs likely and makes new models and reductions harder to review.
What design already exists
The repository has several useful pieces, but they do not form a complete standard:
Problem::dims() and configurations use usize for in-memory dimensions and indices.
WeightElement separates the type of one weight from the type used for a sum.
NumericSize lists operations required by objective-value types.
Decision<P> uses the same value type for an optimization result and its decision bound.
- Problem schemas and the CLI can parse several integer and floating-point types.
- Some models and reductions check overflow explicitly.
What is missing is a repository-level document that connects these pieces and states which behavior is required. NumericSize, for example, says what operations a type supports but does not say which type a model should choose or what to do on overflow.
Existing behavior showing the gap
Weight totals can become wrong
Many models store each weight as i32 and also use i32 for the total.
For a MinimumDominatingSet with two isolated vertices and weights [i32::MAX, i32::MAX], both vertices must be selected. The correct total is:
2_147_483_647 + 2_147_483_647 = 4_294_967_294
Current behavior is a panic in a debug build and potentially -2 in a release build. A negative total can make the solver choose the wrong solution.
This behavior is shared by existing W::Sum-based models, not limited to one new reduction.
SAT variable numbers are checked differently
SAT stores the number of variables as usize but stores positive and negative variable numbers as i32.
Current behavior is inconsistent:
Satisfiability, NAESatisfiability, and Maximum2Satisfiability do not fully check variable numbers;
OneInThreeSatisfiability and Planar3Satisfiability do check them;
- variable
0 can cause an integer underflow during evaluation;
- existing reductions such as
sat_ksat.rs, satisfiability_maximum2satisfiability.rs, and circuit_sat.rs convert usize variable numbers to i32 without checking that they fit.
Objective
Create and adopt one repository-wide standard for numeric types and arithmetic.
The standard must cover existing models and reductions as well as future contributions. It must make concrete decisions for:
- indices and collection sizes;
- individual weights, costs, times, capacities, and bounds;
- totals produced by adding or multiplying many input values;
- positive and negative values;
- values stored in JSON or exposed through the CLI/MCP interface;
- SAT variable numbers and other compact integer encodings;
- conversions between number types;
- overflow and underflow behavior;
- exact integer calculations versus floating-point calculations.
For each category, the document must say:
- which Rust type should normally be used;
- why that type is appropriate;
- what range is supported;
- how to convert to or from other types;
- whether an out-of-range value is rejected or represented with a wider type;
- one short example from this repository.
The result must be a rule a contributor can follow without already knowing the implementation history.
Required repository changes
- Add a contributor-facing numeric-types section to
docs/src/design.md, or add a dedicated page linked from the Design page and docs/src/SUMMARY.md.
- Add a shorter checklist to
.claude/CLAUDE.md so model and reduction work follows the same rules.
- Update the model and reduction contribution instructions to ask authors to identify:
- the type of each numeric input;
- the type of each computed total;
- the largest supported value;
- every conversion to a smaller or signed type.
- Apply the new rules to the two existing problem areas described above:
- weighted totals based on
WeightElement::Sum;
- SAT variable validation and SAT reductions that generate new variables.
- Add tests that protect both the standard examples and normal small-instance behavior.
Do not introduce a generic numeric framework, adapter layer, or compatibility system. The goal is a small set of clear rules and direct fixes to code that violates them.
Suggested starting rules
These are starting points for the design, not a substitute for documenting the final decisions:
- Use
usize for indices into Rust collections and for in-memory configuration dimensions.
- Do not assume that the type of one weight is large enough for the sum of many weights.
- Use a wider type for totals when valid inputs can exceed the range of one input value.
- Do not use
as when a conversion can change the value, sign, or range; check the conversion and report an error.
- Check additions and multiplications derived from user/model input before they overflow.
- Use
f64 only when approximate arithmetic is part of the problem definition or solver interface, not as a shortcut for exact integer arithmetic.
- Define whether serialized sizes are fixed-width values or machine-sized
usize; do not leave this to each model.
Verification
A contributor can find and apply the standard
Run:
The generated contributor documentation must contain the numeric standard and the nine categories listed under Objective. The Design page must link to it.
The model and reduction contribution instructions must each include a numeric-review checklist. A reviewer should be able to answer, from a new model or reduction PR, what every number means, how large it may become, and where conversions are checked.
Existing weighted models produce the correct total
Add focused tests runnable with:
cargo test numeric_boundaries -- --nocapture
Evaluate configuration [1, 1] for:
MinimumDominatingSet with two isolated vertices and weights [i32::MAX, i32::MAX];
MinimumSetCovering with universe {0, 1}, sets [{0}, {1}], and weights [i32::MAX, i32::MAX].
Both results must be exactly:
The tests must fail if either model panics, returns -2, silently caps the result, or says the configuration is invalid.
Existing SAT models reject invalid variable numbers consistently
Every SAT model using CNFClause must reject these inputs when the model is constructed:
- variable
0;
- variable
i32::MIN;
- variable
2 when num_vars is 1.
The error must identify the invalid value and allowed range. The test must fail if construction succeeds and evaluation merely ignores the invalid variable.
Variable i32::MAX with num_vars = i32::MAX as usize is valid and must pass construction without allocating an assignment.
Existing reductions do not change large numbers silently
Use an existing reduction that creates extra SAT variables, such as Satisfiability -> KSatisfiability<K3>. Give it a source already at the largest i32 variable number and a clause that requires one extra variable.
The reduction must stop with a clear error. It must not create a negative or otherwise changed variable number.
Finally run:
It must pass, proving that ordinary in-range instances retain their behavior.
Out of scope
- Replacing every number in the repository with one type.
- Fixing every numeric conversion in the repository in this single issue; additional violations found during the audit may become focused follow-up issues.
- Adding a general numeric framework or compatibility layer.
Why this is needed
Almost every combinatorial optimization problem uses numbers: vertex indices, set sizes, weights, costs, capacities, deadlines, objective values, and bounds. The repository currently uses
usize,i32,i64,u64, andf64, but it does not have one written rule explaining when each type should be used.Using several number types is not itself a problem. The problem is that contributors currently have to guess:
usizeoru64?i32, what type should hold the sum of many weights?as, and when must it check that a conversion fits?usizeor a fixed-size type such asu64?f64acceptable, and when must a result remain an exact integer?Different parts of the current repository answer these questions differently. That makes boundary bugs likely and makes new models and reductions harder to review.
What design already exists
The repository has several useful pieces, but they do not form a complete standard:
Problem::dims()and configurations useusizefor in-memory dimensions and indices.WeightElementseparates the type of one weight from the type used for a sum.NumericSizelists operations required by objective-value types.Decision<P>uses the same value type for an optimization result and its decision bound.What is missing is a repository-level document that connects these pieces and states which behavior is required.
NumericSize, for example, says what operations a type supports but does not say which type a model should choose or what to do on overflow.Existing behavior showing the gap
Weight totals can become wrong
Many models store each weight as
i32and also usei32for the total.For a
MinimumDominatingSetwith two isolated vertices and weights[i32::MAX, i32::MAX], both vertices must be selected. The correct total is:Current behavior is a panic in a debug build and potentially
-2in a release build. A negative total can make the solver choose the wrong solution.This behavior is shared by existing
W::Sum-based models, not limited to one new reduction.SAT variable numbers are checked differently
SAT stores the number of variables as
usizebut stores positive and negative variable numbers asi32.Current behavior is inconsistent:
Satisfiability,NAESatisfiability, andMaximum2Satisfiabilitydo not fully check variable numbers;OneInThreeSatisfiabilityandPlanar3Satisfiabilitydo check them;0can cause an integer underflow during evaluation;sat_ksat.rs,satisfiability_maximum2satisfiability.rs, andcircuit_sat.rsconvertusizevariable numbers toi32without checking that they fit.Objective
Create and adopt one repository-wide standard for numeric types and arithmetic.
The standard must cover existing models and reductions as well as future contributions. It must make concrete decisions for:
For each category, the document must say:
The result must be a rule a contributor can follow without already knowing the implementation history.
Required repository changes
docs/src/design.md, or add a dedicated page linked from the Design page anddocs/src/SUMMARY.md..claude/CLAUDE.mdso model and reduction work follows the same rules.WeightElement::Sum;Do not introduce a generic numeric framework, adapter layer, or compatibility system. The goal is a small set of clear rules and direct fixes to code that violates them.
Suggested starting rules
These are starting points for the design, not a substitute for documenting the final decisions:
usizefor indices into Rust collections and for in-memory configuration dimensions.aswhen a conversion can change the value, sign, or range; check the conversion and report an error.f64only when approximate arithmetic is part of the problem definition or solver interface, not as a shortcut for exact integer arithmetic.usize; do not leave this to each model.Verification
A contributor can find and apply the standard
Run:
The generated contributor documentation must contain the numeric standard and the nine categories listed under Objective. The Design page must link to it.
The model and reduction contribution instructions must each include a numeric-review checklist. A reviewer should be able to answer, from a new model or reduction PR, what every number means, how large it may become, and where conversions are checked.
Existing weighted models produce the correct total
Add focused tests runnable with:
cargo test numeric_boundaries -- --nocaptureEvaluate configuration
[1, 1]for:MinimumDominatingSetwith two isolated vertices and weights[i32::MAX, i32::MAX];MinimumSetCoveringwith universe{0, 1}, sets[{0}, {1}], and weights[i32::MAX, i32::MAX].Both results must be exactly:
The tests must fail if either model panics, returns
-2, silently caps the result, or says the configuration is invalid.Existing SAT models reject invalid variable numbers consistently
Every SAT model using
CNFClausemust reject these inputs when the model is constructed:0;i32::MIN;2whennum_varsis1.The error must identify the invalid value and allowed range. The test must fail if construction succeeds and evaluation merely ignores the invalid variable.
Variable
i32::MAXwithnum_vars = i32::MAX as usizeis valid and must pass construction without allocating an assignment.Existing reductions do not change large numbers silently
Use an existing reduction that creates extra SAT variables, such as
Satisfiability -> KSatisfiability<K3>. Give it a source already at the largesti32variable number and a clause that requires one extra variable.The reduction must stop with a clear error. It must not create a negative or otherwise changed variable number.
Finally run:
It must pass, proving that ordinary in-range instances retain their behavior.
Out of scope