From 6f87acd840f31a092238ecf7e5c455289430878a Mon Sep 17 00:00:00 2001 From: Nick Petalas Date: Tue, 27 Oct 2026 16:13:14 +0000 Subject: [PATCH] feat(research): sharpen width by multiplicative rank --- research/semigroup-rank-width/PROOF.md | 119 +++++++++ research/semigroup-rank-width/README.md | 147 +++++++++++ research/semigroup-rank-width/SOURCES.json | 24 ++ research/semigroup-rank-width/TASK.json | 101 ++++++++ research/semigroup-rank-width/VERIFY.json | 34 +++ research/semigroup-rank-width/verify.py | 288 +++++++++++++++++++++ 6 files changed, 713 insertions(+) create mode 100644 research/semigroup-rank-width/PROOF.md create mode 100644 research/semigroup-rank-width/README.md create mode 100644 research/semigroup-rank-width/SOURCES.json create mode 100644 research/semigroup-rank-width/TASK.json create mode 100644 research/semigroup-rank-width/VERIFY.json create mode 100644 research/semigroup-rank-width/verify.py diff --git a/research/semigroup-rank-width/PROOF.md b/research/semigroup-rank-width/PROOF.md new file mode 100644 index 0000000000..2bffda1cd5 --- /dev/null +++ b/research/semigroup-rank-width/PROOF.md @@ -0,0 +1,119 @@ +# A multiplicative-rank refinement of chronological width + +## Statement + +Use exactly the fixed default-height rule, chronological batches and integer +width recurrence of codyw912's [PR #4638](https://github.com/CrocSwap/integer-mult-bounds/pull/4638), +`research/chronological-width-bound`, sections 1-4. In particular the target +ranks have positive integer multiplicities W_k, paid ranks have positive +integer multiplicities P_j, and + +``` +2 <= k_min <= k <= m = max(target ranks), +1 <= j <= j_max < m, +W = sum W_k, P = sum P_j. +``` + +Base widths below m are one. At rank n >= m the cap is floor(n/m) and +the height is floor(log_(k_min)(floor(n/m))). Let A be the set of all target +and paid ranks. Rank one is permitted and contributes a zero valuation vector. +Let Pi be the prime support of A and d its size. Form the integer matrix + +``` +V = (v_p(a)) with rows p in Pi and columns a in A, +r = rank_Q(V). +``` + +Then 1 <= r <= d, and the same width sequence satisfies + +\[ +\log B_N=O((\log N)^{r+1}). +\] + +The constant depends on the fixed rule. This replaces d+1 in #4638 by r+1. +The degree strictly decreases when the valuation vectors span a proper +subspace of Q^d. It is an upper bound and does not assert a matching lower +bound for the actual widths. + +## The new counting lemma + +Let Gamma be the multiplicative semigroup generated by A, including one. +Choose a set I of r prime coordinates whose r rows of V are independent. +Such rows exist by the definition of rank. Projection to those coordinates +is injective on the column space U of V. Indeed its restriction has rank r, +equal to dim U, so its kernel is zero. + +For x in Gamma, the complete valuation vector v(x) belongs to U. If two +products x,y have the same valuations at the primes in I, injectivity gives +v(x)=v(y) at every prime in Pi. Unique prime factorization gives x=y. +This argument does not require a unique expression as a product of generators. + +For 1 <= x <= X, each selected coordinate is an integer in +[0,floor(log_p X)]. Therefore + +\[ +|\Gamma\cap[1,X]| +\le\prod_{p\in I}(1+\lfloor\log_p X\rfloor) +\le(1+\lfloor\log_2 X\rfloor)^r. \tag{1} +\] + +The selected-prime box can contain vectors outside the projected semigroup. +Surjectivity is unnecessary. Selecting arbitrary r primes is insufficient; +their rows must be independent on U. For example projecting the semigroup +generated by 6 and 10 only to the 3-adic coordinate identifies 1 and 10. + +## Application to the inherited width divisor + +The following facts are cited from #4638, sections 2-4, rather than +re-established by a source replay here. Source counts S(gamma) are constant +on Gamma plateaus. At cap C their bound is + +\[ +1\le S(\gamma)\le W(W+P)^G, +\qquad G=\lfloor\log_{k_{\min}} C\rfloor. +\] + +Every recursive child has rank at most alpha=(m-1)/m times its parent rank. +With tau=m ceil(log_2 k_min), every descending rank chain visits each plateau +at most tau times. For every N >= m, this yields the all-prime divisor + +\[ +B_n\mid Q_N= +\prod_{\substack{\gamma\in\Gamma\\\gamma\le C}} S(\gamma)^\tau, +\qquad C=\lfloor N/m\rfloor,\quad 0\le n\le N. \tag{2} +\] + +The prime factors of S(gamma) need not belong to Pi. Equation (2) retains +all of them. The new projection is used only to count plateau locations; +it does not discard any source-count or width prime. + +Combining (1) and (2) gives the explicit new estimate + +\[ +\log_2 B_n\le +\tau\prod_{p\in I}(1+\lfloor\log_p C\rfloor) +\bigl(\log_2 W+G\log_2(W+P)\bigr),\quad n\le N. \tag{3} +\] + +There are O((log N)^r) box points, and the final factor is O(log N). +This proves the stated all-rank bound. Replacing the two logarithms in the +last factor by their integer ceilings gives a computable integer exponent +b_N with B_n <= 2^b_N. All width and chronological correctness premises +are unchanged. No assumption that gcd cancellation is small or absent is used. + +## A strict degree improvement + +Take target multiplicities W_6=W_36=1 and paid multiplicities P_1=P_6=1. +This is an admissible rank pattern for the integer recurrence, since 6<36. +No physical native rule realizing it is asserted. Its prime support is {2,3}, +but its valuation columns are (1,1), (2,2) and (0,0), of rational rank one. +The old width theorem gives log B_N=O((log N)^3); (3) gives +log B_N=O((log N)^2) for this same recurrence. + +The semigroup is exactly {6^j:j>=0}, so its exact plateau count is +1+floor(log_6 C). This example witnesses a strict decrease of the proved +upper-bound degree, not a measured asymptotic separation between two +width sequences. This contribution changes no sequence. + +The first proved refinement is the finish line. Adaptive heights, optimal +coordinate choices and sharper actual-width growth are left open. diff --git a/research/semigroup-rank-width/README.md b/research/semigroup-rank-width/README.md new file mode 100644 index 0000000000..22d11704e0 --- /dev/null +++ b/research/semigroup-rank-width/README.md @@ -0,0 +1,147 @@ +# Chronological width in the multiplicative rank + +For the fixed default-height chronological compiler of +[codyw912's PR #4638](https://github.com/CrocSwap/integer-mult-bounds/pull/4638), +let d count primes dividing target or paid ranks, and let r be the rational +rank of their prime-valuation vectors. The same width sequence satisfies + +``` +Previous upper bound: log B_N = O((log N)^(d+1)) +New upper bound: log B_N = O((log N)^(r+1)), r <= d. +``` + +This answers the exponent-lattice refinement in #4638's first Open next +question. A projection to r independent prime coordinates is injective on +the rank semigroup. Its selected-prime exponent box therefore bounds the +number of source-count plateaus. [PROOF.md](PROOF.md) gives the quantified +argument and the resulting explicit integer bit envelope. + +This is a **scoped conditional all-rank proof**, with finite exact +corroboration. It changes neither the compiler nor its width sequence. +It gives a strictly smaller upper-bound degree when r=0}. No physical native supplier for this +pattern is asserted. The finite checker at cap 46656 finds its seven +semigroup elements. The generic selected-prime box has 16 points, and the +explicit conservative width exponent is 22464. These are different quantities. + +## Evidence and scope + +The independently written standard-library checker imports no predecessor +program and replays no predecessor census. It checks: + +- Every one-, two- and three-element subset of {1,...,12}, at caps 1, 7, 64 + and 257, plus four larger discriminating fixtures at cap 46656. +- Exact semigroup equality between bounded generator multiplication and an + independent integer-by-integer divisibility oracle, projection injectivity, + the selected-prime box bound and the full-prime comparison. +- Rational elimination ranks against independent nonzero-minor enumeration + using the Leibniz determinant formula, for every fixture. +- Thirteen rejecting controls and two further semantic comparisons, including + a rank-deficient coordinate choice, omitting a paid-rank prime and an + actual collision under an insufficient projection. + +Executed output on CPython 3.12.15: + +``` +PASS_SEMIGROUP_RANK_WIDTH +fixtures=1196 enumerated_members=7641 strict_rank_reductions=186 controls=15 +``` + +The member count sums occurrences across fixtures; it is not a count of +distinct integers across the whole run. The 186 counts fixtures with r remainder: + break + for _ in range(20): + if remainder % divisor: + break + result[divisor] = result.get(divisor, 0) + 1 + remainder //= divisor + if remainder > 1: + result[remainder] = result.get(remainder, 0) + 1 + require(prod(p ** e for p, e in result.items()) == value, "factorization") + return result + + +def floor_log(base, value): + require(type(base) is int and base >= 2, "log base") + require(type(value) is int and 1 <= value <= MAX_CAP, "cap range") + power = 1 + exponent = 0 + for _ in range(value.bit_length()): + if power * base > value: + break + power *= base + exponent += 1 + require(power <= value < power * base, "integer logarithm") + return exponent + + +def pivots(matrix): + """Return pivot columns of a rational row matrix.""" + require(len(matrix) <= MAX_GENERATORS, "matrix row capacity") + width = len(matrix[0]) if matrix else 0 + require(width <= 7 * MAX_GENERATORS, "matrix column capacity") + require(all(len(row) == width for row in matrix), "matrix shape") + rows = [[Fraction(x) for x in row] for row in matrix] + columns = [] + for col in range(width): + start = len(columns) + selected = next((i for i in range(start, len(rows)) if rows[i][col]), None) + if selected is None: + continue + rows[start], rows[selected] = rows[selected], rows[start] + scale = rows[start][col] + rows[start] = [x / scale for x in rows[start]] + for i in range(start + 1, len(rows)): + multiplier = rows[i][col] + rows[i] = [x - multiplier * y for x, y in zip(rows[i], rows[start])] + columns.append(col) + return tuple(columns) + + +def certificate(values): + values = alphabet(values) + factors = [factor(value) for value in values] + primes = tuple(sorted({p for row in factors for p in row})) + matrix = tuple(tuple(row.get(p, 0) for p in primes) for row in factors) + coordinates = tuple(primes[i] for i in pivots(matrix)) + return primes, matrix, coordinates + + +def validate_projection(values, coordinates): + primes, matrix, expected = certificate(values) + require(isinstance(coordinates, tuple), "coordinate type") + require(len(set(coordinates)) == len(coordinates), "duplicate coordinate") + require(all(p in primes for p in coordinates), "coordinate outside support") + require(len(coordinates) == len(expected), "coordinate count") + selected = [[row[primes.index(p)] for p in coordinates] for row in matrix] + require(len(pivots(selected)) == len(expected), "projection loses rank") + return True + + +def exponent_at(value, prime): + exponent = 0 + remainder = value + for _ in range(value.bit_length()): + if remainder % prime: + break + exponent += 1 + remainder //= prime + return exponent + + +def semigroup(values, cap): + """Enumerate by multiplying bounded powers of each generator.""" + values = alphabet(values) + floor_log(2, cap) + members = {1} + for generator in values: + if generator == 1: + continue + previous = tuple(members) + for member in previous: + value = member + for _ in range(cap.bit_length()): + if value > cap // generator: + break + value *= generator + members.add(value) + require(len(members) <= cap, "semigroup capacity") + return tuple(sorted(members)) + + +def membership_oracle(values, cap): + """Independent integer-by-integer divisibility recurrence.""" + reachable = [False] * (cap + 1) + reachable[1] = True + for value in range(2, cap + 1): + reachable[value] = any(g > 1 and value % g == 0 and reachable[value // g] + for g in values) + return tuple(i for i in range(1, cap + 1) if reachable[i]) + + +def determinant(matrix): + """Leibniz determinant, limited to minors of order at most three.""" + size = len(matrix) + require(size <= 3 and all(len(row) == size for row in matrix), "minor size") + result = 0 + for indices in product(range(size), repeat=size): + if len(set(indices)) != size: + continue + inversions = sum(indices[i] > indices[j] for i in range(size) + for j in range(i + 1, size)) + result += (-1) ** inversions * prod(matrix[i][indices[i]] for i in range(size)) + return result + + +def minor_rank(matrix): + require(len(matrix) <= 3, "minor oracle row capacity") + width = len(matrix[0]) if matrix else 0 + result = 0 + for size in range(1, min(len(matrix), width) + 1): + for rows in combinations(range(len(matrix)), size): + for cols in combinations(range(width), size): + if determinant([[matrix[i][j] for j in cols] for i in rows]): + result = size + return result + + +def check_fixture(values, cap): + primes, matrix, coordinates = certificate(values) + require(validate_projection(values, coordinates), "projection validation") + members = semigroup(values, cap) + require(members == membership_oracle(values, cap), "semigroup oracle") + images = {tuple(exponent_at(x, p) for p in coordinates) for x in members} + require(len(images) == len(members), "projection collision") + bound = prod(1 + floor_log(p, cap) for p in coordinates) + full_box = prod(1 + floor_log(p, cap) for p in primes) + require(len(members) <= bound <= full_box, "box bound") + require(minor_rank(matrix) == len(coordinates), "independent minor rank") + return len(members), len(coordinates) < len(primes) + + +def width_envelope(targets, paid, cap): + require(isinstance(targets, dict) and isinstance(paid, dict), "profile type") + alphabet(tuple(targets)) + alphabet(tuple(paid)) + require(min(targets) >= 2 and max(paid) < max(targets), "profile rank order") + require(all(type(v) is int and 1 <= v <= 1000 + for v in (*targets.values(), *paid.values())), "multiplicity range") + _, _, coordinates = certificate(tuple(targets) + tuple(paid)) + w, p = sum(targets.values()), sum(paid.values()) + height = floor_log(min(targets), cap) + tau = max(targets) * (min(targets) - 1).bit_length() + box = prod(1 + floor_log(prime, cap) for prime in coordinates) + bits = tau * box * ((w - 1).bit_length() + height * (w + p - 1).bit_length()) + return {"prime_coordinates": list(coordinates), "rank": len(coordinates), + "height": height, "tau": tau, "plateau_box": box, "log2_width_bound": bits} + + +def must_reject(operation, message): + try: + operation() + except ValueError as exc: + require(str(exc) == message, "unexpected rejection: " + str(exc)) + return + raise ValueError("control accepted: " + message) + + +def check_controls(): + controls = [ + (lambda: alphabet([]), "alphabet capacity"), + (lambda: alphabet([2] * 17), "alphabet capacity"), + (lambda: alphabet([True]), "generator range"), + (lambda: alphabet([0]), "generator range"), + (lambda: alphabet([MAX_GENERATOR + 1]), "generator range"), + (lambda: semigroup([2], MAX_CAP + 1), "cap range"), + (lambda: floor_log(1, 2), "log base"), + (lambda: validate_projection([6, 10], (3,)), "coordinate count"), + (lambda: validate_projection([6, 10, 15], (2, 2, 3)), "duplicate coordinate"), + (lambda: validate_projection([6, 10, 15], (2, 3, 7)), "coordinate outside support"), + (lambda: validate_projection([2, 15], (3, 5)), "projection loses rank"), + (lambda: width_envelope({2: 1}, {2: 1}, 16), "profile rank order"), + (lambda: width_envelope({6: True}, {1: 1}, 16), "multiplicity range"), + ] + for operation, message in controls: + must_reject(operation, message) + require(exponent_at(1, 3) == exponent_at(10, 3), "bad-coordinate collision") + require(len(certificate([2, 4])[2]) == 1 and + len(certificate([2, 3, 4])[2]) == 2, "omitted paid rank control") + return len(controls) + 2 + + +def run_checks(): + fixtures = members = strict = 0 + for size in range(1, 4): + for values in combinations(range(1, 13), size): + for cap in (1, 7, 64, 257): + count, reduction = check_fixture(values, cap) + fixtures += 1 + members += count + strict += reduction + witnesses = [] + for values in ((1, 6, 36), (6, 10, 60), (12, 18), (6, 10, 15)): + count, reduction = check_fixture(values, 46_656) + primes, _, coordinates = certificate(values) + witnesses.append({"generators": list(values), "cap": 46_656, + "members": count, "prime_count": len(primes), + "rank": len(coordinates), "coordinates": list(coordinates)}) + fixtures += 1 + members += count + strict += reduction + envelope = width_envelope({6: 1, 36: 1}, {1: 1, 6: 1}, 46_656) + require(envelope["rank"] == 1 and envelope["plateau_box"] == 16, + "width witness projection") + require(envelope["height"] == 6 and envelope["tau"] == 108 and + envelope["log2_width_bound"] == 22_464, "width envelope arithmetic") + require(semigroup([1, 6, 36], 46_656) == tuple(6 ** i for i in range(7)), + "rank-one exact semigroup") + return {"fixtures": fixtures, "enumerated_members": members, + "strict_rank_reductions": strict, "controls": check_controls(), + "witnesses": witnesses, "width_witness": envelope} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--record", type=Path, help="create a new hash-bound receipt") + args = parser.parse_args() + result = run_checks() + package = Path(__file__).resolve().parent + names = ("README.md", "PROOF.md", "TASK.json", "SOURCES.json", "VERIFY.json", "verify.py") + hashes = {name: hashlib.sha256((package / name).read_bytes()).hexdigest() for name in names} + receipt = {"schema_version": 1, "python": platform.python_version(), + "package_sha256": hashes, "result": result} + if args.record is not None: + with args.record.open("x", encoding="utf-8") as stream: + stream.write(json.dumps(receipt, indent=2, sort_keys=True) + "\n") + print("PASS_SEMIGROUP_RANK_WIDTH " + json.dumps(result, sort_keys=True)) + + +if __name__ == "__main__": + main()