From e833fa110cb6cb878a1e95680d4957b2638b29a8 Mon Sep 17 00:00:00 2001 From: Nick Petalas Date: Thu, 29 Oct 2026 13:12:49 +0000 Subject: [PATCH] feat(research): construct unbounded rank-metric shear bicliques --- research/unbounded-shear-bicliques/PROOF.md | 109 ++++++++++ research/unbounded-shear-bicliques/README.md | 103 ++++++++++ .../unbounded-shear-bicliques/SOURCES.json | 24 +++ research/unbounded-shear-bicliques/TASK.json | 79 ++++++++ .../unbounded-shear-bicliques/VERIFY.json | 34 ++++ research/unbounded-shear-bicliques/verify.py | 191 ++++++++++++++++++ 6 files changed, 540 insertions(+) create mode 100644 research/unbounded-shear-bicliques/PROOF.md create mode 100644 research/unbounded-shear-bicliques/README.md create mode 100644 research/unbounded-shear-bicliques/SOURCES.json create mode 100644 research/unbounded-shear-bicliques/TASK.json create mode 100644 research/unbounded-shear-bicliques/VERIFY.json create mode 100644 research/unbounded-shear-bicliques/verify.py diff --git a/research/unbounded-shear-bicliques/PROOF.md b/research/unbounded-shear-bicliques/PROOF.md new file mode 100644 index 0000000000..d06f8999fe --- /dev/null +++ b/research/unbounded-shear-bicliques/PROOF.md @@ -0,0 +1,109 @@ +# Unbounded bipartite contacts in fixed rational shear dimension + +This scoped construction and proof were produced by Nick Petalas. + +## Statement + +For a rational 2-by-2 matrix M, put + +```text +Phi(M) = [[I_2, M], [0, I_2]], +d(Phi(M), Phi(N)) = rank_Q(Phi(N) - Phi(M)) = rank_Q(N-M). +``` + +For arbitrary finite sets T,A of distinct rational parameters within each set, +define + +```text +E(t) = [[t, t^2], [1, t]], t in T, +O(a) = [[a, a^2], [0, -a]], a in A. +``` + +The metric on their |T|+|A| shear operators is the shortest-path metric of +the complete bipartite graph K_(|T|,|A|), provided both sets are nonempty. +Every cross distance is one and every distinct same-part distance is two. +The two sets of operators are disjoint even if T and A overlap. + +In particular, K_(n,n) occurs in 4-by-4 commuting integral shear operators +for every positive integer n. For T=A={0,...,n-1}, all matrix entries, +including those of the inverse shears, have magnitude at most +max(1,(n-1)^2). Matrix dimension stays fixed, but coefficient storage does not. + +## Proof of the new realization + +Direct subtraction gives the nonzero rank-one factorization + +```text +E(t)-O(a) = [[t-a, (t-a)(t+a)], [1, t+a]] + = column(t-a, 1) row(1, t+a). +``` + +The entry in position (2,1) is always one. Thus the difference has rank +exactly one, including when t=a. In particular, the two label families +never meet. + +Within each family, + +```text +det(E(t)-E(s)) = (t-s)^2, +det(O(a)-O(b)) = -(a-b)^2. +``` + +Distinct rational parameters make these determinants nonzero. Therefore +the rank is two within either part and one across the parts. These are +exactly the graph distances of a nonempty complete bipartite graph. + +Block multiplication gives + +```text +Phi(M) Phi(N) = Phi(M+N) = Phi(N) Phi(M), +Phi(M)^(-1) = Phi(-M). +``` + +The nonzero block of Phi(N)-Phi(M) is N-M, so its rank is unchanged. +This transfers every label distance to the stated operator distance. +Choosing integer parameters from zero to n-1 proves the integral and +coefficient-height assertions. This argument proves the statement for all +n; finite fixtures are corroboration rather than an extrapolation. QED. + +## Consequence using the predecessor's distortion theorem + +For a metric d, let c_1(d) be the least D for which an L1 metric rho can +be rescaled to satisfy d <= rho <= D d. Jerry Chen / CubeJerry's +[PR907](https://github.com/CrocSwap/integer-mult-bounds/pull/907), section +"All-size family and sharp distortion", proves + +```text +c_1(K_(n,n)) = 2(n-1)/n, n >= 2. +``` + +That abstract theorem is cited as a predecessor result. Its cut argument +and finite examples are not replayed or claimed as new here. Applying it +to the new realization proves that the actual rational shear rank metric +in fixed operator dimension four has finite subsets with distortion +arbitrarily close to two. This replaces a fixed eight-frame witness with +an unbounded family of actual frames. + +There is also an exact countably infinite example. Take both parameter +sets to be the nonnegative integers. Every finite balanced restriction has +the distortion just cited, so the whole metric has distortion at least +two. Sending every operator to a different unit vector of countable l1 +gives distance two on all distinct pairs. Since the original distances +are one or two, this embedding has distortion at most two. Hence the +countably infinite example has distortion exactly two. + +## Scope + +The rank charge is the declared metric. This proof gives no cheaper +network, changed free operation, nonlinear gate, involutive translation, +native Clifford realization, productive target, or recursive saving. +The shear group is abelian and upper triangular. The separate common-flag +obstruction of navinor's PR825 and the signed-potential restrictions of +Jeremy Diviney's PR836 remain applicable under their own hypotheses. +In particular, failure of an L1 metric premise does not imply a coding gain. + +The inherited multiplication framework, exact caller costs, dirty +restoration, compiler closure, precision and tape implementation are +outside this statement. No selected-frontier change or complete +multiplication theorem is claimed. Literature priority for these elementary +matrix identities is unclaimed. diff --git a/research/unbounded-shear-bicliques/README.md b/research/unbounded-shear-bicliques/README.md new file mode 100644 index 0000000000..6fd50ccfce --- /dev/null +++ b/research/unbounded-shear-bicliques/README.md @@ -0,0 +1,103 @@ +# Unbounded bipartite rank metrics in four-dimensional rational shears + +This construction and scoped proof were produced by Nick Petalas. + +For every n, the following two families realize the distance metric of +K_(n,n) inside commuting 4-by-4 integral shear operators: + +```text +E(t) = [[t,t^2],[1,t]], O(a) = [[a,a^2],[0,-a]], 0 <= t,a < n, +Phi(M) = [[I_2,M],[0,I_2]], d(Phi(M),Phi(N)) = rank_Q(N-M). +``` + +Every cross distance is one; every distinct same-part distance is two. +The [proof](PROOF.md) gives a literal rank-one factorization and the two +within-part determinants. Matrix dimension stays four. Entries have +magnitude at most max(1,(n-1)^2). + +Jerry Chen / CubeJerry's [PR907](https://github.com/CrocSwap/integer-mult-bounds/pull/907) +supplies an eight-frame rational shear example and proves the abstract +formula c_1(K_(n,n))=2(n-1)/n. The new step realizes every size by actual +rational shear frames. Thus their distortion approaches two in fixed +matrix dimension; the countably infinite family has distortion exactly +two. The predecessor's abstract distortion proof is cited, not rechecked. + +Claim type: scoped written construction proof with exact finite +corroboration. There is no new kappa or supplier. This is a changed frame +alphabet side result under `coverage-law-change`; it does not meet that +card's complete paid/productive invoice gate. The selected baseline +orientation passed, but the selected scientific replay was not run. + +## Evidence and reproduction + +Run from the repository root with the recorded CPython 3.12 interpreter: + +```sh +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -I -W error -B research/unbounded-shear-bicliques/verify.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -I -W error -O -B research/unbounded-shear-bicliques/verify.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/research_package.py --package research/unbounded-shear-bicliques +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/check_research_commit.py --package research/unbounded-shear-bicliques --check-source-history +``` + +Another absolute CPython 3.12 path may replace the recorded path. The direct +commands print `PASS_UNBOUNDED_SHEAR_BICLIQUES` in a generated JSON receipt +bound to all six package files. No receipt is handwritten. + +The checker compares determinant-based ranks with independent rational +elimination for every ordered label and 4-by-4 operator pair in thirteen +balanced fixtures, n=2 through 12, 16 and 32, and one 9-by-11 rational +fixture with negative, zero and fractional parameters. There are 8,116 +ordered pairs, 301 explicit factorization/determinant checks, 400 ordered +group-product checks, and ten rejection controls. Controls catch a wrong +square entry, omitted unit, wrong diagonal sign, duplicate parameters and +invalid finite-fixture inputs. Normal and optimized commands preserve +every check. The n=32 realization has distortion 31/16 by PR907. + +## Limits and credit + +This is a rank-metric construction. It supplies no nonlinear circuit, +native physical implementation, complete bill, dirty-input protocol or +recursive gain. The infinite result uses the cited all-n distortion +theorem. The universal construction uses the written determinant proof. +Finite tests alone prove neither universal statement. Independent human +and formal proof-kernel review are unclaimed. No Lean, Docker, full native, +selected-supplier or complete multiplier replay is part of this package. + +PR907 retains its metric/cut theorem and concrete eight-frame credit. +eumemic's PR288 supplies the rational shear framework, navinor's PR825 the +separate common-flag obstruction, and Jeremy Diviney's PR836 the separate +signed-potential restrictions. Their results are neither audited nor +overridden here. No predecessor code is copied. The new contribution is +the unbounded explicit realization and its consequence for this fixed +matrix dimension. Elementary rank and block-matrix identities are standard; +no literature-priority claim is made. Apache-2.0. + +## Open next questions + +1. Can this contact geometry be used in a changed interface that satisfies + every endpoint and has a favorable complete signed bill? First specify + the legal gates, demanded output and paid cleanup. The known common-flag + obstruction must be addressed before searching within its closed model. +2. What coefficient-height growth is necessary for such integral bicliques + at fixed matrix dimension? First compare this quadratic-height + construction with rank-one contact equations under a bounded-entry + constraint. This question concerns representation size, not an assumed + physical saving. + +## Verifier engineering bounds + +The verifier is a standalone standard-library program. All loops range +over fixed fixtures or matrices of order at most four; finite fixture +construction rejects more than 64 parameters per part. It has no +recursion, external dispatch or writes. Runtime checks stay active under +optimization. Each function is shorter than sixty lines. + +Power-of-Ten rule 3 deviation: CPython and Fraction allocate during +arithmetic. Live matrices have at most sixteen rational entries and each +fixture has at most 64 labels in this replay. The checker runs one pair at +a time, so it retains no quadratic matrix collection. Rules 8 and 9 use +ordinary Python entry-point dispatch and bounded negative-control lambdas; +the callable targets are literal functions in this file. Warning-strict +normal and optimized replay, syntax inspection and publication checks +provide the available diagnostics. No separate static analyzer is required +or claimed. diff --git a/research/unbounded-shear-bicliques/SOURCES.json b/research/unbounded-shear-bicliques/SOURCES.json new file mode 100644 index 0000000000..b7785991a9 --- /dev/null +++ b/research/unbounded-shear-bicliques/SOURCES.json @@ -0,0 +1,24 @@ +{ + "schema_version": 1, + "base_commit": "3f0152a32eeebac0df11946dbd50cabe5a7f7839", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "d59b5035e7b4cbaa9d688a1d32dd0d6eb79c466a", + "sha256": "9b8d0eea95b3bf0dfcb7938a732a6439b87a2685dec2a5ab9e525b3b34debbfa" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "3404fbdd5e7529a0674eef26114b5071e4586cec", + "sha256": "ead6cdc9d0af6d58e8a49744d8ec8c7c15e13d2ba93c276c434bcf9b51b93a81" + }, + { + "path": "research/abelian-cayley-metric-scope/README.md", + "usage": "provenance", + "git_blob": "bb598f97cadc32f5da271a1f2da6bb2dc17c469c", + "sha256": "4e74affa1e0239b84da1c8fef25b88aabef8a655047854e04d14d35c981dfac2" + } + ] +} diff --git a/research/unbounded-shear-bicliques/TASK.json b/research/unbounded-shear-bicliques/TASK.json new file mode 100644 index 0000000000..84b5078e41 --- /dev/null +++ b/research/unbounded-shear-bicliques/TASK.json @@ -0,0 +1,79 @@ +{ + "schema_version": 1, + "task_id": "coverage-law-change", + "priority_revision": 8, + "base_commit": "3f0152a32eeebac0df11946dbd50cabe5a7f7839", + "original_card": { + "id": "coverage-law-change", + "question": "Can a completed call earn more independent productive target credit without an offsetting paid bill?", + "starting_points": [ + "docs/research/current-priorities.md", + "docs/research/research-family-status.md", + "certificates/selected-result.json", + "docs/research/pr-intake-evidence/pr5599-completion/PROOF-REVIEW.md" + ], + "methods": [ + "Construct and independently check one source-bound instance of the stated first experiment.", + "Seek an exact counterexample or target-specific complete-budget obstruction to that same proposed change." + ], + "acceptance_gate": "A source-bound arbitrary-input identity and legal producer/consumer boundary with the complete paid and productive target invoice, including restoration, ownership, native alignment and extra charges. Price under the actual current model; historical ceiling.py assumptions must be established before use. A favorable optimistic relaxation keeps a route open but is not a completed supplier. A scoped local result remains useful; expansion requires the family-level budget gate.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_selected_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read revision 8, the selected review and live exact-source handoffs. Then follow this card's bounded first_experiment.", + "scope": "Source-bound orientation only, not a supplier replay or theorem proof." + }, + "first_experiment": "Use #5599 as a completed positive control, then choose one uncovered cut/module beyond an applicable frozen exclusion. Derive independence, saturation and chronological availability rather than counting rational rank alone. Price target credits and all new jobs together, then check compiler and actual caller compatibility. Stop on a nonphysical credit or an unfavorable complete relaxation.", + "bottleneck_link": "Judge the actual current supplier contract and complete signed target/paid bill; frozen-profile ceilings require an applicability proof.", + "allowed_variations": [ + "One exact source head, helper/cut region or quantified proposition and changed hypothesis; check live handoffs first. Different seeds are not different scopes." + ], + "scope_change_triggers": [ + "Changing source head, helper/cut domain, operation alphabet or caller boundary without recording the new scope.", + "Treating an archived proposal or local numerical pass as complete supplier admission." + ], + "overlap_terms": [ + "target credit", + "helper split", + "coverage law" + ], + "existing_checks": [ + { + "scope": "Selected PR5599: complete helper-subspace construction and independent caller replay; five framework assumptions remain.", + "evidence": "docs/research/pr-intake-evidence/pr5599-completion/PROOF-REVIEW.md", + "remaining": "The next experiment must identify uncovered source-specific work. Successor archive intake does not transfer this admission.", + "status": "reviewed", + "source_commit": "09dd0965711ca7eeb169057a420abab1c9052137", + "selected_record_sha256": "2a0220e866417774606e0f991e41b9c1d26b1f43b97857238cf478dbc7d330b5" + } + ] + }, + "scope_status": "changed", + "actual_scope": "Construct unbounded complete bipartite rank-distance metrics inside fixed 4-by-4 commuting rational shear operators.", + "scope_change_reason": "The original card asks for a complete productive invoice. This is a side result about a changed frame alphabet, extending PR907 actual-frame realization to all sizes; it does not claim that invoice gate.", + "bottleneck_link": "New contact alphabets need exact geometry before delivery and complete cost analysis. This removes a fixed-cardinality limitation of an existing non-L1 rank-metric example, but the separate common-flag obstruction remains.", + "budget_minutes": 60, + "stop_rule": "Stop at the first exact all-size construction and finite corroboration; do not search circuits or larger savings.", + "outcome": "completed", + "evidence": "PROOF.md gives the all-size determinant proof and a distortion corollary using PR907. verify.py checks exact finite label/operator distances, group identities and rejection controls.", + "author": "Nick Petalas", + "ai_assistance": "Independent human and formal proof-kernel review are unclaimed.", + "open_questions": [ + { + "question": "Can this geometry participate in a changed completed interface with a favorable signed bill?", + "why_it_matters": "A metric example alone earns no productive credit or recursive saving.", + "first_step": "Specify legal gates, demanded endpoints and paid cleanup, and identify the exact hypothesis escaping the known common-flag obstruction.", + "blocked_by": "No changed caller or complete supplier bill is supplied." + }, + { + "question": "What coefficient-height growth is necessary for integral bicliques at fixed matrix dimension?", + "why_it_matters": "Fixed matrix order does not imply constant representation or physical cost.", + "first_step": "Analyze rank-one contact equations with all integral entries bounded in magnitude.", + "blocked_by": "The construction gives a quadratic-height upper bound only." + } + ] +} diff --git a/research/unbounded-shear-bicliques/VERIFY.json b/research/unbounded-shear-bicliques/VERIFY.json new file mode 100644 index 0000000000..dda81fe469 --- /dev/null +++ b/research/unbounded-shear-bicliques/VERIFY.json @@ -0,0 +1,34 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-W", + "error", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "Exact finite rational label/operator distances, factorization, commutation/inverse identities and ten rejection controls." + }, + { + "argv": [ + "{python}", + "-I", + "-W", + "error", + "-O", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "The same checks with Python assertions disabled; all acceptance checks use explicit exceptions." + } + ] +} diff --git a/research/unbounded-shear-bicliques/verify.py b/research/unbounded-shear-bicliques/verify.py new file mode 100644 index 0000000000..0250ce1a9d --- /dev/null +++ b/research/unbounded-shear-bicliques/verify.py @@ -0,0 +1,191 @@ +"""Exact finite corroboration of the new shear construction. Apache-2.0.""" + +import hashlib +import json +import sys +from fractions import Fraction as Q +from pathlib import Path + + +def require(condition, message): + if not condition: + raise ValueError(message) + + +def label(parameter, side): + require(type(parameter) in (int, Q), "parameter must be rational") + require(side in (0, 1), "side must be zero or one") + x = Q(parameter) + if side == 0: + return ((x, x * x), (Q(1), x)) + return ((x, x * x), (Q(0), -x)) + + +def family(parameters, side): + require(1 <= len(parameters) <= 64, "family size outside 1..64") + require(len(set(parameters)) == len(parameters), "repeated parameter") + return tuple(label(x, side) for x in parameters) + + +def difference(a, b): + size = len(a) + return tuple(tuple(a[i][j] - b[i][j] for j in range(size)) + for i in range(size)) + + +def determinant2(a): + return a[0][0] * a[1][1] - a[0][1] * a[1][0] + + +def rank(a): + """Independent rational row elimination, on matrices of order at most four.""" + size = len(a) + require(1 <= size <= 4 and all(len(row) == size for row in a), + "rank expects a square matrix of order at most four") + work = [[Q(x) for x in row] for row in a] + pivot = 0 + for column in range(size): + selected = next((i for i in range(pivot, size) if work[i][column]), None) + if selected is None: + continue + work[pivot], work[selected] = work[selected], work[pivot] + for i in range(pivot + 1, size): + factor = work[i][column] / work[pivot][column] + for j in range(column, size): + work[i][j] -= factor * work[pivot][j] + pivot += 1 + return pivot + + +def shear(a): + return tuple(tuple(Q(i == j) if j < 2 or i >= 2 else a[i][j - 2] + for j in range(4)) for i in range(4)) + + +def multiply(a, b): + return tuple(tuple(sum(a[i][k] * b[k][j] for k in range(4)) + for j in range(4)) for i in range(4)) + + +def check_family(left, right): + matrices = left + right + sides = (0,) * len(left) + (1,) * len(right) + pairs = 0 + for i, a in enumerate(matrices): + for j, b in enumerate(matrices): + delta = difference(a, b) + expected = 0 if i == j else 1 if sides[i] != sides[j] else 2 + by_determinant = 2 if determinant2(delta) else int(any(map(any, delta))) + require(by_determinant == expected, "wrong label distance") + require(rank(delta) == expected, "elimination disagrees") + require(rank(difference(shear(a), shear(b))) == expected, + "wrong operator distance") + pairs += 1 + return pairs + + +def check_factors(left_parameters, right_parameters): + checks = 0 + for t in left_parameters: + for a in right_parameters: + factor = ((t - a, (t - a) * (t + a)), (Q(1), t + a)) + require(difference(label(t, 0), label(a, 1)) == factor, + "cross rank-one factorization failed") + checks += 1 + for side, parameters in enumerate((left_parameters, right_parameters)): + for x in parameters: + for y in parameters: + det = determinant2(difference(label(x, side), label(y, side))) + require(det == (1 if side == 0 else -1) * (x - y) ** 2, + "within-family determinant identity failed") + checks += 1 + return checks + + +def check_group(matrices): + identity = shear(((Q(0), Q(0)), (Q(0), Q(0)))) + pairs = 0 + for a in matrices: + inverse = shear(tuple(tuple(-x for x in row) for row in a)) + require(multiply(shear(a), inverse) == identity, "wrong inverse") + for b in matrices: + total = tuple(tuple(a[i][j] + b[i][j] for j in range(2)) + for i in range(2)) + expected = shear(total) + require(multiply(shear(a), shear(b)) == expected, "wrong product") + require(multiply(shear(b), shear(a)) == expected, "not commuting") + pairs += 1 + return pairs + + +def rejects(action, message): + try: + action() + except ValueError: + return + raise ValueError("control accepted: " + message) + + +def check_controls(): + left, right = family((0, 1), 0), family((0, 1), 1) + wrong_square = (((Q(0), Q(1)), (Q(1), Q(0))), left[1]) + missing_unit = (((Q(0), Q(0)), (Q(0), Q(0))), left[1]) + wrong_sign = (right[0], ((Q(1), Q(1)), (Q(0), Q(1)))) + rejects(lambda: check_family(wrong_square, right), "changed square") + rejects(lambda: check_family(missing_unit, right), "omitted unit") + rejects(lambda: check_family(left, wrong_sign), "wrong diagonal sign") + rejects(lambda: family((0, 0), 0), "duplicate parameter") + rejects(lambda: family((), 0), "empty family") + rejects(lambda: family(tuple(range(65)), 0), "oversized finite fixture") + rejects(lambda: label(0.5, 0), "inexact parameter") + rejects(lambda: label(True, 0), "boolean parameter") + rejects(lambda: label(0, 2), "invalid family") + rejects(lambda: rank(((1, 2),)), "malformed matrix") + return 10 + + +def run(): + pairs = 0 + sizes = tuple(range(2, 13)) + (16, 32) + for n in sizes: + left = family(tuple(range(n)), 0) + right = family(tuple(range(n)), 1) + pairs += check_family(left, right) + bound = max(1, (n - 1) ** 2) + require(max(abs(x) for m in left + right for row in m for x in row) + <= bound, "coefficient-height bound failed") + left_parameters = tuple(Q(i, 3) for i in range(-4, 5)) + right_parameters = tuple(Q(i, 5) for i in range(-5, 6)) + left, right = family(left_parameters, 0), family(right_parameters, 1) + pairs += check_family(left, right) + factors = check_factors(left_parameters, right_parameters) + group_pairs = check_group(left + right) + controls = check_controls() + require(pairs == 8116 and factors == 301 and group_pairs == 400, + "finite coverage count changed") + return {"status": "PASS_UNBOUNDED_SHEAR_BICLIQUES", + "claim_type": "scoped written proof with finite corroboration", + "balanced_fixture_sizes": list(sizes), + "rational_fixture_parts": [len(left), len(right)], + "ordered_label_and_operator_pairs": pairs, + "factorization_and_determinant_checks": factors, + "ordered_group_product_pairs": group_pairs, + "rejection_controls": controls, + "largest_fixture_distortion_by_PR907": str(Q(2 * (32 - 1), 32)), + "new_kappa": False} + + +def main(): + require(len(sys.argv) == 1, "this verifier takes no arguments") + result = run() + package = Path(__file__).resolve().parent + names = ("README.md", "PROOF.md", "TASK.json", "SOURCES.json", + "VERIFY.json", "verify.py") + result["package_sha256"] = { + name: hashlib.sha256((package / name).read_bytes()).hexdigest() + for name in names} + print(json.dumps(result, sort_keys=True, indent=2)) + + +if __name__ == "__main__": + main()