Skip to content

feat(metrics): expose alpha_min + alpha_max kwargs in microssim#41

Merged
alxndrkalinin merged 6 commits into
mainfrom
feat/microssim-expose-alpha-max
May 26, 2026
Merged

feat(metrics): expose alpha_min + alpha_max kwargs in microssim#41
alxndrkalinin merged 6 commits into
mainfrom
feat/microssim-expose-alpha-max

Conversation

@alxndrkalinin

@alxndrkalinin alxndrkalinin commented May 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds alpha_min and alpha_max kwargs to get_ri_factor / get_global_ri_factor / MicroSSIM.__init__ so callers can lift / lower the bracket caps for pathological fits without monkey-patching internals.
  • Bumps the defaults symmetrically: alpha_max 1e3 → 1e6 (covers heavily down-scaled predictions, α* > 1e3) and alpha_min 1e-3 → 1e-6 (covers heavily up-scaled predictions, α* < 1e-3).
  • Documents the pre-existing MicroSSIM(ri_factor=...) / MicroMS3IM(ri_factor=...) constructor path with tests pinning the use case: load per-(model, organelle) α calibrated once, reuse across all evaluation calls — no re-fit.
  • Re-exports ALPHA_MIN_DEFAULT and ALPHA_MAX_DEFAULT from cubic.metrics.microssim so callers can reference the cap defaults at a stable import path.
  • Validates bounds eagerly in MicroSSIM.__init__ and get_global_ri_factor (out-of-range / NaN / ±inf raise immediately instead of after an expensive per-slice element pass). Shared _validate_alpha_bounds helper enforces the same contract everywhere.
  • All new kwargs are keyword-only (*, marker) to prevent silent positional misuse.

