Skip to content

Sum range ​

Every exercise generated from a recipe walks a running total from step to step. sumMax is the highest value that total may ever reach.

sumMax ​

text
0 <= every running sum <= recipe.sumMax

The ceiling is inclusive: sumMax: 19 permits a running sum of exactly 19. The floor is a hard 0, and it is not a recipe field — a soroban has no negative state, so there is nothing to configure.

PropertyValue
Typeinteger
Range1 … 1999
Default on create99
Applies toevery running sum, including the value each step lands on

The upper bound of 1999 exists because sumMax + 1 sizes the generator's feasibility analysis arrays; it is a memory bound, not a pedagogical one.

sumMax also determines the generator's candidate operand alphabet: every power of ten up to sumMax. A recipe with sumMax: 99 can produce steps in the ones and the tens; sumMax: 9 can only produce steps in the ones. You do not configure that alphabet directly — you narrow it with rules, as Restricting places describes.

Why it is a recipe field, not a rule ​

It is fair to ask why sumMax is not simply a constraint rule such as current_sum <= 99.

The generator proves feasibility before it searches. That analysis is a dynamic program indexed by (layer, sum), and it allocates its working arrays before any rule is evaluated — it has to know the width of the sum axis up front. A rule cannot size an allocation; it can only narrow a domain that already exists.

So the division of labour is:

  • sumMax establishes the domain. Structural, authored on the recipe.
  • A rule referencing current_sum narrows that domain further. It can never widen it.

Writing current_sum <= 500 on a recipe with sumMax: 99 does nothing. Writing current_sum <= 19 on a recipe with sumMax: 99 genuinely tightens the ceiling — with one important caveat, below.

Confining sums to a narrower window ​

Suppose you want every running sum inside 0..19. The obvious move is to set sumMax: 19 and be done, and for most recipes that is exactly right.

But when you want a window narrower than the recipe's sumMax — or a floor above the structural 0 — you reach for a step-scope constraint rule. The naive version is not enough:

current_sum >= 0 AND current_sum <= 19

This is incomplete. current_sum is prev_sum + current_value: it describes the state after the step is applied. It says nothing about where the exercise started.

current_sum alone does not bound the opening value

current_sum constrains transitions only. With just the current_sum bound above, exercises were measured opening on start values well outside the window — 16 of 40 generated exercises opened above 19 (on values such as 26 and 22), with the first step dropping into range from outside it. Every individual transition satisfied the rule; the opening was never a transition.

The fix is to bound the previous sum as well:

current_sum >= 0 AND current_sum <= 19 AND prev_sum <= 19

prev_sum <= 19 is not redundant with current_sum <= 19. The two clauses close different holes:

ClauseRejects
current_sum <= 19a step that would land above the window
prev_sum <= 19a step taken from a position already above the window — including the very first step, whose prev_sum is the opening value

With both clauses in place the same measurement produced 0 of 40 exercises opening outside 0..19.

This is the concrete technique for a recipe teaching carries into the tens, where sums must stay in 0..19 — a range no fixed digit-count setting could ever express. Either sumMax: 19, or a looser sumMax plus the rule above, works directly.

Prefer sumMax when the window starts at 0

If the window you want is 0..sumMax, set sumMax and skip the rule — the ceiling is already enforced structurally and prunes the search more cheaply. Reach for the constraint rule when you need a floor above 0, or a ceiling below the recipe's sumMax for a subset of situations.

A sum-range rule constrains transitions. If the opening value needs its own shape — a clean tens digit, a zero ones digit — guard on step_index:

IF step_index = 0 THEN digitAt(prev_sum, 1) = 0

See Restricting places for the full treatment of opening-value pinning, and Variables for how prev_sum, current_value, and current_sum relate.

Sum rules and place channels ​

A rule attached to a place-channel (place: 1, 10, 100, 1000) cannot reference current_sum, and compilation rejects it if it does. Inside a channel, current_sum would mean "prev_sum plus that one channel's digit" — an intermediate state a composite step never actually passes through, because it commits every channel together.

Whole-step sum conditions belong on an ordinary global attachment (place: 0) with usage: constraint. Written that way, a sum rule works unchanged on recipes that produce composite steps. See Multi-place combo steps.

See also ​

Reference and cookbook for mental-math rule and recipe authoring.