Tasks/Math & Scientific Computing/Computational Mechanics

Discrete Truss Sizing Optimisation

Size every bar of a transmission tower

discrete_truss_section_sizing Math & Scientific Computing Computational Mechanics
instruction.mdthis is what the agent is given

You inherit a weak but legal truss sizing pipeline and must improve its solve() so that it picks one steel pipe section per bar of a 3D transmission-tower truss to minimise total structural weight under stress and displacement constraints. The section catalogue is discrete and the constraints couple every bar to every other through the load path, so the design space is strongly non-separable and the naive starting point leaves a great deal of weight on the table. Your submitted solve() is re-run per instance on a set of sealed hidden instances, and the lower your mean normalised weight, the better.

Hard Constraints

  • An instance is a self-contained JSON file: parametric tower geometry (num_levels, total height, base/top half-widths, cross-bracing levels — the same generator as the reference tower), material (E, rho), three axis-aligned distributed load_cases (total N in +x, +y and −z, split equally over all unsupported nodes), constraints (allowable stress, node displacement limit, tolerance) and the 37-entry pipe section catalog (sections, areas in mm²; section ids are 1-based).
  • Physics (fixed, implemented by the public evaluator truss.py): linear 3D truss FEM by the direct stiffness method — identical to the official reference evaluator (verified to < 1e-9 relative on weight/stress/displacement over 200+ designs). The base 4 nodes are fully fixed. The single scalar objective (lower is better) is total weight.
  • Feasibility: in every load case, every bar's |stress| must not exceed the allowable stress and every displacement component must stay within the limit (tolerance 1e-6). An infeasible or malformed design scores 100.0 (the baseline) on that instance — there is no partial credit and no repair on the grader side.
  • Implement solve(instance_path: str, time_budget_s: float) -> list[int] in methods/main/solver.py. It is called once per instance and must return within time_budget_s (the verifier uses 60 s per instance) a list of n_bars section ids in {1..37} (n_bars varies per instance with the tower parameters — read it from the instance, do not hard-code 284).
  • You may only change your solver code — not the evaluator, the instances, or the scoring. Determinism is recommended (seed your RNG) so your local scores reproduce.
  • Hidden instances change the level count (so n_bars ≠ 284), taper, bracing and limits; output shaped for one instance is malformed on another and scores 100.

What You Have

  • methods/main/solver.py — the weak baseline you edit in place: start all bars at the middle section and multiply every id by the worst constraint-violation ratio until feasible. One knob for 300+ bars — it lands on an absurdly heavy design.
  • truss.py — the exact public evaluator used for scoring: instance loader (parametric topology builder), fast sparse FEM (analyze(), ~0.4 ms per design), evaluate(), the deterministic weak baseline (weak_ids()) used as the normalisation denominator, and score() = 100 × weight / weight(weak baseline).
  • data/ — 3 visible instances: T0_reference (the exact reference tower: 23 levels, 284 bars, 248.2 MPa, 5 mm) plus V1, V2 (samples from the hidden-set generator, so the visible set spans the hidden distribution).
  • selfcheck.py — runs your current solve() on the visible instances and prints the mean normalised score. Iterate against it (QUICK=5 python selfcheck.py for fast rounds).

What You Submit

Your edited methods/main/solver.py (plus any helper modules under methods/). The verifier re-runs solve() per hidden instance and re-scores the returned designs; only the solve(path, budget) -> list[int] contract above is relied upon.

How It Is Judged

The sealed verifier calls your solve() on each hidden instance (unseen towers from the same parametric generator: different level counts, heights, tapers, bracing patterns, load magnitudes and allowable limits), then recomputes

score(instance) = 100 × weight(your design) / weight(weak baseline)

with its own trusted evaluator. The hidden mean is your score; lower is better, and your reward rises as it drops. The headroom below the shipped starting point is large and well established for this problem family: careful discrete search reaches designs many times lighter than a uniform scale-up, and it is territory where iterative methods are known to stall well short of what is attainable.

Metric

