Skip to content

Commit

Permalink
Merge branch 'main' into benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
blnicho authored Jan 9, 2024
2 parents 973fb23 + d04f6bb commit b4e9f47
Show file tree
Hide file tree
Showing 26 changed files with 146 additions and 104 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ version, we will remove testing for that Python version.

### Tutorials and Examples

* [Pyomo Workshop Slides](https://software.sandia.gov/downloads/pub/pyomo/Pyomo-Workshop-Summer-2018.pdf)
* [Pyomo Workshop Slides](https://github.com/Pyomo/pyomo-tutorials/blob/main/Pyomo-Workshop-December-2023.pdf)
* [Prof. Jeffrey Kantor's Pyomo Cookbook](https://jckantor.github.io/ND-Pyomo-Cookbook/)
* [Pyomo Gallery](https://github.com/Pyomo/PyomoGallery)

Expand Down
3 changes: 3 additions & 0 deletions doc/OnlineDocs/contributed_packages/gdpopt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ To use the GDPopt-LBB solver, define your Pyomo GDP model as usual:
>>> m.djn = Disjunction(expr=[m.y1, m.y2])

Invoke the GDPopt-LBB solver

>>> results = SolverFactory('gdpopt.lbb').solve(m)
WARNING: 09/06/22: The GDPopt LBB algorithm currently has known issues. Please
use the results with caution and report any bugs!

>>> print(results) # doctest: +SKIP
>>> print(results.solver.status)
Expand Down
14 changes: 0 additions & 14 deletions doc/OnlineDocs/developer_reference/expressions/managing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,6 @@ a consistent ordering of terms that should make it easier to interpret
expressions.


Cloning Expressions
-------------------

Expressions are automatically cloned only during certain expression
transformations. Since this can be an expensive operation, the
:data:`clone_counter <pyomo.core.expr.clone_counter>` context
manager object is provided to track the number of times the
:func:`clone_expression <pyomo.core.expr.clone_expression>`
function is executed.

For example:

.. literalinclude:: ../../tests/expr/managing_ex4.spy

Evaluating Expressions
----------------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ Context Managers
.. autoclass:: pyomo.core.expr.linear_expression
:members:

.. autoclass:: pyomo.core.expr.clone_counter
.. autoclass:: pyomo.core.expr.current.clone_counter
:members:

3 changes: 3 additions & 0 deletions doc/OnlineDocs/tutorial_examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Pyomo Tutorial Examples

Additional Pyomo tutorials and examples can be found at the following links:

`Pyomo Workshop Slides and Exercises
<https://github.com/Pyomo/pyomo-tutorials>`_

`Prof. Jeffrey Kantor's Pyomo Cookbook
<https://jckantor.github.io/ND-Pyomo-Cookbook/>`_

Expand Down
17 changes: 16 additions & 1 deletion pyomo/common/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

from .deprecation import deprecated, deprecation_warning, in_testing_environment
from .errors import DeferredImportError
from . import numeric_types


SUPPRESS_DEPENDENCY_WARNINGS = False
Expand Down Expand Up @@ -743,6 +742,12 @@ def _finalize_yaml(module, available):
yaml_load_args['Loader'] = module.SafeLoader


def _finalize_ctypes(module, available):
# ctypes.util must be explicitly imported (and fileutils assumes
# this has already happened)
import ctypes.util


def _finalize_scipy(module, available):
if available:
# Import key subpackages that we will want to assume are present
Expand Down Expand Up @@ -778,6 +783,8 @@ def _finalize_matplotlib(module, available):
def _finalize_numpy(np, available):
if not available:
return
from . import numeric_types

# Register ndarray as a native type to prevent 1-element ndarrays
# from accidentally registering ndarray as a native_numeric_type.
numeric_types.native_types.add(np.ndarray)
Expand Down Expand Up @@ -835,6 +842,14 @@ def _pyutilib_importer():
return importlib.import_module('pyutilib')


# Standard libraries that are slower to import and not strictly required
# on all platforms / situations.
ctypes, _ = attempt_import(
'ctypes', deferred_submodules=['util'], callback=_finalize_ctypes
)
random, _ = attempt_import('random')

# Commonly-used optional dependencies
dill, dill_available = attempt_import('dill')
mpi4py, mpi4py_available = attempt_import('mpi4py')
networkx, networkx_available = attempt_import('networkx')
Expand Down
3 changes: 2 additions & 1 deletion pyomo/common/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________

import ctypes
import os

from .dependencies import ctypes


def _as_bytes(val):
"""Helper function to coerce a string to a bytes() object"""
Expand Down
2 changes: 1 addition & 1 deletion pyomo/common/fileutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
PathData
"""

import ctypes.util
import glob
import inspect
import logging
Expand All @@ -42,6 +41,7 @@
import sys

from . import envvar
from .dependencies import ctypes
from .deprecation import deprecated, relocated_module_attribute

relocated_module_attribute('StreamIndenter', 'pyomo.common.formatting', version='6.2')
Expand Down
4 changes: 2 additions & 2 deletions pyomo/common/modeling.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________

from random import random
import sys
from .dependencies import random


def randint(a, b):
Expand All @@ -21,7 +21,7 @@ def randint(a, b):
can support deterministic testing (i.e., setting the random.seed and
expecting the same sequence), we will implement a simple, but stable
version of randint()."""
return int((b - a + 1) * random())
return int((b - a + 1) * random.random())


def unique_component_name(instance, name):
Expand Down
8 changes: 8 additions & 0 deletions pyomo/common/numeric_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import logging
import sys

from pyomo.common.dependencies import numpy_available
from pyomo.common.deprecation import deprecated, relocated_module_attribute
from pyomo.common.errors import TemplateExpressionError

Expand Down Expand Up @@ -207,6 +208,13 @@ def check_if_numeric_type(obj):
if obj_class in native_types:
return obj_class in native_numeric_types

if 'numpy' in obj_class.__module__:
# trigger the resolution of numpy_available and check if this
# type was automatically registered
bool(numpy_available)
if obj_class in native_numeric_types:
return True

try:
obj_plus_0 = obj + 0
obj_p0_class = obj_plus_0.__class__
Expand Down
2 changes: 1 addition & 1 deletion pyomo/contrib/parmest/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _add_scipy_dist_CI(
data_slice.append(np.array([[theta_star[var]] * ncells] * ncells))
data_slice = np.dstack(tuple(data_slice))

elif isinstance(dist, stats.kde.gaussian_kde):
elif isinstance(dist, stats.gaussian_kde):
for var in theta_star.index:
if var == xvar:
data_slice.append(X.ravel())
Expand Down
12 changes: 7 additions & 5 deletions pyomo/core/base/indexed_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@

import pyomo.core.expr as EXPR
import pyomo.core.base as BASE
from pyomo.core.expr.numeric_expr import NumericNDArray
from pyomo.core.expr.numvalue import native_types
from pyomo.core.base.indexed_component_slice import IndexedComponent_slice
from pyomo.core.base.initializer import Initializer
from pyomo.core.base.component import Component, ActiveComponent
from pyomo.core.base.config import PyomoOptions
from pyomo.core.base.enums import SortComponents
from pyomo.core.base.global_set import UnindexedComponent_set
from pyomo.core.expr.numeric_expr import _ndarray
from pyomo.core.pyomoobject import PyomoObject
from pyomo.common import DeveloperError
from pyomo.common.autoslots import fast_deepcopy
from pyomo.common.dependencies import numpy as np, numpy_available
from pyomo.common.deprecation import deprecated, deprecation_warning
from pyomo.common.errors import DeveloperError, TemplateExpressionError
from pyomo.common.modeling import NOTSET
from pyomo.common.numeric_types import native_types
from pyomo.common.sorting import sorted_robust

from collections.abc import Sequence
Expand Down Expand Up @@ -1216,7 +1216,7 @@ class IndexedComponent_NDArrayMixin(object):

def __array__(self, dtype=None):
if not self.is_indexed():
ans = NumericNDArray(shape=(1,), dtype=object)
ans = _ndarray.NumericNDArray(shape=(1,), dtype=object)
ans[0] = self
return ans

Expand All @@ -1236,10 +1236,12 @@ def __array__(self, dtype=None):
% (self, bounds[0], bounds[1])
)
shape = tuple(b + 1 for b in bounds[1])
ans = NumericNDArray(shape=shape, dtype=object)
ans = _ndarray.NumericNDArray(shape=shape, dtype=object)
for k, v in self.items():
ans[k] = v
return ans

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
return NumericNDArray.__array_ufunc__(None, ufunc, method, *inputs, **kwargs)
return _ndarray.NumericNDArray.__array_ufunc__(
None, ufunc, method, *inputs, **kwargs
)
39 changes: 39 additions & 0 deletions pyomo/core/expr/ndarray.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
# Copyright (c) 2008-2022
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
# rights in this software.
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________

from pyomo.common.dependencies import numpy as np, numpy_available


#
# Note: the "if numpy_available" in the class definition also ensures
# that the numpy types are registered if numpy is in fact available
#
class NumericNDArray(np.ndarray if numpy_available else object):
"""An ndarray subclass that stores Pyomo numeric expressions"""

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
if method == '__call__':
# Convert all incoming types to ndarray (to prevent recursion)
args = [np.asarray(i) for i in inputs]
# Set the return type to be an 'object'. This prevents the
# logical operators from casting the result to a bool. This
# requires numpy >= 1.6
kwargs['dtype'] = object

# Delegate to the base ufunc, but return an instance of this
# class so that additional operators hit this method.
ans = getattr(ufunc, method)(*args, **kwargs)
if isinstance(ans, np.ndarray):
if ans.size == 1:
return ans[0]
return ans.view(NumericNDArray)
else:
return ans
38 changes: 7 additions & 31 deletions pyomo/core/expr/numeric_expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from math import isclose

from pyomo.common.dependencies import numpy as np, numpy_available
from pyomo.common.dependencies import attempt_import
from pyomo.common.deprecation import (
deprecated,
deprecation_warning,
Expand Down Expand Up @@ -47,6 +47,9 @@
# Note: pyggyback on expr.base's use of attempt_import(visitor)
from pyomo.core.expr.base import ExpressionBase, NPV_Mixin, visitor


_ndarray, _ = attempt_import('pyomo.core.expr.ndarray')

relocated_module_attribute(
'is_potentially_variable',
'pyomo.core.expr.numvalue.is_potentially_variable',
Expand Down Expand Up @@ -634,7 +637,9 @@ def __abs__(self):
return _abs_dispatcher[self.__class__](self)

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
return NumericNDArray.__array_ufunc__(None, ufunc, method, *inputs, **kwargs)
return _ndarray.NumericNDArray.__array_ufunc__(
None, ufunc, method, *inputs, **kwargs
)

def to_string(self, verbose=None, labeler=None, smap=None, compute_values=False):
"""Return a string representation of the expression tree.
Expand Down Expand Up @@ -671,35 +676,6 @@ def to_string(self, verbose=None, labeler=None, smap=None, compute_values=False)
return str(self)


#
# Note: the "if numpy_available" in the class definition also ensures
# that the numpy types are registered if numpy is in fact available
#
# TODO: Move this to a separate module to support avoiding the numpy
# import if numpy is not actually used.
class NumericNDArray(np.ndarray if numpy_available else object):
"""An ndarray subclass that stores Pyomo numeric expressions"""

def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
if method == '__call__':
# Convert all incoming types to ndarray (to prevent recursion)
args = [np.asarray(i) for i in inputs]
# Set the return type to be an 'object'. This prevents the
# logical operators from casting the result to a bool. This
# requires numpy >= 1.6
kwargs['dtype'] = object

# Delegate to the base ufunc, but return an instance of this
# class so that additional operators hit this method.
ans = getattr(ufunc, method)(*args, **kwargs)
if isinstance(ans, np.ndarray):
if ans.size == 1:
return ans[0]
return ans.view(NumericNDArray)
else:
return ans


# -------------------------------------------------------
#
# Expression classes
Expand Down
6 changes: 3 additions & 3 deletions pyomo/core/tests/examples/test_kernel_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
def setUpModule():
global testing_solvers
import pyomo.environ
from pyomo.solvers.tests.solvers import test_solver_cases
from pyomo.solvers.tests.solvers import test_solver_cases as _test_solver_cases

for _solver, _io in test_solver_cases():
if (_solver, _io) in testing_solvers and test_solver_cases(
for _solver, _io in _test_solver_cases():
if (_solver, _io) in testing_solvers and _test_solver_cases(
_solver, _io
).available:
testing_solvers[_solver, _io] = True
Expand Down
2 changes: 1 addition & 1 deletion pyomo/core/tests/unit/test_numpy_expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
Reals,
)
from pyomo.core.expr import MonomialTermExpression
from pyomo.core.expr.numeric_expr import NumericNDArray
from pyomo.core.expr.ndarray import NumericNDArray
from pyomo.core.expr.numvalue import as_numeric
from pyomo.core.expr.compare import compare_expressions
from pyomo.core.expr.relational_expr import InequalityExpression
Expand Down
Loading

0 comments on commit b4e9f47

Please sign in to comment.