Skip to content

Deprecate use of LMLSQFitter for models with bounds - #16994

Merged
pllim merged 4 commits into
astropy:mainfrom
astrofrog:deprecate-bounds-lmlsqfitter
Oct 10, 2024
Merged

pllim merged 4 commits into
astropy:mainfrom
astrofrog:deprecate-bounds-lmlsqfitter

Conversation

@astrofrog

@astrofrog astrofrog commented Sep 11, 2024 •

Copy link
Copy Markdown
Member

Now that we have support for different non-linear fitters in astropy.modeling, including several that have proper support for bounds, we should consider starting to phase out support for the 'hacky' bounds algorithm originally introduced in LevMarLSQFitter. I noticed that in fact the new LMLSQFitter uses the hacky algorithm by default, with no way to turn it off.

I think we should instead deprecate this behavior in LMLSQFitter and recommend other fitters, and once the deprecation phase is over simply change supported_constraints to exclude bounds on that fitter. There are other more suitable fitters for models with bounds, and we should be encouraging good practices. Note that at the moment most examples in the docs use LevMarLSQFitter so I think there is likely to be far more usage of that class in the wild. For that reason, I am not touching that class for now - instead, I want to make sure that the new class LMLSQFitter does 'The Right Thing' ™️ before there is too much uptake in it.

If people are on board with this, I will update the tests, which currently fail due to the warning being emitted in several of them, and I will also add a changelog entry.

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@astrofrog
astrofrog requested a review from a team as a code owner September 11, 2024 10:19
@astrofrog
astrofrog marked this pull request as draft September 11, 2024 10:20
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@astrofrog astrofrog added this to the v7.0.0 milestone Sep 11, 2024

@Cadair Cadair left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this is "a good thing" ™️ (once the CI is fixed 😛)

@astrofrog

astrofrog commented Sep 11, 2024 •

Copy link
Copy Markdown
Member Author

The main reason the CI is failing in a number of places is because Gaussian1D uses bounds on stddev by default, and Gaussian1D is used as the de-facto model in tests. There are three main options at this point:

  1. Don't run the tests that use Gaussian1D with LMLSQFitter
  2. Re-write many tests to use a different model that doesn't have bounds
  3. Find another way to deal with restricting stddev to positive values on Gaussian1D that doesn't involve bounds

For option 3, what's interesting is that for instance Lorentz1D doesn't have bounds on the fwhm and we've never had any complaints. In fact, the equation of the gaussian works fine with negative sigma so this is more just about what users would expect, as they would find a negative sigma strange (even though it would be mathematically valid). So I wonder if we can find a different way to handle this. I did try a few things and ran into other issues.

Option 1 is the easiest, so it might make the most sense for now (this is what's I'll implement here for now)

@astrofrog
astrofrog marked this pull request as ready for review September 11, 2024 13:20
@astrofrog

Copy link
Copy Markdown
Member Author

I think the CI should be fixed now (I also think we need fixtures to avoid repeating the list of fitters in all test files, but that can wait)

@pllim

pllim commented Sep 11, 2024

Copy link
Copy Markdown
Member

but that can wait

You mean wait to merge until you have time for it here? Or open follow up issue? Hope you can clarify. Thanks!

@pllim pllim added the API change PRs and issues that change an existing API, possibly requiring a deprecation period label Sep 11, 2024
@pllim

pllim commented Sep 11, 2024

Copy link
Copy Markdown
Member

I wonder how many downstream packages will be affected by this deprecation warning... 👀

Comment thread astropy/modeling/fitting.py Resolved
Comment thread astropy/modeling/fitting.py Resolved
@Cadair

Cadair commented Sep 12, 2024

Copy link
Copy Markdown
Member

I wonder how many downstream packages will be affected by this deprecation warning... 👀

I would hope that not too many people are using this new LMSQ fitter when the ones with good bounds support were added at the same time. If people are using this I would assume they are doing it because they don't understand that they would probably be better off using one of the other ones.

@astrofrog

Copy link
Copy Markdown
Member Author

This definitely needs to be reviewed by @nden or @perrygreenfield as this is not a trivial change.

From searching code on GitHub I found a handful (perhaps a dozen or a little more) usages of LMLSQFitter with e.g. Gaussian models, so those will definitely receive deprecation warnings. So it will definitely impact some users, though I don't think it's very widespread as many many users will copy examples from docs which use LevMarLSQFitter. The users it does affect will get warnings and will have at least a year to adjust to using a different fitter.

Just for full disclosure, we could also still optionally support the current bounds algorithm via a use_min_max_bounds kwarg in the initializer in case users do want to opt in to it, but I think it just boils down to whether we still need to do this given that other fitters support bounds properly. If we don't support bounds at all in LMLSQFitter, we'll be doing the same as scipy's least_squares, which makes users use other algorithms for bounds support (which I think is reasonable).

@Cadair

Cadair commented Sep 12, 2024

Copy link
Copy Markdown
Member

I strongly think supporting use_min_max_bounds is a bad idea for anything but legacy use in LevMarLSQFitter.

@astrofrog
astrofrog force-pushed the deprecate-bounds-lmlsqfitter branch from ea9c322 to 5a91b8a Compare September 12, 2024 10:05

@nden nden 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.

This looks reasonable. I also agree we should not support use_min_max_bounds in LMLSQFitter . Those that find it useful can continue using it in LevMarLSQFitter.

@pllim
pllim merged commit 3a1004d into astropy:main Oct 10, 2024
@larrybradley

larrybradley commented Oct 11, 2024 •

Copy link
Copy Markdown
Member

@astrofrog FYI, this PR causes a photutils test to fail.

photutils PSF photometry accepts a fitter_maxiters keyword that is then passed on as maxiter to fitters that support it. It does this by inspecting the fitter __call__ function signature. By overriding the LMLSQFitter __call__ signature to simply __call__(self, model, *args, **kwargs) the maxiter keyword no longer explicitly shows up and a new photutils warning is raised, causing a test to fail. The _NLLSQFitter base class __call__ method explicitly has a maxiter keyword.

@larrybradley

Copy link
Copy Markdown
Member

Does it make sense to move maxiter to the fitter __init__ method? But that would be a bigger breaking change.....

@pllim

pllim commented Oct 11, 2024

Copy link
Copy Markdown
Member

Uh oh... should we revert this?

@larrybradley

Copy link
Copy Markdown
Member

To prevent the breaking API change, all that would be needed is to update the LMLSQFitter.__call__ signature to match the base class. I can open a PR to do that if you want.

@astrofrog

Copy link
Copy Markdown
Member Author

Yes that would be great, thanks!

@larrybradley

larrybradley commented Oct 11, 2024 •

Copy link
Copy Markdown
Member

The new __call__ method in this PR also does not have the @fitter_unit_support decorator. That is needed, right?

kkrutkowski pushed a commit to kkrutkowski/astropy that referenced this pull request Apr 13, 2025
* Deprecate use of LMLSQFitter for models with bounds

* Don't run tests that use models that have bounds with the LMLSQFitter

* Added changelog entry

* Improve deprecation warning

Co-authored-by: Clément Robert <[email protected]>

---------

Co-authored-by: Clément Robert <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API change PRs and issues that change an existing API, possibly requiring a deprecation period modeling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants