Skip to content

Make none explicit choice for linear robust estimator#3341

Open
Lestropie wants to merge 1 commit into
masterfrom
registration_linear_estimators
Open

Make none explicit choice for linear robust estimator#3341
Lestropie wants to merge 1 commit into
masterfrom
registration_linear_estimators

Conversation

@Lestropie
Copy link
Copy Markdown
Member

Closes #2586.

Claude agreed with my diagnosis and came up with an intervention that was the same as my own.

I don't know whether the imprecision of the implementation was influenced at all by uncertainty about whether the L2 robust estimator and "no robust estimator" are equivalent; which Claude says they are. So removing "None" as an option and just having a "choice of estimator" instead of "one of these robust estimators, or none" is also an option.


Full log of Claude query and response

❯ Analyse the conflict described in GitHub Issue #2586. Cross-check the
behaviour within population_template and mrregister. Report on whether the
posted interpretation is correct, and what change to the code or
documentation would be most appropriate.

The interpretation is correct. The current behaviour (still present on master)
is:

mrregister (cpp/mrregister.cpp:433–446, 847–887)

  • If -rigid_metric.diff.estimator is omitted, rigid_estimator is initialised
    to Registration::None and the code path that runs is Metric::MeanSquared /
    MeanSquared4D — i.e. ordinary least squares, not the DifferenceRobust
    branch.
  • The help text in src/registration/linear.cpp:259-264 (and the affine
    equivalent at :327-332) advertising "Default: l2" is therefore misleading: the
    explicit l2 choice triggers a different code path (DifferenceRobust) that
    is never visited under default invocation.
  • Mathematically, the two paths are equivalent (Metric::L2 in
    src/registration/metric/robust_estimators.h:53 is just x*x / slope x,
    identical in form to OLS), so end-user numerical behaviour is the OLS the help
    text implies — but the documented "default" is not actually executed.

population_template (bin/population_template:56, 659–664, 1172–1173,
1186–1187)

  • Default behaviour: app.ARGS.linear_estimator is None, the truthiness checks
    at :1172 / :1186 fail, and the -rigid_metric.diff.estimator /
    -affine_metric.diff.estimator option is not forwarded to mrregister. So
    mrregister falls through to its MeanSquared path. The advertised "Default:
    None (no robust estimator used)" is faithful.
  • Note a latent inconsistency at :660: the validator accepts the literal
    string none (case-insensitive), but the dispatch at :1172/:1186 uses bare if
    linear_estimator:, which is truthy for "none". Passing -linear_estimator none
    would forward -rigid_metric.diff.estimator none to mrregister, whose
    type_choice only accepts {l1, l2, lp} and would error.

Recommended changes

  1. src/registration/linear.cpp (preferred fix) — correct the help text on both
    rigid and affine metric.diff.estimator options. Remove "Default: l2"; replace
    with something like "Default: not used (ordinary least squares / mean squared
    difference is applied; mathematically equivalent to l2)". This keeps current
    numerical behaviour and accurately reflects that the option only takes effect
    when explicitly specified.
  2. Make none an explicit choice (your stated plan) in both interfaces. In
    mrregister, add it to linear_robust_estimator_choices and treat it the same as
    the option being absent. In population_template, this avoids the
    validator/dispatch mismatch noted above. While doing so, also fix the dispatch
    guards at :1172/:1186 to if linear_estimator and linear_estimator.lower() !=
    'none': so an explicit none is suppressed rather than forwarded.
  3. Not recommended: changing the default path in mrregister to actually route
    through DifferenceRobust. It's an extra layer of indirection for an
    OLS-equivalent computation and would silently change anyone relying on the
    current MeanSquared code path; the documentation fix is the right call.

❯ Proceed with recommended changes 1 and 2. Change the command-line options for
robust estimators to mrregister to include "none" as an available choice.
Change population_template to use the "enum" module rather than strings for
handling user-specified & default robust estimators.

● All changes are in place and verified. Summary:

src/registration/linear.cpp

  • Added "none" to linear_robust_estimator_choices.
  • Replaced the misleading "Default: l2" help text on both
    rigid_metric.diff.estimator and affine_metric.diff.estimator with an accurate
    description: explicit none choice that documents the actual behaviour (mean
    squared difference / ordinary least squares, mathematically equivalent to l2),
    and Default: none.

cmd/mrregister.cpp

  • Added case 3 to both rigid and affine estimator dispatch switches, mapping
    the new "none" choice to Registration::None (the same path already taken when
    the option is omitted).

bin/population_template

  • Added import enum and a LinearEstimator(enum.Enum) with members
    NONE/L1/L2/LP plus a DEFAULT_LINEAR_ESTIMATOR constant.
  • The -linear_estimator argument now uses argparse choices= and default=
    driven by the enum, with a help string aligned to mrregister's.
  • Replaced string-based parsing/validation with
    LinearEstimator(app.ARGS.linear_estimator) and is not LinearEstimator.NONE
    checks; this also fixes the latent bug where passing -linear_estimator none
    would forward the unsupported string to mrregister.
  • Both dispatch sites (rigid + affine) now pass linear_estimator.value only
    when the estimator is not NONE.

Verification: ./check_syntax --diff and ./run_pylint both pass. Auto-generated
docs under docs/reference/commands/ will refresh on the next
./docs/generate_user_docs.sh run.

Resolves the documentation/behaviour mismatch flagged in issue #2586:
mrregister's help text advertised `l2` as the default robust estimator,
but the absence of the option led to the ordinary mean squared difference
path being taken rather than `DifferenceRobust<L2>`. Adds `none` to the
valid choices for both `-rigid_metric.diff.estimator` and
`-affine_metric.diff.estimator`, updates the help text accordingly, and
refactors `population_template` to use an `enum.Enum` for the
`-linear_estimator` argument — also fixing a latent bug where passing
`-linear_estimator none` would forward an unsupported string to
mrregister.

Session prompts:
1. > Analyse the conflict described in GitHub Issue #2586. Cross-check
   > the behaviour within population_template and mrregister. Report
   > on whether the posted interpretation is correct, and what change
   > to the code or documentation would be most appropriate.
2. > Proceed with recommended changes 1 and 2. Change the command-line
   > options for robust estimators to mrregister to include "none" as
   > an available choice. Change population_template to use the "enum"
   > module rather than strings for handling user-specified & default
   > robust estimators.

Generated-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Lestropie Lestropie requested a review from a team May 7, 2026 07:05
@Lestropie Lestropie self-assigned this May 7, 2026
@Lestropie Lestropie added this to the 3.1.0 updates milestone May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default linear registration estimator

1 participant