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 xiαix_i^{\alpha_i}.

Mathematical background

For an element aa of a monoid with unit 11 and e∈Ne \in \mathbb{N}, aea^e is the ee-fold product, a0=1a^0 = 1. Writing ee in binary, e=∑jbj2je = \sum_j b_j 2^j, gives

ae=∏j:bj=1a2j,a^e = \prod_{j : b_j = 1} a^{2^j},

and the factors a2ja^{2^j} are obtained by repeated squaring.

Design decisions

Binary exponentiation with an explicit loop invariant

pow_nat keeps three values, state, exp and factor, initially 11, ee and aa, and maintains

state⋅factorexp=ae.\text{state} \cdot \text{factor}^{\text{exp}} = a^e .

Each step with exp≥2\text{exp} \ge 2 replaces (state,exp,factor)(\text{state}, \text{exp}, \text{factor}) by (state⋅factorb,⌊exp/2⌋,factor2)(\text{state}\cdot\text{factor}^{b}, \lfloor \text{exp}/2 \rfloor, \text{factor}^2) where b=exp mod 2b = \text{exp} \bmod 2. The invariant is preserved:

state⋅factorb⋅(factor2)⌊exp/2⌋=state⋅factor b+2⌊exp/2⌋=state⋅factorexp=ae.\begin{aligned} \text{state}\cdot\text{factor}^{b} \cdot (\text{factor}^2)^{\lfloor \text{exp}/2 \rfloor} &= \text{state}\cdot\text{factor}^{\,b + 2\lfloor \text{exp}/2 \rfloor} \\ &= \text{state}\cdot\text{factor}^{\text{exp}} = a^e . \end{aligned}

The loop stops at exp=0\text{exp} = 0 with result state, or at exp=1\text{exp} = 1 with result state⋅factor\text{state}\cdot\text{factor}; in both cases the invariant gives aea^e. exp halves each step, so there are ⌊log⁡2e⌋\lfloor \log_2 e \rfloor squarings. All multiplied values are powers of aa, 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^e for associative *; with u the unit this is aea^e.
  • e=0e = 0 returns one without multiplying, so 00=10^0 = 1.
  • At most 2⌊log⁡2e⌋+12\lfloor\log_2 e\rfloor + 1 multiplications.

Alternatives rejected

  • Repeated multiplication, e−1e - 1 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.