v6.4.13
Fri Aug 28 2026
Bug Fixes
AI-Engine
- guard zero-span bounds in direction loss
create_direction_lossnormalised a variable's position by(max - min).sum(). When a variable's boundary constraints are pinned, i.e. min == max on every date, that span is 0 and the term evaluates to 0/0 = NaN. The NaN propagates into the loss, then into the gradients, survivesclip_grad_value_/clip_grad_norm_and is written into every optimisation variable byopt.step(). The next forward pass then fails with "produced non finite values" on whichever node happens to come first in topological order, which makes the crash look unrelated to the bounds that caused it. A pinned variable cannot move, so it carries no direction signal at all: skip it instead of dividing by zero. When every direction variable is pinned the loss falls back to 1, matching the no-directions default. Reproduced on danske-spil optimization 12, where two media variables were pinned to min = max = 0. - accumulate the Maximize direction penalty The Maximize branch of
create_direction_lossassignedloss = 1 - positioninstead of adding to the running sum, so it discarded every direction term accumulated before it. The result depended on the iteration order of the directions dict: a Maximize variable visited last wiped out all Minimize pressure, while the divisornstill counted the discarded terms. Add the penalty like the Minimize branch does. The loss is now the mean of the per-variable penalties regardless of direction or order, which is what the divisor already assumed. The two existing expectations move from 1.25 to 1.5: with b Minimize and c Maximize both sitting at position 0.5, each contributes 0.5, so the mean is 0.5 rather than the 0.25 the overwrite produced.