ModelChangeDetector

(class from pyomo.contrib.observer.model_observer)

class pyomo.contrib.observer.model_observer.ModelChangeDetector(model: BlockData, observers: Sequence[Observer], **kwds)[source]

Bases: object

This class “watches” a pyomo model and notifies the observers when any changes to the model are made (but only when ModelChangeDetector.update is called). An example use case is for the persistent solver interfaces.

The ModelChangeDetector considers the model to be defined by its set of active components and any components used by those active components. For example, the observers will not be notified of the addition of a variable if that variable is not used in any constraints.

The Observer/ModelChangeDetector are most useful when a small number of changes are being made relative to the size of the model. For example, the persistent solver interfaces can be very efficient when repeatedly solving the same model but with different values for mutable parameters.

If you know that certain changes will not be made to the model, the config can be modified to improve performance. For example, if you know that no constraints will be added to or removed from the model, then check_for_new_or_removed_constraints can be set to False, which will save some time when update is called.

Here are some usage examples:

>>> import pyomo.environ as pyo
>>> from typing import Mapping
>>> from pyomo.contrib.observer.model_observer import (
...     AutoUpdateConfig,
...     Observer,
...     ModelChangeDetector,
...     Reason,
... )
>>> from pyomo.core.base import (
...     VarData,
...     ParamData,
...     ConstraintData,
...     SOSConstraintData,
...     ObjectiveData,
... )
>>> class PrintObserver(Observer):
...     def _update_variables(self, vars: Mapping[VarData, Reason]):
...         for v, r in vars.items():
...             print(f'{v}: {r.name}')
...     def _update_parameters(self, params: Mapping[ParamData, Reason]):
...         for p, r in params.items():
...             print(f'{p}: {r.name}')
...     def _update_constraints(self, cons: Mapping[ConstraintData, Reason]):
...         for c, r in cons.items():
...             print(f'{c}: {r.name}')
...     def _update_sos_constraints(self, cons: Mapping[SOSConstraintData, Reason]):
...         for c, r in cons.items():
...             print(f'{c}: {r.name}')
...     def _update_objectives(self, objs: Mapping[ObjectiveData, Reason]):
...         for o, r in objs.items():
...             print(f'{o}: {r.name}')
>>> m = pyo.ConcreteModel()
>>> obs = PrintObserver()
>>> detector = ModelChangeDetector(m, [obs])
>>> m.x = pyo.Var()
>>> m.y = pyo.Var()
>>> detector.update()  # no output because the variables are not used
>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
>>> detector.update()
x: added
y: added
obj: added
>>> del m.obj
>>> detector.update()
obj: removed
x: removed
y: removed
>>> m.px = pyo.Param(mutable=True, initialize=1)
>>> m.py = pyo.Param(mutable=True, initialize=1)
>>> m.obj = pyo.Objective(expr=m.px*m.x + m.py*m.y)
>>> detector.update()
x: added
y: added
px: added
py: added
obj: added
>>> m.px.value = 2
>>> detector.update()
px: value
>>> detector.config.check_for_new_or_removed_constraints = False
>>> detector.config.check_for_new_or_removed_objectives = False
>>> detector.config.update_constraints = False
>>> detector.config.update_vars = False
>>> detector.config.update_parameters = True
>>> detector.config.update_named_expressions = False
>>> detector.config.update_objectives = False
>>> for i in range(10):
...     m.py.value = i
...     detector.update()  # this will be faster because it is only checking for changes to parameters
py: value
py: value
py: value
py: value
py: value
py: value
py: value
py: value
py: value
py: value
>>> m.c = pyo.Constraint(expr=m.y >= pyo.exp(m.x))
>>> detector.update()  # no output because we did not check for new constraints
>>> detector.config.check_for_new_or_removed_constraints = True
>>> detector.update()
c: added
__init__(model: BlockData, observers: Sequence[Observer], **kwds)[source]
Parameters:
  • model (BlockData) – The model for which changes should be detected

  • observers (Sequence[Observer]) – The objects to notify when changes are made to the model

Methods

__init__(model, observers, **kwds)

add_constraints(cons)

add_objectives(objs)

add_sos_constraints(cons)

get_constraints_impacted_by_param(p)

get_constraints_impacted_by_var(v)

get_objectives_impacted_by_param(p)

get_objectives_impacted_by_var(v)

get_variables_impacted_by_param(p)

remove_constraints(cons)

remove_objectives(objs)

remove_sos_constraints(cons)

update([timer])

Check for changes to the model and notify the observers.

update_constraints([cons])

update_objectives([objs])

update_parameters(params)

update_sos_constraints([cons])

update_variables([variables])

Member Documentation

update(timer: HierarchicalTimer | None = None, **kwds)[source]

Check for changes to the model and notify the observers.

Parameters:

timer (Optional[HierarchicalTimer]) – The timer to use for tracking how much time is spent detecting different kinds of changes