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

Automatic scaling of constraint coefficients and RHS #780

Closed

Conversation

RuaridhMacd
Copy link
Collaborator

Description

This PR creates an option to automatically scale the coefficient matrix and RHS of a problem to be within user-defined bounds. It achieves this by multiplying or dividing constraints (i.e. scaling rows), and using proxy variables to scale parts of columns.

Large GenX problems can become numerically unstable if their constraints have large ranges of coefficients, the coefficients are very large or small, or the RHS is very large or small. There are many ways to address this, but one is to scale the rows and columns so that all the coefficients in the problem are within a desired range.
Some more details are given here: https://www.gurobi.com/documentation/current/refman/advanced_user_scaling.html

This PR implements those methods. The results are not affected in my testing, other than becoming more stable. Run times increase for small problems, due to the overhead of the method, and decrease in larger problems.

For example, I recently had a model with the following issues:
image

After scaling, it had this matrix:
image

The results were the same in both instances.

Some additional notes:

  • The feature is activated by the AdvancedScaling setting
  • I have currently defaulted the scaling to be ON (AdvancedScaling = 1), as it generally only helps models. This could be changed to avoid any bugs being triggered by default.
  • There are several additional settings that I need to document, e.g. coefficient lower / upper bounds, logging, etc.
  • Columns are scaled using proxy variables (e.g. x' = 10^5 x to divide the original 'x' variable b 10^5). This is currently done per-row. I will update this to allow columns or elements in a column to use the same proxy variable.
  • The default settings also allow for recursive proxy variables (e.g. x'' = 10^3 x', x' = 10^5 x is we wanted to reduce the original variable by 10^8 but were only allowed coefficients up to 10^5). I am not sure if this is always sensible, so we may want to turn this off by default.
  • The settings are stored in a separate struct to avoid adding a lot of settings with short names to the main settings Dict. This is borrowed from Dolphyn, and could be changed.
  • I need to update the document to reflect the new features
  • I need to implement proxy variable caching to reduce the number created.
  • I have only implemented this for single stage models, so far, as I need to work out how any adjustments to the model will be impacted by scaling the previous time-step.

What type of PR is this? (check all applicable)

  • Feature
  • Bug Fix
  • Documentation Update
  • Code Refactor
  • Performance Improvements

Related Tickets & Documents

Checklist

  • Code changes are sufficiently documented; i.e. new functions contain docstrings and .md files under /docs/src have been updated if necessary.
  • The latest changes on the target branch have been incorporated, so that any conflicts are taken care of before merging. This can be accomplished either by merging in the target branch (e.g. 'git merge develop') or by rebasing on top of the target branch (e.g. 'git rebase develop'). Please do not hesitate to reach out to the GenX development team if you need help with this.
  • Code has been tested to ensure all functionality works as intended.
  • CHANGELOG.md has been updated (if this is a 'notable' change).
  • I consent to the release of this PR's code under the GNU General Public license.

How this can be tested

I recommend trying it with all the single-stage examples. They worked on my machine and gave the same result.

Post-approval checklist for GenX core developers

After the PR is approved

  • Check that the latest changes on the target branch are incorporated, either via merge or rebase
  • Remember to squash and merge if incorporating into develop

Currently defaults to be on.
I've used a slightly odd way of storing the settings, from Dolphyn. I think it keeps the names simpler as we can use shorter names in topic-specific structs.
@RuaridhMacd RuaridhMacd added the enhancement New feature or request label Oct 7, 2024
@RuaridhMacd RuaridhMacd self-assigned this Oct 7, 2024
if has_upper_bound(var)
set_upper_bound(proxy_var, upper_bound(var) * multiplier)
end
@constraint(model, var == proxy_var * multiplier)
Copy link

Choose a reason for hiding this comment

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

This may make the coefficients look nicer, but it doesn't actually help.

See https://www.gurobi.com/documentation/current/refman/avoid_hiding_large_coeffic.html

You may also want to take a read of https://jump.dev/JuMP.jl/dev/tutorials/getting_started/tolerances/

@lbonaldo
Copy link
Collaborator

lbonaldo commented Nov 7, 2024

I’m closing this PR as we’ve decided to move this contribution to a separate package. Thanks to @RuaridhMacd for working on it.

@lbonaldo lbonaldo closed this Nov 7, 2024
@RuaridhMacd
Copy link
Collaborator Author

Thanks @lbonaldo
The new package is here: https://github.com/macroenergy/MacroEnergySystemsScaling.jl

I've registered it, so it should be available early next week

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants