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
towergeometry (num_levels, total height, base/top half-widths, cross-bracing levels — the same generator as the reference tower),material(E, rho), three axis-aligned distributedload_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]inmethods/main/solver.py. It is called once per instance and must return withintime_budget_s(the verifier uses 60 s per instance) a list ofn_barssection ids in{1..37}(n_barsvaries 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, andscore()=100 × weight / weight(weak baseline).data/— 3 visible instances:T0_reference(the exact reference tower: 23 levels, 284 bars, 248.2 MPa, 5 mm) plusV1,V2(samples from the hidden-set generator, so the visible set spans the hidden distribution).selfcheck.py— runs your currentsolve()on the visible instances and prints the mean normalised score. Iterate against it (QUICK=5 python selfcheck.pyfor 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.