Skip to content

Establish a repository-wide standard for numeric types and arithmetic #1116

Description

@isPANN

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:

  1. indices and collection sizes;
  2. individual weights, costs, times, capacities, and bounds;
  3. totals produced by adding or multiplying many input values;
  4. positive and negative values;
  5. values stored in JSON or exposed through the CLI/MCP interface;
  6. SAT variable numbers and other compact integer encodings;
  7. conversions between number types;
  8. overflow and underflow behavior;
  9. 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:

make doc

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:

  1. MinimumDominatingSet with two isolated vertices and weights [i32::MAX, i32::MAX];
  2. MinimumSetCovering with universe {0, 1}, sets [{0}, {1}], and weights [i32::MAX, i32::MAX].

Both results must be exactly:

4294967294

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:

make check

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions