Source code for openmdao.vectors.bound_map
"""Name-keyed mapping of optimizer bounds, storing None for entirely-unbounded variables."""
from dataclasses import dataclass
import numpy as np
@dataclass(slots=True)
class _VarBounds:
"""
Bounds for a single optimizer variable.
Attributes
----------
lower : ndarray or None
Lower bound array, or None if entirely unbounded below.
upper : ndarray or None
Upper bound array, or None if entirely unbounded above.
equals : ndarray or None
Equality value array, or None if not an equality constraint.
"""
lower: object
upper: object
equals: object
def _compact(arr, is_lower):
"""
Return arr, or None if all elements are the unbounded infinity for this direction.
Parameters
----------
arr : ndarray or None
Bound array.
is_lower : bool
True if this is a lower bound (checks for all -inf), False for upper (all +inf).
Returns
-------
ndarray or None
"""
if arr is None:
return None
arr = np.asarray(arr, dtype=float).ravel()
if is_lower:
return None if np.all(np.isneginf(arr)) else arr
return None if np.all(np.isposinf(arr)) else arr
[docs]
class BoundMap:
"""
Name-keyed mapping of optimizer bounds.
Each entry holds lower, upper, and equals bounds for one variable. Entirely-unbounded
directions are stored as None rather than an array of ±inf, avoiding unnecessary
memory allocation for large unbounded variables.
Attributes
----------
_data : dict[str, _VarBounds]
Per-variable bounds objects.
"""
[docs]
def __init__(self):
"""Initialize BoundMap."""
self._data = {}
[docs]
def set(self, name, lower, upper, equals):
"""
Store bounds for a single variable.
Parameters
----------
name : str
Variable name.
lower : ndarray or None
Lower bound in scaled units, or None if entirely unbounded below.
upper : ndarray or None
Upper bound in scaled units, or None if entirely unbounded above.
equals : ndarray or None
Equality value in scaled units, or None if not an equality constraint.
"""
self._data[name] = _VarBounds(
_compact(lower, is_lower=True),
_compact(upper, is_lower=False),
equals if equals is None else np.asarray(equals, dtype=float).ravel(),
)
[docs]
def __getitem__(self, name):
"""
Return the _VarBounds for a variable.
Parameters
----------
name : str
Variable name.
Returns
-------
_VarBounds
Bounds object with .lower, .upper, .equals attributes.
Raises
------
KeyError
If variable name not found.
"""
if name not in self._data:
raise KeyError(f"Variable '{name}' not found in BoundMap")
return self._data[name]
[docs]
def __contains__(self, name):
"""Return True if name is in the dict."""
return name in self._data
[docs]
def __iter__(self):
"""Iterate over variable names."""
return iter(self._data)
[docs]
def keys(self):
"""Return variable names."""
return self._data.keys()
[docs]
def items(self):
"""Iterate over (name, _VarBounds) pairs."""
return self._data.items()