diff --git a/research/gaussian-schur-fill-sign/PROOF.md b/research/gaussian-schur-fill-sign/PROOF.md new file mode 100644 index 0000000000..f69ad9341b --- /dev/null +++ b/research/gaussian-schur-fill-sign/PROOF.md @@ -0,0 +1,157 @@ +# Noncancellation and signs of truncated Gaussian Schur fill + +This contribution was produced by Nick Petalas. + +## Statement + +Let n>=1 and b>=1 be integers, and let 0=1) t^(r^2) + <= 2 sum_(r>=1) t^(2r-1) + = 2t/(1-t^2) <= 3/4 < 1. + +Consequently P(z_j) has sign (-1)^(j+b). The 2b+1 evaluation points +are distinct, ordered negative reals, and their signs alternate. Each of +the 2b disjoint consecutive intervals contains a root by continuity. +Since the degree is 2b, these roots are all the roots and are simple. +Write them as -lambda_1,...,-lambda_(2b), with every lambda_r>0. Then + + P(z) = t^(b^2) product_(r=1)^(2b) (z+lambda_r). + +This elementary sufficient range is all that is needed. No optimal +root-realness threshold is claimed. + +## 2. Exactly which ordered minors are positive + +Consider the same kernel on all integer indices. Let T be the shift with +T[i,j]=1 when i=j+1. Its formal Laurent polynomial representation is + + G = t^(b^2) T^(-b) product_r (lambda_r I + T). + +Every entry involves only 2b steps, so this identity requires no convergence +or infinite matrix multiplication. A path starts at column c, takes 2b +steps, each staying put with weight lambda_r or increasing by one with +weight one, and finishes at row r+b. All weights are positive. + +For increasing row and column lists R=(r_1,...,r_d) and C=(c_1,...,c_d), +expand det G[R,C] as a signed sum of path families. Families with an +intersection cancel in pairs: choose their first intersection by a fixed +ordering and exchange the two path tails. This preserves their weight, +reverses the endpoint permutation and is an involution. A family without +intersections preserves the order of its starts and ends, so it contributes +with positive sign. Therefore the minor is nonnegative. + +Such a family can exist only if + + -b <= r_l-c_l <= b for every l. (1) + +Conversely suppose (1) holds. At time s=0,...,2b give path l position + + x_l(s) = max(c_l, r_l+b-(2b-s)). + +It starts at c_l and ends at r_l+b. Every increment is zero or one. +For each fixed s the positions strictly increase with l, since both +arguments of the maximum strictly increase. These paths never intersect. +Their positive weight proves the exact minor criterion + + det G[R,C] > 0 iff |r_l-c_l|<=b for every l; + otherwise det G[R,C] = 0. (2) + +The cancellation argument and bidiagonal path factorization are classical +techniques; no claim of their invention is made here. The proof above is +included so that the specific strictness and support conclusions do not +rely on a quoted total-positivity theorem. + +Taking R=C in (2) proves positivity of every principal determinant, +including all eliminated pivots. + +## 3. Schur entries and their signs + +List E in increasing order, and append i to its row list and j to its +column list. The block determinant formula gives + + S[i,j] = det G[(E,i),(E,j)] / det G[E,E]. + +Sorting both appended lists changes the numerator sign by + + (-1)^(#{e in E:e>i} + #{e in E:e>j}). + +For i0. + +The chain condition is equivalent to structural fill in the bandwidth-b +path graph. If it holds, the chain itself is a path with eliminated internal +vertices. If a gap is larger than b, no such path can cross the cut between +these consecutive available vertices, even using eliminated vertices outside +the endpoint interval. Thus every structurally possible fill is present, +without any generic-entry qualification, in this restricted real Gaussian +family. This supplies the missing actual-entry conclusion; the structural +bandwidth formulas of PR4373/4407 remain predecessor results. + +## 4. Positive gauges + +For H=D_left G D_right with positive diagonal factors, direct substitution +into the Schur formula gives + + Schur_E(H) = D_left[V,V] S D_right[V,V]. + +Every multiplier on an entry is positive. This proves the stated gauge +corollary without bounding any gauge's condition number or physical cost. + +## Scope and first example + +For n=12, b=3, t=1/3 and E={4,5,6,7}, the entry between 1 and 10 is +exactly 1/9170703360, at survivor-order distance five. The four intervening +eliminated vertices give positive sign. This is a new Gaussian fixture, +not a replay of James Reed's equal-weight path. + +Only the restricted real kernel and its positive scalings have been proved. +The unrestricted t range, a concrete caller's admissibility, periodic +kernels, finite-precision stability, physical routines and supplier admission +remain outside this theorem. No new kappa or selected-frontier change. +Independent human and formal proof-kernel review are unclaimed. diff --git a/research/gaussian-schur-fill-sign/README.md b/research/gaussian-schur-fill-sign/README.md new file mode 100644 index 0000000000..ea04de57ac --- /dev/null +++ b/research/gaussian-schur-fill-sign/README.md @@ -0,0 +1,111 @@ +# Exact signs and noncancellation of real Gaussian Schur fill + +This contribution was produced by Nick Petalas. + +For every bandwidth b>=1 and every finite linear path, truncate the real +Gaussian kernel t^((i-j)^2) to |i-j|<=b. If 0 b for u, v in zip(chain, chain[1:])): + return 0 + return (-1) ** len(between) + + +def check_root_signs(): + evaluations = 0 + for t in (Fraction(1, 3), Fraction(1, 4)): + require(2*t/(1-t*t) <= Fraction(3, 4), "root dominance") + for b in range(1, MAX_B + 1): + for j in range(-b, b + 1): + z = -(t ** (-2*j)) + value = Fraction(0) + for h in range(b, -b - 1, -1): + value = value*z + t ** (h*h) + require(value * (-1)**(j+b) > 0, "root isolation sign") + evaluations += 1 + return evaluations + + +def check_minors(): + counts = {"minors": 0, "positive": 0, "zero": 0, "paths": 0} + for t in (Fraction(1, 3), Fraction(1, 4)): + for b in range(1, 4): + a = kernel(6, b, t) + for size in range(1, 7): + subsets = list(combinations(range(6), size)) + for rows in subsets: + for columns in subsets: + expected = all(abs(r-c) <= b for r, c in zip(rows, columns)) + value = determinant(minor(a, rows, columns)) + require(value >= 0 and (value > 0) == expected, "ordered minor") + counts["minors"] += 1 + counts["positive" if value > 0 else "zero"] += 1 + if expected: + path = [[max(c, r+b-(2*b-s)) for r, c in zip(rows, columns)] + for s in range(2*b + 1)] + require(path[0] == list(columns), "path starts") + require(path[-1] == [r+b for r in rows], "path ends") + require(all(x < y for row in path for x, y in zip(row, row[1:])), + "path collision") + require(all(path[s+1][k]-path[s][k] in (0, 1) + for s in range(2*b) for k in range(size)), "path step") + counts["paths"] += 1 + return counts + + +def check_schurs(): + counts = {"layouts": 0, "entries": 0, "positive": 0, "negative": 0, "zero": 0} + for t in (Fraction(1, 3), Fraction(1, 4)): + for b in range(1, 4): + for n in range(1, 9): + a = kernel(n, b, t) + for mask in range(2**n - 1): + e = [i for i in range(n) if mask >> i & 1] + require(determinant(minor(a, e, e)) > 0, "principal determinant") + survivors, s = schur(a, e) + counts["layouts"] += 1 + for r, i in enumerate(survivors): + for c, j in enumerate(survivors): + expected = predicted_sign(i, j, e, b) + actual = (s[r][c] > 0) - (s[r][c] < 0) + require(actual == expected, "Schur support/sign") + counts["entries"] += 1 + counts[{1: "positive", -1: "negative", 0: "zero"}[actual]] += 1 + return counts + + +def check_fixture_and_controls(): + a = kernel(12, 3, Fraction(1, 3)) + e = [4, 5, 6, 7] + v, s = schur(a, e) + value = s[v.index(1)][v.index(10)] + require(value == Fraction(1, 9170703360), "first Gaussian fixture") + require(v.index(10)-v.index(1) == 5, "boundary distance") + left = [Fraction(i+1) for i in range(12)] + right = [Fraction(1, i+2) for i in range(12)] + gauged = [[left[i]*a[i][j]*right[j] for j in range(12)] for i in range(12)] + w, gs = schur(gauged, e) + require(w == v and all(gs[r][c] == left[i]*s[r][c]*right[j] + for r, i in enumerate(v) for c, j in enumerate(v)), "positive gauges") + rejected = 0 + for args in ((0, 1, Fraction(1, 3)), (13, 1, Fraction(1, 3)), + (3, 0, Fraction(1, 3)), (3, 13, Fraction(1, 3)), + (3, 1, Fraction(0)), (3, 1, Fraction(1, 2))): + try: + kernel(*args) + except ValueError: + rejected += 1 + require(rejected == 6, "boundary rejections") + require(determinant([[Fraction(1), Fraction(1)], [Fraction(1), Fraction(1)]]) == 0, + "unrestricted-t singular control") + require(predicted_sign(0, 2, [], 1) == 0 and Fraction(1, 3)**4 > 0, + "truncation is essential") + require(predicted_sign(0, 2, [1], 1) == -1, "interior parity is essential") + return {"first_entry": str(value), "boundary_distance": 5, "rejections": rejected, + "scope_controls": 3, "positive_gauges": 1} + + +def main(): + require(len(sys.argv) == 1, "no command-line arguments accepted") + result = {"root_evaluations": check_root_signs(), "minor_checks": check_minors(), + "schur_checks": check_schurs(), "fixtures": check_fixture_and_controls()} + package = Path(__file__).resolve().parent + names = ("PROOF.md", "README.md", "SOURCES.json", "TASK.json", "VERIFY.json", "verify.py") + result["package_sha256"] = {name: sha256((package / name).read_bytes()).hexdigest() + for name in names} + result["python"] = platform.python_version() + print(json.dumps(result, sort_keys=True)) + print("PASS_GAUSSIAN_SCHUR_FILL_SIGN t<=1/3 first_entry=1/9170703360 no_new_kappa") + + +if __name__ == "__main__": + main()