Skip to main content

feasibility_quantities_are_finite

Function feasibility_quantities_are_finite 

Source
pub fn feasibility_quantities_are_finite(quantities: &[f64]) -> bool
Expand description

Can this row’s feasibility be DECIDED by comparison at all?

EVERY feasibility rule in this module decides with an ordering predicate on per-row quantities — slack < −tol, drift ≥ 0, t < step, violation > worst — and EVERY one of those is false for NaN. A row carrying a NaN therefore contributes NOTHING to any of those minima and maxima, and the rule answers with its neutral element: “take the whole step”, “nothing is violated”. That is the exact opposite of the truth, and it is gam#2721: a step with a NaN component was certified at α = 1.0, and its caller rejects only !α.is_finite() || α ≤ 0.0, neither of which 1.0 is.

The quantities are therefore tested BEFORE they are compared, and a row that cannot be decided is refused by name rather than skipped. The predicate is exported — rather than re-written at each site — because the defect WAS the rule existing in several copies and being repaired in one of them: the two fraction-to-boundary rules here, the violation sweep here, the saddle-escape chord truncation in gam-custom-family, and the Bernoulli marginal-slope segment cap in gam-models all decide with the same comparisons.

NaN is the value that cannot be compared, but it is not the only value that must be refused. An infinite drift passes drift ≥ 0 and an infinite iterate value drives the violation to −∞, both of which read as “this row does not object” for an argument that is not a point. And the carrier’s own constructor already holds the same line — LinearInequalityConstraints::new rejects a non-finite A or b with the identical reason — so requiring finiteness here keeps the row descriptors and the per-iterate quantities under ONE rule rather than two.

A NaN row_norm additionally defeats the norm <= 0.0 vacuity test that would otherwise be the branch to catch it, which is why the norm is checked here and not left to that branch.

This does NOT collide with the legitimately-vacuous row: ‖a‖ = 0 with a bound at or below zero is finite, passes here, and keeps its own disposition in each rule.