Test plan

  • pytest tests/metrics/microssim/ — 132 passed, 1 skipped
  • pytest tests/metrics/ — full metrics suite green (no regression in adjacent metrics)
  • ruff check, ruff format --check, mypy cubic/ clean
  • Upstream parity tests still pass (default-cap bumps don't shift golden α near 1)
  • CI green on push

🤖 Generated with Claude Code

alxndrkalinin and others added 2 commits May 26, 2026 11:35
Adds alpha_max to get_ri_factor / get_global_ri_factor / MicroSSIM.__init__
so callers can lift the bracket cap for pathological fits without monkey-
patching internals. Bumps the default from 1e3 to 1e6 — the old cap could
spuriously fail on heavily down-scaled predictions (optimum > 1e3) before
the fit even surfaced; new default safely covers those without changing
the result for well-conditioned inputs.

Also adds regression tests pinning the MicroMS3IM(ri_factor=...) +
offset/max_val constructor path so callers can load a per-(model,
organelle) RI factor calibrated once and reuse it across all evaluation
calls (no re-fit needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…xport)

Pre-PR cleanup from the review pass:
- Re-export ALPHA_MAX_DEFAULT from cubic.metrics.microssim so callers can
  reference the default without reaching into the ri_factor submodule.
- Validate alpha_max eagerly in MicroSSIM.__init__ (NaN, ±inf, <=1 now
  raise at construction instead of after an expensive fit-time pass).
- Drop a stale "[1e-3, 1e3]" reference from a test docstring after the
  default cap bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Introduces a configurable alpha_max cap for RI-factor bracketing in MicroSSIM, raises the default cap from 1e3 to 1e6, threads the parameter through the RI-factor helpers and MicroSSIM, and adds tests and exports to support external calibration and pinned RI factors.

Sequence diagram for configurable alpha_max propagation in MicroSSIM fit

sequenceDiagram
    actor User
    participant MicroSSIM
    participant get_global_ri_factor
    participant get_ri_factor
    participant _bracket_root

    User->>MicroSSIM: __init__(bg_percentile, offset_gt, offset_pred, max_val, ri_factor, alpha_max)
    MicroSSIM->>MicroSSIM: validate alpha_max
    MicroSSIM->>MicroSSIM: store _alpha_max

    User->>MicroSSIM: fit(gt, pred)
    MicroSSIM->>get_global_ri_factor: get_global_ri_factor(gt_norm, pred_norm, alpha_max=_alpha_max)
    get_global_ri_factor->>get_ri_factor: get_ri_factor(pooled, alpha_max)
    get_ri_factor->>get_ri_factor: validate alpha_max
    get_ri_factor->>_bracket_root: _bracket_root(flat, f1, alpha_max)
    _bracket_root-->>get_ri_factor: lo, hi, f_lo, f_hi
    get_ri_factor-->>get_global_ri_factor: alpha
    get_global_ri_factor-->>MicroSSIM: alpha
    MicroSSIM->>MicroSSIM: set _ri_factor = alpha
    MicroSSIM-->>User: MicroSSIM (fitted)
Loading

File-Level Changes

Change Details Files
Expose and validate alpha_max in RI-factor computation and MicroSSIM, and bump the default cap.
  • Replaced the internal _ALPHA_MAX constant with a public ALPHA_MAX_DEFAULT = 1e6 and exported it from the microssim package
  • Updated _bracket_root to take an alpha_max argument, use it as the right-hand expansion limit, and include it in the bracket-failure error message
  • Extended get_ri_factor to accept an alpha_max parameter with validation, forwarding it into _bracket_root, and updated its docstring to describe the new behavior
  • Extended get_global_ri_factor to accept an alpha_max parameter, documented it, and pass it down to get_ri_factor
  • Added an alpha_max parameter to MicroSSIM.init, validated it eagerly, stored it on the instance, and forwarded it into get_global_ri_factor in fit()
cubic/metrics/microssim/ri_factor.py
cubic/metrics/microssim/micro_ssim.py
cubic/metrics/microssim/__init__.py
Pin and document the constructor path for externally calibrated RI factors in MicroSSIM and MicroMS3IM.
  • Clarified MicroSSIM constructor docstring around using ri_factor to pin an externally calibrated alpha and skip fit()
  • Added tests to verify that MicroSSIM and MicroMS3IM constructed with ri_factor and normalization parameters can score without calling fit()
  • Added a test ensuring that providing ri_factor without required normalization parameters on MicroMS3IM raises a ValueError
cubic/metrics/microssim/micro_ssim.py
tests/metrics/microssim/test_micro_ssim.py
tests/metrics/microssim/test_micro_ms3im.py
Expand test coverage around alpha_max behavior and the new default cap.
  • Adjusted an existing bisection-bracketing test to call _bracket_root with an explicit alpha_max=1e3 to preserve its assumptions
  • Added tests that alpha_max <= 1 is rejected in get_ri_factor and MicroSSIM.init
  • Added tests showing that the new default alpha_max allows heavy down-scaled predictions to succeed while an explicit low cap reproduces the previous bracket failure
  • Added a test ensuring get_global_ri_factor forwards alpha_max through to get_ri_factor and that default vs low caps affect behavior as expected
  • Updated an existing NaN/inf-guard test docstring to refer to the generic default bracket window instead of a hard-coded numeric range
tests/metrics/microssim/test_ri_factor.py
tests/metrics/microssim/test_micro_ssim.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The alpha_max validation logic is duplicated in both get_ri_factor and MicroSSIM.__init__; consider factoring this into a small shared helper to keep behavior and error messages in sync.
  • Now that MicroSSIM exposes an alpha_max knob, you may want to surface a corresponding parameter on MicroMS3IM (or document how to tune it indirectly) so callers using the higher-level API can control the same behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `alpha_max` validation logic is duplicated in both `get_ri_factor` and `MicroSSIM.__init__`; consider factoring this into a small shared helper to keep behavior and error messages in sync.
- Now that `MicroSSIM` exposes an `alpha_max` knob, you may want to surface a corresponding parameter on `MicroMS3IM` (or document how to tune it indirectly) so callers using the higher-level API can control the same behavior.

## Individual Comments

### Comment 1
<location path="cubic/metrics/microssim/micro_ssim.py" line_range="65-70" />
<code_context>
         offset_pred: float | None = None,
         max_val: float | None = None,
         ri_factor: float | None = None,
+        alpha_max: float = ALPHA_MAX_DEFAULT,
     ) -> None:
+        if not (np.isfinite(alpha_max) and alpha_max > 1.0):
+            raise ValueError(f"alpha_max must be a finite float > 1; got {alpha_max}")
         self._bg_percentile = bg_percentile
</code_context>
<issue_to_address>
**suggestion:** alpha_max is validated even when ri_factor is supplied and alpha_max is documented as having no effect in that case

Because the constructor still validates `alpha_max` even when `ri_factor` is provided, callers may see a `ValueError` for a parameter that is documented as having no effect in this case. To avoid this mismatch, either skip `alpha_max` validation when `ri_factor` is not `None`, or update the docs to state that `alpha_max` is always validated regardless of whether it affects the computation.

