internal design
Design goal
internal keeps code that several representation packages need, but that is not part of the public surface, in one place. Today it contains a single function, the natural-power routine behind every pow and every evaluation of .
Mathematical background
For an element of a monoid with unit and , is the -fold product, . Writing in binary, , gives
and the factors are obtained by repeated squaring.
Design decisions
Binary exponentiation with an explicit loop invariant
pow_nat keeps three values, state, exp and factor, initially , and , and maintains
Each step with replaces by where . The invariant is preserved:
The loop stops at with result state, or at with result ; in both cases the invariant gives . exp halves each step, so there are squarings. All multiplied values are powers of , which commute with each other, so only associativity of * is used.
The unit is a parameter
The unit is passed as one~ instead of being taken from a One instance. Callers already know their unit (DensePolynomial::one(), One::one() for coefficients), and the helper then needs only Mul, which keeps its bound minimal.
Correctness / invariants
pow_nat(a, e, one=u) = u · a^efor associative*; withuthe unit this is .- returns
onewithout multiplying, so . - At most multiplications.
Alternatives rejected
- Repeated multiplication, products, is too slow for polynomial powers.
- A trait method on each representation would duplicate the loop four times.
Boundaries
- Not importable outside
luna-poly. - Natural exponents only; no negative powers and no modular exponentiation.
- The cost of each multiplication is the caller’s: for polynomials the final squaring dominates.