Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nonlinear constraints #353 #371

Merged
merged 72 commits into from
Aug 28, 2024
Merged

Conversation

MarkBlyth
Copy link
Contributor

@MarkBlyth MarkBlyth commented Jun 18, 2024

Description

Enables nonlinear optimisation constraints. This turned out to be somewhat trivial with the newest PyBOP API; all it needed was a slightly different callback signature for the "trust-constr" optimiser.

Issue reference

Fixes #353

Review

Before you mark your PR as ready for review, please ensure that you've considered the following:

  • Updated the CHANGELOG.md in reverse chronological order (newest at the top) with a concise description of the changes, including the PR number.
  • Noted any breaking changes, including details on how it might impact existing functionality.

Type of change

  • New Feature: A non-breaking change that adds new functionality.
  • Optimization: A code change that improves performance.
  • Examples: A change to existing or additional examples.
  • Bug Fix: A non-breaking change that addresses an issue.
  • Documentation: Updates to documentation or new documentation for new features.
  • Refactoring: Non-functional changes that improve the codebase.
  • Style: Non-functional changes related to code style (formatting, naming, etc).
  • Testing: Additional tests to improve coverage or confirm functionality.
  • Other: (Insert description of change)

Key checklist:

  • No style issues: $ pre-commit run (or $ nox -s pre-commit) (see CONTRIBUTING.md for how to set this up to run automatically when committing locally, in just two lines of code)
  • All unit tests pass: $ nox -s tests
  • The documentation builds: $ nox -s doctest

You can run integration tests, unit tests, and doctests together at once, using $ nox -s quick.

Further checks:

  • Code is well-commented, especially in complex or unclear areas.
  • Added tests that prove my fix is effective or that my feature works.
  • Checked that coverage remains or improves, and added tests if necessary to maintain or increase coverage.

Thank you for contributing to our project! Your efforts help us to deliver great software.

@NicolaCourtier
Copy link
Member

Hi @MarkBlyth, great to hear that you could achieve the desired functionality with the current code structure!

I wonder if you could achieve the same result more efficiently (and for all optimisers) by extending the check_params function, because this function is run before the model is called rather than after. Did you try this?

@MarkBlyth
Copy link
Contributor Author

MarkBlyth commented Jun 20, 2024

I wonder if you could achieve the same result more efficiently (and for all optimisers) by extending the check_params function, because this function is run before the model is called rather than after. Did you try this?

Interesting idea, I hadn't thought of that! I've included an example now of using a subclassed Thevenin model, where the check_params does the constraining. Happy to integrate it into the core ECM file, if that's a route we want to go down.

I'd lean towards wanting to pass the parameter constraints into the optimiser, rather than the model. But given that this works easily and has no breaking changes, then perhaps it's the right way to go.

@NicolaCourtier
Copy link
Member

Hi @MarkBlyth, thanks for the two examples! I've just merged #388 into develop so please check if it helps. Have you compared the performance of the two methods?

I like the extension of the SciPy callback function to wrap around base_callback as this would allow any other type of callback to be used as well, so we should add this feature.

For constraints though, I think the check_params method is more extensible and could be implemented similar to the SciPy method, i.e. I think we can pass a constraints function to be run within the check_params function, without defining a new class.

@MarkBlyth
Copy link
Contributor Author

Have you compared the performance of the two methods?

trust-constr seems a bit faster and more robust.

The extra speed is possibly because it's a gradient-based method, which is suitable for this particular flavour of problem.

For robustness, I've found the gradient-free / metaheuristic optimisers can sometimes give up (for lack of better phrasing!) when I try to apply fairly tight bounds, whereas trust-constr manages. These tight bounds can be useful when trying to resolve fast timescales in GITT data. Maybe implementing the bounds at an optimiser level could help with that, e.g. changing sample-point distributions to ensure they always remain inside the bounds, so that the optimiser doesn't give up after seeing a big list of inf returns.

I think we can pass a constraints function to be run within the check_params function, without defining a new class.

Yep agreed, that sounds like the nicest way to do it. I'll get on that.

@MarkBlyth MarkBlyth requested review from NicolaCourtier and removed request for NicolaCourtier July 30, 2024 15:05
@MarkBlyth
Copy link
Contributor Author

Finally got round to committing these changes. So far I've only set up the empirical models to take a user-defined parameter checker, but I'm sure the same could be done easily for physics-based models too

@NicolaCourtier
Copy link
Member

Hi @MarkBlyth, looks like you're almost ready to merge but I noticed a small mistake in the develop version of the SciPyMinimize logging. Please could you consider fixing it alongside your additions?

The fix is to add a default value of self._cost0 = 1.0 to the SciPyMinimize.__init__ and line 197 to become:
self.log["cost"].append((cost if self.minimising else -cost)*self._cost0)
to rescale the cost value before logging. Otherwise I can create a separate issue and pull request...

@MarkBlyth
Copy link
Contributor Author

@NicolaCourtier fix pushed, should be ready to merge now!

Copy link
Member

@BradyPlanden BradyPlanden left a comment

Choose a reason for hiding this comment

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

This is looking great, a few suggestions/requests. Happy to merge once they are resolved! Nice one @MarkBlyth

pybop/optimisers/scipy_optimisers.py Outdated Show resolved Hide resolved
pybop/optimisers/scipy_optimisers.py Show resolved Hide resolved
pybop/optimisers/scipy_optimisers.py Outdated Show resolved Hide resolved
examples/notebooks/ecm_trust-constr.ipynb Outdated Show resolved Hide resolved
examples/notebooks/ecm_trust-constr.ipynb Outdated Show resolved Hide resolved
MarkBlyth and others added 10 commits August 23, 2024 10:22
Co-authored-by: Brady Planden <55357039+BradyPlanden@users.noreply.github.com>
Co-authored-by: Brady Planden <55357039+BradyPlanden@users.noreply.github.com>
Co-authored-by: Brady Planden <55357039+BradyPlanden@users.noreply.github.com>
…r integration tests, small fixes on examples
@BradyPlanden BradyPlanden linked an issue Aug 27, 2024 that may be closed by this pull request
@BradyPlanden BradyPlanden merged commit cd07b14 into pybop-team:develop Aug 28, 2024
30 of 31 checks passed
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.

[Bug]: SciPy bounds are not enforced Allow nonlinear constraints
3 participants