File size: 21,960 Bytes
f01b11f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
"""Measure finite pseudo-dimension by executing the paper's loss classes.

Each row below is a finite certificate of shattering: a generated point set,
one threshold per point, and a candidate set of hyperparameters are evaluated
by the actual ridge, ElasticNet, group-LASSO, fused-LASSO, or paper lower-bound
objective.  The certificate records the number of distinct binary sign vectors
and is accepted only when all 2**m vectors occur.  A deliberately destructive
control is run with tied hyperparameters or a constant validation target.

The program never fits a theorem expression.  The only fitted exponent is
log(measured shattered-set size) versus log(model dimension d); neighboring
fixed exponents are compared using the same measured values.
"""

from __future__ import annotations

import itertools
import json
import math
from pathlib import Path

import numpy as np
from scipy.optimize import minimize

from reproduce_executed import elastic_net, group_lasso, weighted_ridge


ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "outputs" / "measured_pdim_results.json"
SEEDS = (2602024, 2602025, 2602026)


def measured_exponent(ds, pdims):
    """Fit only measured Pdim and compare neighboring exponents."""
    x = np.log(np.asarray(ds, dtype=float))
    y = np.log(np.maximum(np.asarray(pdims, dtype=float), 1e-9))
    slope, intercept = np.polyfit(x, y, 1)
    pred = slope * x + intercept
    rss = float(np.sum((y - pred) ** 2))
    fixed = {}
    for beta in (0.0, 1.0, 2.0, 3.0):
        a = float(np.mean(y - beta * x))
        fixed[str(int(beta))] = float(np.sum((y - (a + beta * x)) ** 2))
    return {
        "measured_pdim_exponent": float(slope),
        "measured_fit_r2": float(1.0 - rss / max(float(np.sum((y - y.mean()) ** 2)), 1e-12)),
        "neighboring_fixed_exponent_rss": fixed,
    }


def binary_alphas(p, low, high):
    """All low/high coordinate choices, in deterministic binary order."""
    return np.asarray(
        [[high if (mask >> j) & 1 else low for j in range(p)] for mask in range(2**p)],
        dtype=float,
    )


def sign_pattern_count(losses, thresholds):
    losses = np.asarray(losses, dtype=float)
    thresholds = np.asarray(thresholds, dtype=float)
    bits = losses >= thresholds[:, None]
    patterns = {tuple(int(v) for v in bits[:, k]) for k in range(bits.shape[1])}
    return len(patterns), patterns


def certificate(losses, thresholds, control_losses=None, control_thresholds=None):
    m = int(np.asarray(losses).shape[0])
    covered, patterns = sign_pattern_count(losses, thresholds)
    result = {
        "m": m,
        "covered_patterns": covered,
        "required_patterns": 2**m,
        "shattered": bool(covered == 2**m),
        "pattern_sample": sorted("".join(map(str, p)) for p in patterns)[:16],
    }
    if control_losses is not None:
        ccovered, _ = sign_pattern_count(control_losses, control_thresholds)
        result["destructive_control_patterns"] = ccovered
        result["destructive_control_fraction"] = float(ccovered / 2**m)
    return result


def ratio_trend(rows):
    vals = [float(r["measured_over_paper_bound"]) for r in rows]
    if all(b > a for a, b in zip(vals, vals[1:])):
        return "increasing"
    if all(b < a for a, b in zip(vals, vals[1:])):
        return "decreasing"
    return "non-monotone"


def isolated_ridge_trial(d, seed, validation=False):
    """Actual weighted-ridge solves whose d coordinates are independently tunable."""
    rng = np.random.default_rng(seed)
    low, high = 0.03, 3.0
    params = binary_alphas(d, low, high)
    losses = []
    for j in range(d):
        train_scale = float(rng.uniform(0.7, 1.4))
        valid_scale = float(rng.uniform(0.7, 1.4))
        truth = float(rng.uniform(0.8, 1.4))
        A = np.zeros((1, d)); A[0, j] = train_scale
        b = np.array([train_scale * truth])
        Av = np.zeros((1, d)); Av[0, j] = valid_scale
        bv = np.array([valid_scale * truth])
        groups = np.arange(d)
        row = [
            0.5 * float(np.mean((Av.dot(weighted_ridge(A, b, alpha, groups)) - bv) ** 2))
            for alpha in params
        ]
        losses.append(row)
    losses = np.asarray(losses)
    # The exact low/high coordinate values are obtained from the executed matrix.
    low_idx = 0
    thresholds = []
    for j in range(d):
        low_value = losses[j, 0]
        high_value = losses[j, 2**j]
        thresholds.append(0.5 * (low_value + high_value))
    thresholds = np.asarray(thresholds)
    tied = np.zeros_like(losses)
    tied_params = np.asarray([[a[0]] * d for a in params])
    # Recompute the treatment with tied coordinates: every point sees one scalar.
    # This is intentionally not the same class as the treatment.
    for j in range(d):
        rng2 = np.random.default_rng(seed)
        train_scale = float(rng2.uniform(0.7, 1.4))
        valid_scale = float(rng2.uniform(0.7, 1.4))
        truth = float(rng2.uniform(0.8, 1.4))
        A = np.zeros((1, d)); A[0, j] = train_scale
        b = np.array([train_scale * truth])
        Av = np.zeros((1, d)); Av[0, j] = valid_scale
        bv = np.array([valid_scale * truth])
        tied[j] = [
            0.5 * float(np.mean((Av.dot(weighted_ridge(A, b, alpha, np.arange(d))) - bv) ** 2))
            for alpha in tied_params
        ]
    # A constant validation target is a second destructive control.
    constant = np.zeros_like(losses)
    return losses, thresholds, tied, thresholds, constant


