Skip to content

Discussion: Adding inherent support for scaling #1905

Open
@staadecker

Description

@staadecker

Hello there,

As part of my work, I've been developing a better solution to scaling and wonder if there's interest to integrate some form of my work directly into Pyomo.

The problem

My biggest issues with the scaling transformation plugin that currently exists is

  1. It's clumsy to use. I need to create a copy of the model and then back-propagate the changes once the model is solved. I also need to define the scaling factors in a different place than where I define my variables and constraints.

  2. It's slow. Recreating a copy of the entire model takes several minutes for the size of data I'm working with (it also uses way too much memory since I now have two models stored in memory).

Proposal

What I'd love to see and what I'm proposing is for Objective(), Constraint(), and Var() to accept a parameter called
scaling_factor that would scale the respective object automatically.

For Objective() and Constraint() this seems straightforward. Simply multiply their expressions internally by scaling_factor (for constraints we'd multiply both the left-hand and right-hand sides).

For Var() this is a bit more challenging. Here's what I've done on my end and I'm open to other suggestions.

I've overridden the __setattr__ function of Pyomo's AbstractModel to allow for special
behaviours when we assign a Var to the model with scaling_factor != 1.
For example, during the following call.

model.MyVariable = Var(..., scaling_factor=10)

My modified __setattr__ will actually do the following internally.

model._scaled_MyVariable = Var(..., scaling_factor=10)
model.MyVariable = Expression(..., rule=_scaled_MyVariable / scaling_factor)

This way whenever we use MyVariable elsewhere in my code, I'm actually referencing the unscaled version
of _scaled_MyVariable. This means that to the developers perspective it's like we never scaled the variable in the first place,
but to Pyomo's perspective, _scaled_MyVariable is the underlying variable that is used.

Possible issues

Some things I haven't thought about

  • Behaviour when using ConcreteModel
  • Handling of how to set a default value to a scaled variable (since now the scaled variable is actually an Expression)
  • Other differences between Expression and Var that I'm not aware about.

Possible downsides

I think there is an argument to be made that setting the scaling factors after the model is defined is beneficial (since for me at least scaling is done as a correction on top of a model rather than while the model is being constructed). If we want to keep scaling factors separate that would be ok with me, however it would still be nice to not need to make a copy of the entire model. Something as simple as model.MyVariable.scaling_factor = 10 would seem ideal to me.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions