Warning
The pyomo.kernel
API is still in the beta phase of development. It is fully tested and functional; however, the interface may change as it becomes further integrated with the rest of Pyomo.
Warning
Models built with pyomo.kernel
components are not yet compatible with pyomo extension modules (e.g., PySP
, pyomo.dae
, pyomo.gdp
).
The pyomo.kernel
library is an experimental modeling interface designed to provide a better experience for users doing concrete modeling and advanced application development with Pyomo. It includes the basic set of modeling components <kernel_modeling_components>
necessary to build algebraic models, which have been redesigned from the ground up to make it easier for users to customize and extend. For a side-by-side comparison of pyomo.kernel
and pyomo.environ
syntax, visit the link below.
syntax_comparison.rst
Models built from pyomo.kernel
components are fully compatible with the standard solver interfaces included with Pyomo. A minimal example script that defines and solves a model is shown below.
examples/kernel_solving.py
Containers in pyomo.kernel
are analogous to indexed components in pyomo.environ
. However, pyomo.kernel
containers allow for additional layers of structure as they can be nested within each other as long as they have compatible categories. The following example shows this using pyomo.kernel.variable
containers.
examples/kernel_containers_all.spy
As the next section will show, the standard modeling component containers are also compatible with user-defined classes that derive from the existing modeling components.
The existing components and containers in pyomo.kernel
are designed to make sub-classing easy. User-defined classes that derive from the standard modeling components and containers in pyomo.kernel
are compatible with existing containers of the same component category. As an example, in the following code we see that the pyomo.kernel.block_list
container can store both pyomo.kernel.block
objects as well as a user-defined Widget
object that derives from pyomo.kernel.block
. The Widget
object can also be placed on another block object as an attribute and treated itself as a block.
class Widget(pyomo.kernel.block):
...
model = pyomo.kernel.block()
model.blist = pyomo.kernel.block_list()
model.blist.append(Widget())
model.blist.append(pyomo.kernel.block())
model.w = Widget()
model.w.x = pyomo.kernel.variable()
The next series of examples goes into more detail on how to implement derived components or containers.
The following code block shows a class definition for a non-negative variable, starting from pyomo.kernel.variable
as a base class.
examples/kernel_subclassing_Nonnegative.spy
The NonNegativeVariable
class prevents negative values from being stored into its lower bound during initialization or later on through assignment statements (e.g, x.lb = -1
fails). Note that the __slots__ == ()
line at the beginning of the class definition is optional, but it is recommended if no additional data members are necessary as it reduces the memory requirement of the new variable type.
The next code block defines a custom variable container called Point
that represents a 3-dimensional point in Cartesian space. The new type derives from the pyomo.kernel.variable_tuple
container and uses the NonNegativeVariable
type we defined previously in the z coordinate.
examples/kernel_subclassing_Point.spy
The Point
class can be treated like a tuple storing three variables, and it can be placed inside of other variable containers or added as attributes to blocks. The property methods included in the class definition provide an additional syntax for accessing the three variables it stores, as the next code example will show.
The following code defines a class for building a convex second-order cone constraint from a Point
object. It derives from the pyomo.kernel.constraint
class, overriding the constructor to build the constraint expression and utilizing the property methods on the point class to increase readability.
examples/kernel_subclassing_SOC.spy
The pyomo.kernel
library offers significant opportunities to reduce memory requirements for highly structured models. The situation where this is most apparent is when expressing a model in terms of many small blocks consisting of singleton components. As an example, consider expressing a model consisting of a large number of voltage transformers. One option for doing so might be to define a Transformer component as a subclass of pyomo.kernel.block
. The example below defines such a component, including some helper methods for connecting input and output voltage variables and updating the transformer ratio.
examples/transformer_kernel.spy
A simplified version of this using pyomo.environ
components might look like what is below.
examples/transformer_aml.spy
The transformer expressed using pyomo.kernel
components requires roughly 2 KB of memory, whereas the pyomo.environ
version requires roughly 8.4 KB of memory (an increase of more than 4x). Additionally, the pyomo.kernel
transformer is fully compatible with all existing pyomo.kernel
block containers.
Pyomo 5.6.3 introduced support into pyomo.kernel
for six conic constraint forms that are directly recognized by the new Mosek solver interface. These are
conic.quadratic
:∑ixi2 ≤ r2, r ≥ 0
conic.rotated_quadratic
:∑ixi2 ≤ 2r1r2, r1, r2 ≥ 0
conic.primal_exponential
:x1exp (x2/x1) ≤ r, x1, r ≥ 0
conic.primal_power
(α is a constant):||x||2 ≤ r1αr21 − α, r1, r2 ≥ 0, 0 < α < 1
conic.dual_exponential
:− x2exp ((x1/x2) − 1) ≤ r, x2 ≤ 0, r ≥ 0
conic.dual_power
(α is a constant):||x||2 ≤ (r1/α)α(r2/(1 − α))1 − α, r1, r2 ≥ 0, 0 < α < 1
Other solver interfaces will treat these objects as general nonlinear or quadratic constraints, and may or may not have the ability to identify their convexity. For instance, Gurobi will recognize the expressions produced by the quadratic
and rotated_quadratic
objects as representing convex domains as long as the variables involved satisfy the convexity conditions. However, other solvers may not include this functionality.
Each of these conic constraint classes are of the same category type as standard pyomo.kernel.constraint
object, and, thus, are directly supported by the standard constraint containers (constraint_tuple
, constraint_list
, constraint_dict
).
Each conic constraint class supports two methods of instantiation. The first method is to directly instantiate a conic constraint object, providing all necessary input variables:
examples/conic_Class.spy
This method may be limiting if utilizing the Mosek solver as the user must ensure that additional conic constraints do not use variables that are directly involved in any existing conic constraints (this is a limitation the Mosek solver itself).
To overcome this limitation, and to provide a more general way of defining conic domains, each conic constraint class provides the as_domain
class method. This alternate constructor has the same argument signature as the class, but in place of each variable, one can optionally provide a constant, a linear expression, or None
. The as_domain
class method returns a block
object that includes the core conic constraint, auxiliary variables used to express the conic constraint, as well as auxiliary constraints that link the inputs (that are not None
) to the auxiliary variables. Example:
examples/conic_Domain.spy
block.rst variable.rst constraint.rst parameter.rst objective.rst expression.rst sos.rst suffix.rst piecewise/index.rst conic.rst
base.rst homogeneous_container.rst heterogeneous_container.rst
tuple_container.rst list_container.rst dict_container.rst