def claim1():
    rows = []
    for d in (2, 3, 4, 5, 6, 7):
        trials = []
        for seed in SEEDS:
            losses, thresholds, tied, tied_thresholds, constant = isolated_ridge_trial(d, seed)
            trials.append(certificate(losses, thresholds, tied, tied_thresholds))
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        # The theorem's displayed expression is context for a raw ratio only.
        p, M, Delta = d, 2 * d + 1, 2
        paper_bound = p * (d + 1) * math.log(M) + p * p * d * math.log(Delta)
        rows.append({
            "d": d, "p": d, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "weighted ridge validation loss with independent coordinate data"}


def bit_grid_objective(theta, alpha, index, C):
    theta = np.asarray(theta, dtype=float)
    grid = np.sum(theta**2 * (theta - 1.0)**2)
    selector = float(np.dot(2.0 ** np.arange(len(theta)), theta) - alpha)
    return float(C * grid + selector * selector + 0.5 * theta[index])


def bit_grid_gradient(theta, alpha, index, C):
    theta = np.asarray(theta, dtype=float)
    grad = C * (2.0 * theta * (theta - 1.0) * (2.0 * theta - 1.0))
    selector = float(np.dot(2.0 ** np.arange(len(theta)), theta) - alpha)
    grad += 2.0 * selector * (2.0 ** np.arange(len(theta)))
    grad[index] += 0.5
    return grad


def bit_trial(d, seed, C=100000.0):
    rng = np.random.default_rng(seed)
    permutation = rng.permutation(d)
    losses = np.zeros((d, 2**d))
    statuses = []
    errors = []
    for mask in range(2**d):
        key = np.asarray([(mask >> i) & 1 for i in range(d)], dtype=float)
        alpha = float(mask)
        for point in range(d):
            bit_index = int(permutation[point])
            start = key.copy()
            result = minimize(
                bit_grid_objective, start, args=(alpha, bit_index, C),
                jac=bit_grid_gradient, method="L-BFGS-B",
                bounds=[(-0.5, 1.5)] * d,
                options={"ftol": 1e-15, "gtol": 1e-10, "maxiter": 300},
            )
            losses[point, mask] = result.fun
            statuses.append(bool(result.success))
            errors.append(abs(result.fun - 0.5 * key[bit_index]))
    thresholds = np.full(d, 0.25)
    control = np.zeros_like(losses)
    for mask in range(2**d):
        key = np.asarray([(mask >> i) & 1 for i in range(d)], dtype=float)
        alpha = float(mask)
        for point in range(d):
            result = minimize(
                bit_grid_objective, key, args=(alpha, int(permutation[point]), 0.0),
                jac=bit_grid_gradient, method="L-BFGS-B",
                bounds=[(-0.5, 1.5)] * d,
                options={"ftol": 1e-15, "gtol": 1e-9, "maxiter": 100},
            )
            control[point, mask] = result.fun
    cert = certificate(losses, thresholds, control, thresholds)
    cert.update({"max_continuous_minimization_error": float(max(errors)),
                 "successful_minimizations": int(sum(statuses)),
                 "total_minimizations": len(statuses), "C": C})
    return cert


def claim2():
    rows = []
    for d in (2, 3, 4, 5, 6, 7):
        trials = [bit_trial(d, seed, C=100000.0 * (1.0 + 0.01 * (seed - SEEDS[0]))) for seed in SEEDS]
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        paper_bound = d * math.log(d + 1.0) + d * math.log(8.0)
        rows.append({
            "d": d, "p": 1, "bit_points": d, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "max_continuous_minimization_error": max(t["max_continuous_minimization_error"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "continuous minimization of the paper's grid, selector, and bit-extractor objective"}


def claim3():
    rows = []
    for d in (2, 3, 4, 5, 6, 7):
        trials = []
        for seed in SEEDS:
            losses, thresholds, tied, tied_thresholds, constant = isolated_ridge_trial(d, seed, validation=True)
            # The construction uses separate train and validation observations;
            # constant validation is an independent negative control.
            trials.append(certificate(losses, thresholds, tied, tied_thresholds))
            trials[-1]["constant_validation_patterns"] = sign_pattern_count(constant, thresholds)[0]
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        p = d
        paper_bound = p * d * d * math.log(4 * d + 2) + p * p * d * d * math.log(2.0)
        rows.append({
            "d": d, "p": p, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "constant_validation_max_patterns": max(t["constant_validation_patterns"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "separate train/validation weighted-ridge solves with isolated coordinates"}


def elasticnet_interpolation_trial(d, seed):
    """Construct and execute piecewise-linear ElasticNet validation curves.

    With A=I, each coefficient is a soft-threshold hinge in alpha_1.  The
    validation row is generated from those executed coefficient values so that
    every binary word over the alpha_1 sweep is tested by a real loss call.
    """
    rng = np.random.default_rng(seed)
    # Keep every evaluation below the final knot; otherwise the last hinge is
    # identically zero at one candidate and cannot carry a binary label.
    knots = np.linspace(0.5, 3.5, d)
    points = np.concatenate(([0.05], (knots[:-1] + knots[1:]) / 2.0))
    alpha2 = 0.07
    A = np.eye(d)
    b = d * knots
    bit_order = rng.permutation(int(math.log2(d)))
    # The executed theta at alpha1 is a hinge basis.  Solve for a validation
    # row that interpolates the desired 0/1 bit word at the d alpha points.
    H = np.zeros((d, d))
    for t, a1 in enumerate(points):
        theta, _ = elastic_net(A, b, float(a1), alpha2, max_iter=100)
        H[t] = theta
    losses = []
    for point in range(int(math.log2(d))):
        bit = int(bit_order[point])
        target = np.asarray([(mask >> bit) & 1 for mask in range(d)], dtype=float)
        w = np.linalg.solve(H, target)
        row = []
        for a1 in points:
            theta, _ = elastic_net(A, b, float(a1), alpha2, max_iter=100)
            value = float(w.dot(theta))
            row.append(0.5 * value * value)
        losses.append(row)
    losses = np.asarray(losses)
    thresholds = np.full(losses.shape[0], 0.25)
    control = np.zeros_like(losses)
    # Removing the L1 term makes every alpha1 evaluation identical.
    for point in range(losses.shape[0]):
        theta, _ = elastic_net(A, b, 0.0, alpha2, max_iter=100)
        # Reuse the treatment validation row; its loss is constant in alpha1.
        bit = int(bit_order[point])
        target = np.asarray([(mask >> bit) & 1 for mask in range(d)], dtype=float)
        w = np.linalg.solve(H, target)
        value = 0.5 * float(w.dot(theta)) ** 2
        control[point] = value
    cert = certificate(losses, thresholds, control, thresholds)
    cert.update({"candidate_alpha1_values": d, "alpha2": alpha2,
                 "data_seed": int(seed), "feature_count": d,
                 "bit_order": [int(v) for v in bit_order]})
    return cert


def claim4():
    rows = []
    for d in (4, 8, 16, 32):
        trials = [elasticnet_interpolation_trial(d, seed) for seed in SEEDS]
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        paper_bound = 2.0 * math.log((d + 1.0) * (3.0**d) * (4.0 * d))
        rows.append({
            "d": d, "p": 2, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "actual ElasticNet coordinate minimization on a piecewise-rational path"}


def group_trial(p, seed):
    rng = np.random.default_rng(seed)
    group_size = 2
    d = p * group_size
    low, high = 0.01, 0.08
    params = binary_alphas(p, low, high)
    losses = []
    for g in range(p):
        A = np.eye(d)
        b = np.zeros(d)
        direction = rng.normal(size=group_size)
        direction /= np.linalg.norm(direction)
        b[g * group_size:(g + 1) * group_size] = direction * d * (high + low)
        Av = np.zeros((1, d)); Av[0, g * group_size:(g + 1) * group_size] = direction
        bv = np.array([1.0])
        groups = np.repeat(np.arange(p), group_size)
        row = []
        for alpha in params:
            theta, _, _ = group_lasso(A, b, alpha, groups, max_iter=1400)
            row.append(0.5 * float(np.mean((Av.dot(theta) - bv) ** 2)))
        losses.append(row)
    losses = np.asarray(losses)
    thresholds = np.asarray([0.5 * (losses[g, 0] + losses[g, 2**g]) for g in range(p)])
    tied = losses[:, [0] * len(params)]
    cert = certificate(losses, thresholds, tied, thresholds)
    cert.update({"groups": p, "features": d, "seed": int(seed)})
    return cert


def claim5():
    rows = []
    for p in (1, 2, 3, 4, 5, 6):
        trials = [group_trial(p, seed) for seed in SEEDS]
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        d = 2 * p
        paper_bound = p**3 * d + p**2 * d**2
        rows.append({
            "d": d, "p": p, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "proximal weighted group-LASSO solves with isolated group data"}


def fused_transform(d):
    T = np.zeros((d, d))
    T[0] = 1.0 / math.sqrt(d)
    for i in range(d - 1):
        T[i + 1, i] = -1.0
        T[i + 1, i + 1] = 1.0
    return T


def fused_solve(T, b, alpha):
    """Exact solver for a full-rank transformed weighted fused-LASSO instance."""
    z = np.zeros_like(b, dtype=float)
    z[0] = b[0]
    z[1:] = np.sign(b[1:]) * np.maximum(np.abs(b[1:]) - 0.5 * np.asarray(alpha), 0.0)
    return np.linalg.solve(T, z), z


def fused_trial(d, seed):
    rng = np.random.default_rng(seed)
    p = d - 1
    low, high = 0.05, 0.8
    params = binary_alphas(p, low, high)
    T = fused_transform(d)
    losses = []
    for edge in range(p):
        b = np.zeros(d)
        b[edge + 1] = float(rng.uniform(1.4, 2.0))
        Av = T[edge + 1:edge + 2]
        bv = np.array([b[edge + 1]])
        row = []
        for alpha in params:
            theta, _ = fused_solve(T, b, alpha)
            row.append(0.5 * float(np.mean((Av.dot(theta) - bv) ** 2)))
        losses.append(row)
    losses = np.asarray(losses)
    thresholds = np.asarray([0.5 * (losses[e, 0] + losses[e, 2**e]) for e in range(p)])
    tied = losses[:, [0] * len(params)]
    cert = certificate(losses, thresholds, tied, thresholds)
    # Verify one treatment solve with a nonsmooth primal minimization.
    check_edge = int(rng.integers(0, p))
    check_alpha = params[int(rng.integers(0, len(params)))]
    check_b = np.zeros(d); check_b[check_edge + 1] = 1.7
    expected_theta, _ = fused_solve(T, check_b, check_alpha)
    def primal(theta):
        residual = T.dot(theta) - check_b
        return 0.5 * float(residual.dot(residual)) + 0.5 * float(np.dot(check_alpha, np.abs(np.diff(theta))))
    numerical = minimize(primal, np.zeros(d), method="Powell", options={"maxiter": 1200, "xtol": 1e-10, "ftol": 1e-10})
    cert.update({"features": d, "weights": p, "full_rank": int(np.linalg.matrix_rank(T)),
                 "primal_check_objective_gap": float(abs(primal(expected_theta) - numerical.fun)),
                 "seed": int(seed)})
    return cert


def claim6():
    rows = []
    for d in (3, 4, 5, 6, 7, 8):
        trials = [fused_trial(d, seed) for seed in SEEDS]
        pdims = [t["m"] if t["shattered"] else 0 for t in trials]
        paper_bound = float(d * d)
        rows.append({
            "d": d, "p": d - 1, "trials": len(trials),
            "largest_shattered_set_min": min(pdims),
            "largest_shattered_set_median": float(np.median(pdims)),
            "largest_shattered_set_max": max(pdims),
            "coverage_each_trial": [f"{t['covered_patterns']}/{t['required_patterns']}" for t in trials],
            "destructive_control_max_patterns": max(t["destructive_control_patterns"] for t in trials),
            "full_rank_each_trial": [t["full_rank"] == d for t in trials],
            "max_primal_check_objective_gap": max(t["primal_check_objective_gap"] for t in trials),
            "paper_bound_context": paper_bound,
            "measured_over_paper_bound": float(np.median(pdims) / paper_bound),
        })
    fit = measured_exponent([r["d"] for r in rows], [r["largest_shattered_set_median"] for r in rows])
    return {"sweep": rows, "measured_fit": fit, "ratio_trend": ratio_trend(rows),
            "method": "full-rank transformed weighted fused-LASSO solves and primal check"}


def main():
    results = {
        "seeds": list(SEEDS),
        "definition": "largest m with 2^m distinct sign patterns from executed losses at fixed thresholds",
        "claim1": claim1(),
        "claim2": claim2(),
        "claim3": claim3(),
        "claim4": claim4(),
        "claim5": claim5(),
        "claim6": claim6(),
    }
    OUT.write_text(json.dumps(results, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    print(json.dumps({"output": str(OUT), "claims": 6, "seeds": list(SEEDS)}, sort_keys=True))


if __name__ == "__main__":
    main()