mean normalised weight over the 5 sealed hidden towers · lower is better

score = 100 x weight / weight(uniform scale-up baseline) per tower; infeasible or malformed scores 100

anchorheld-outreward
Bshipped template (uniform scale-up)100.000.00
Rreference (stressed + greedy downsize)48.930.30
Sauthoring SOTA (annealing + polish)25.170.60
no upper anchor: soft cap0< 1.00
normalisation
m >= B0
B > m >= R0.3 * (L(B) - L(m)) / (L(B) - L(R))
R > m >= S0.3 + 0.3 * (L(R) - L(m)) / (L(R) - L(S))
m < S1 - 0.4 / (1 + (L(S) - L(m)) / (L(R) - L(S)))

m = this run's held-out metric  ·  B = shipped template (uniform scale-up)  ·  R = reference (stressed + greedy downsize)  ·  S = authoring SOTA (annealing + polish)

L(x) = log(x). The five hidden scores are averaged first, then the mean is mapped once. Past SOTA the cap nears 1.0 but never reaches it.

Rollouts

109 minwall clock
$31.66spend
50.2Mtokens
17versions, 14 kept
18.72 18.76 18.80 18.84 18.88 $0 $7.5 $15 $22 $30 cumulative spend on the run visible mean at the 60 s budget, lower is better v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16
keptrevertedno scoreturning point
  1. v0Shipped uniform scale-up baseline, unmodifiedmeasured at 5 s only1 min · $0.35
  2. v1Randomised round-robin coordinate descent from the largest sectionsmeasured at 5 s only2 min · $0.51
  3. v2Continuous SLSQP on exact adjoints, upward rounding, then discrete descentSolve the continuous relaxation first, then round up and repair, instead of searching bar by bar. The 5 s mean fell 53.7 to 19.0.measured at 5 s only6 min · $0.97
  4. v3Multistart discrete descent over orders and 1.00-1.16 scaled continuous seeds18.89921 min · $3.11
  5. v4Trust-region MILP up/down catalogue exchanges on exact adjointsTrade single-bar moves for a trust-region MILP that exchanges many sections at once, ranked by exact adjoint sensitivities.18.80325 min · $3.92
  6. v5Reserve end-of-budget time for adjoint-ranked one-up/one-down refinement18.79832 min · $5.23
  7. v6Keep a distinct coordinate basin and exchange it before exact selection18.78745 min · $8.46
  8. v7Sequential catalogue fixing: drop snapped bars, re-optimise, branch the tailFix the bars the relaxation already snaps, re-optimise the rest, and branch only the hard tail; closes most of the discrete gap.18.72162 min · $13.41
  9. v8Seed catalogue fixing from the earlier ftol=2e-9 continuous stationary point18.71667 min · $15.17
  10. v9Three catalogue-fixing paths (30/15, 30/20, 40/15) with exact incumbent pick18.71674 min · $17.50
  11. v10Exact-select five deterministic greedy descent orders per catalogue snap18.71578 min · $19.11
  12. v11Random jitter in catalogue-fix priority; 12-path diagnosticT0/V1 probe only81 min · $19.91
  13. v12Add a bounded ftol=5e-9 continuous seed and a 24 s catalogue window18.71596 min · $25.75
  14. v13Sweep catalogue-fix distance: absolute, objective-weighted, local-gapT0/V1 probe only99 min · $27.10
  15. v14Snap batches to the catalogue floor or ceiling instead of the nearestT0/V1 probe only100 min · $27.56
  16. v15One path compares four feasible hard-tail branches before fixing18.715106 min · $29.91
  17. v16Deadline callback on the optional early continuous seed18.715108 min · $31.08

31.1 USD over 109 min. HiGHS logged onto stdout and broke the grader's JSON parse; the saved submission was re-scored with a fixed parser.

On the hidden set

held-out metricreward
shipped template (uniform scale-up)100.000.00
reference (stressed + greedy downsize)48.930.30
authoring SOTA (annealing + polish)25.170.60
no upper anchor: soft cap0< 1.00
this run24.550.6145