pub fn feasibility_quantities_are_finite(quantities: &[f64]) -> boolExpand 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.