```suggestion
        ri_factor: float | None = None,
        alpha_max: float = ALPHA_MAX_DEFAULT,
    ) -> None:
        # Only validate alpha_max when it is actually used (i.e., when ri_factor is not supplied)
        if ri_factor is None and not (np.isfinite(alpha_max) and alpha_max > 1.0):
            raise ValueError(f"alpha_max must be a finite float > 1; got {alpha_max}")
        self._bg_percentile = bg_percentile
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread cubic/metrics/microssim/micro_ssim.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes the MicroSSIM “range-invariant factor” (RI-factor) fitting more configurable and robust by exposing an alpha_max cap through the public API, increasing the default cap to handle heavily down-scaled predictions, and adding tests that document/lock in these behaviors (including scoring with a pinned, externally-calibrated ri_factor).

Changes:

  • Add alpha_max to get_ri_factor, get_global_ri_factor, and MicroSSIM.__init__, and re-export ALPHA_MAX_DEFAULT.
  • Increase the default bracketing cap from 1e3 to 1e6 and validate alpha_max eagerly.
  • Add tests for alpha_max behavior/forwarding and for “pinned ri_factor skips fit()” usage in MicroSSIM/MicroMS3IM.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
cubic/metrics/microssim/ri_factor.py Adds alpha_max plumbing/default and updates bracketing behavior + docs.
cubic/metrics/microssim/micro_ssim.py Adds alpha_max to constructor, validates/stores it, forwards to global fit.
cubic/metrics/microssim/__init__.py Re-exports ALPHA_MAX_DEFAULT at the subpackage level.
tests/metrics/microssim/test_ri_factor.py Adds coverage for alpha_max validation, default behavior, and forwarding.
tests/metrics/microssim/test_micro_ssim.py Tests constructor alpha_max propagation and pinned-ri_factor scoring path.
tests/metrics/microssim/test_micro_ms3im.py Tests pinned-ri_factor scoring and validation inherited from MicroSSIM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cubic/metrics/microssim/ri_factor.py
alxndrkalinin and others added 2 commits May 26, 2026 11:51
- Eager-validate alpha_max in get_global_ri_factor before the per-slice
  compute_ssim_elements loop (avoids O(N) wasted work on bad input).
- Make alpha_max keyword-only in get_ri_factor / get_global_ri_factor /
  MicroSSIM.__init__ so positional misuse can't bind silently.
- Document the power-of-2 probe granularity in the alpha_max docstring
  (effective largest probe = floor of log2(alpha_max)).
- Document that get_parameters() intentionally does NOT round-trip
  alpha_max (mirrors upstream MicroSSIM's key set verbatim).
- Tighten pinned-ri_factor score-equality tests from `< 1e-12` to `==`
  to express the bit-exact invariant — same params + same inputs through
  the same code path must produce the same float, not just a close one.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Symmetric mirror of the alpha_max work: the bracket solver's left-side
floor is now a public kwarg on get_ri_factor / get_global_ri_factor /
MicroSSIM.__init__ (default 1e-6, bumped from the old hardcoded 1e-3).
Use case: heavily up-scaled predictions (pred ~ 1e5 * gt) push the
optimum to alpha ~ 1e-5, below the old 1e-3 floor; the bumped default
now succeeds, and an explicit alpha_min raises cleanly when the floor
is set above the optimum.

Refactored validation into a shared _validate_alpha_bounds helper so
get_ri_factor / get_global_ri_factor / MicroSSIM.__init__ all enforce
the same contract: alpha_min in (0, 1), alpha_max > 1, both finite,
both keyword-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alxndrkalinin alxndrkalinin changed the title feat(metrics): expose alpha_max kwarg in microssim; bump default to 1e6 feat(metrics): expose alpha_min + alpha_max kwargs in microssim May 26, 2026
alxndrkalinin and others added 2 commits May 26, 2026 13:30
…ailure

The doubling/halving bracket walks at powers of 2, so it could miss a
sign change in (last_probe, alpha_max] (or [alpha_min, last_probe))
when the cap isn't itself a power of 2 — e.g. with the default
alpha_max=1e6 the last probe is 2**19 = 524288, leaving (524288, 1e6]
uncovered. Now probe the cap itself once if the doubling/halving
schedule overshoots it, so the full requested interval is actually
explored before raising RuntimeError.

Caught by Copilot review on cubic/metrics/microssim/ri_factor.py:209.

Also adds MicroMS3IM(alpha_min=..., alpha_max=...) inheritance test
per Sourcery's overall feedback, pinning the contract that the new
kwargs work uniformly across the class hierarchy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@alxndrkalinin alxndrkalinin merged commit 908a22f into main May 26, 2026
9 checks passed
@alxndrkalinin alxndrkalinin deleted the feat/microssim-expose-alpha-max branch May 26, 2026 20:49
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.

2 participants