Skip to content

Charge candidates for detail the target does not have - #93

Merged
rasros merged 2 commits into
mainfrom
detail-objective
Aug 17, 2026
Merged

Charge candidates for detail the target does not have#93
rasros merged 2 commits into
mainfrom
detail-objective

Conversation

@rasros

@rasros rasros commented Aug 17, 2026

Copy link
Copy Markdown
Owner

The other objectives all reward agreement with the reference at a pixel or an edge, and local search can buy that agreement by adding detail the target does not have — stipple a flat region and the edge map lights up in roughly the right places. Measured: on a 45-minute single-epoch run the round score fell 64% against a three-epoch run while the evaluator scored the two within 0.000004 of each other. The search was paying for detail no perceptual judge would credit, and the drawing showed it.

detail() is deflate over the raw RGB bytes of the render — not the PNG, which is already deflated and would mostly measure the encoder. It reads the render, so rewriting the source cannot talk it down.

One-sided, and this is the important part

The objective is max(0, detail(candidate) − detail(reference)) / detail(reference).

It first went in as a symmetric distance, on the reasoning that a pure minimum would make an empty drawing optimal on this axis. Both halves of that were wrong.

Symmetric breaks on any noisy target. Noise is the most incompressible thing an image can carry, and generated or photographed inputs carry some. On the duck at working resolution:

target detail distance of a correct SVG render
clean 7,607 0.238
grain σ=2 (barely visible) 55,664 — 7.3× 0.896
grain σ=12 96,889 — 12.7× 0.940

A symmetric reading calls a correct vector render 90% wrong on this axis, and the only way to improve it is to add incompressible speckle. The regulariser would drive exactly the artefacts it exists to suppress.

The degenerate needed no guard. An empty drawing does score 0 here, but it wins this one axis while losing colour, edge and shape — one win against three losses is dominated whatever the arity. I had assumed it would split 2–2 and become incomparable; it cannot, because it can only win one axis.

Sanity check on the real case: the current duck SVG against its clean target scores exactly 0.0 excess, so this is inert until a candidate actually gets busier than the target.

Side effect: the arity is now even

With three objectives, wins and losses cannot split evenly, so every pair is comparable, the relation is a total tournament, and the top tier holds one candidate. A 2–2 split is the first time two candidates can be mutually unbeaten because they are good at different things — genuine fronts exist now. It also weakens selection pressure, which is the documented reason majority replaced unanimity, so it cuts both ways.

build_objectives derives the vector from SCORER_METRICS rather than a hardcoded triple, so a registered measure cannot silently be left out of ranking again — which is how the blend happened. The ranking cache key had the same hardcoding and would have served stale rankings; it derives from the registry too.

Known limit

A striped image compresses nearly as small as a blank one — 67 bytes against 50. That is correct (a regular pattern genuinely is low complexity) but it means this charges for irregular detail specifically. Repetitive artefacts — stipple in a grid, hatching, duplicated strokes — will barely register, and catching those would need a measure other than compressed size.

@rasros
rasros force-pushed the staleness-top-tier branch from 9e991f1 to 8cfd257 Compare August 17, 2026 15:45
@rasros
rasros changed the base branch from staleness-top-tier to main August 17, 2026 15:49
@rasros
rasros merged commit 9afdd8a into main Aug 17, 2026
1 check passed
@rasros
rasros deleted the detail-objective branch August 17, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant