Revise communication RE linear robust estimator#3341
Conversation
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>
|
I have to admit I'm also confused about the difference between L2 and none - if they both reduce to mean squared difference, I don't get the rationale for even listing them as separate entities... I'll need to dig into the code to get a proper sense of whether there really is a difference, and if so what that difference really is... |
Automated checkpoint for one turn of work. Prompt: > This worktree corresponds to an earlier version of the MRtrix3 project, for which some of the configuration information provided to Claude may be inaccurate (eg. build system, filesystem arrangement). > This code branch involves an attempt to rectify ambiguity in description and interface of image registration similarity metrics. See GitHub PR#3341 for info, including a prior Claude session. Specifically, there is a "robust" estimator named "L2", which seems to possess no meaningful difference to the default "MeanSquared" estimator. Maintainers wish to fully resolve this discrepancy rather than merely patching existing bugs and making documentation faithful. Communicating the use of the mean squared metric as a linear estimator of "none" is fundamentally confusing. > 1. Is the "Robust L2" metric equally applicable to 3D and 4D images as is the combined pair of "MeanSquared" and "MeanSquared4D" (accessible though "none" linear estimator)? If so, then removing the latter, and retaining the L2 metric in conjunction with the "L1" and "LP" metrics (perhaps renamed from "robust" estimators to something more suitable for inclusion of L2), is an appealing candidate. > 2. Is there any other feature that can be discovered by which the "robust L2" and "MeanSquared" measures may behave differently? > 3. Is there any trace in the code base that evidences the prospect of other augmentations to the set of robust estimators that may have been intended to make all implementations within that category "more robust", thereby prospectively making the attribution of an L2 norm to the set of "robust" estimators appropriate? > 4. Perform testing of these two code paths within the mrregister command. The software has been compiled in debug mode at bin/mrregister. Local modifications to the code to export additional debugging information or guarantee execution of specific code paths is permitted. Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Automated checkpoint for one turn of work. Prompt: > Recover and reprint in-progress session from yesterday from this worktree that was lost due to unexpected system shutdown. Report absolute location of file used to recover this information. Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
|
OK sent Claude on a deep dive. Story basically conforms to my hypothesis.
Question then is what to change. It agrees with my instinct (though acknowledge they can be hesitant to do the converse): the overall cleanest solution would be to remove I'd prefer however to do any refactoring on |
- Reverts some changes in #3341 to make interface more consistent with existing. - Change some variable names to better communicate operation. - Avoids contaminating Registration namespace with unscoped "NONE".
|
@jdtournier See if the overall revised proposal make sense to you. Changes compared to current
|
none explicit choice for linear robust estimator
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)
to Registration::None and the code path that runs is Metric::MeanSquared /
MeanSquared4D — i.e. ordinary least squares, not the DifferenceRobust
branch.
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.
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)
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.
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
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.
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.
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
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
the new "none" choice to Registration::None (the same path already taken when
the option is omitted).
bin/population_template
NONE/L1/L2/LP plus a DEFAULT_LINEAR_ESTIMATOR constant.
driven by the enum, with a help string aligned to mrregister's.
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.
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.