diff --git a/.codecov.yml b/.codecov.yml
index 6b88f948fe1..3395aa4b358 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1,19 +1,25 @@
+codecov:
+ notify:
+ # GHA: 5, Jenkins: 11
+ # Accurate as of April 1, 2025
+ # Potential to change when Python versions change. We will allow
+ # codecov to start reporting when 80% of the reports are in. This
+ # will hopefully help avoid an issue where codecov is not tracking
+ # PR branches (see https://github.com/codecov/feedback/issues/692).
+ after_n_builds: 13
+ wait_for_ci: false
+ require_ci_to_pass: false
+comment:
+ after_n_builds: 13
coverage:
- range: "50...100"
+ range: 70..98
status:
+ patch:
+ default:
+ # Force patches to be covered at the level of the codebase
+ threshold: 0.0
project:
default:
# Allow overall coverage to drop to avoid failures due to code
# cleanup or CI unavailability/lag
- threshold: 5%
- patch:
- default:
- # Force patches to be covered at the level of the codebase
- threshold: 0%
-# ci:
-# - !ci.appveyor.com
-codecov:
- notify:
- # GHA: 4, Jenkins: 8
- after_n_builds: 12 # all
- wait_for_ci: yes
+ threshold: 5.0
diff --git a/.coin-or/projDesc.xml b/.coin-or/projDesc.xml
index 1ee247e100f..667b374abed 100644
--- a/.coin-or/projDesc.xml
+++ b/.coin-or/projDesc.xml
@@ -227,8 +227,8 @@ Carl D. Laird, Chair, Pyomo Management Committee, claird at andrew dot cmu dot e
Use explicit overrides to disable use of automated
version reporting.
-->
- 6.7.0
- 6.7.0
+ 6.9.2
+ 6.9.2
@@ -287,7 +287,7 @@ Carl D. Laird, Chair, Pyomo Management Committee, claird at andrew dot cmu dot e
Any
- Python 3.8, 3.9, 3.10, 3.11, 3.12
+ Python 3.9, 3.10, 3.11, 3.12, 3.13
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 36b9898397f..ff10e62397b 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -45,4 +45,5 @@ ed13c8c65d6c3f56973887744be1c62a5d4756de
363a16a609f519b3edfdfcf40c66d6de7ac135af
d024718991455519e09149ede53a38df1c067abe
017e21ee50d98d8b2f2083e6880f030025ed5378
+91972008d109322fc1a3b688333d67def2288625
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index a6b1df3cf9a..61a09df7258 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -4,6 +4,8 @@ about: Report a bug in Pyomo (command not working as expected, etc.)
labels: "bug"
---
+
+
## Summary
+
## Summary
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4bd8e88bfed..5ab3eb16ed9 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -7,6 +7,8 @@
+
+
## Fixes # .
## Summary/Motivation:
diff --git a/.github/workflows/release_wheel_creation.yml b/.github/workflows/release_wheel_creation.yml
index 932b0d8eea6..419921c795d 100644
--- a/.github/workflows/release_wheel_creation.yml
+++ b/.github/workflows/release_wheel_creation.yml
@@ -4,6 +4,8 @@ on:
push:
tags:
- '*'
+ schedule:
+ - cron: '0 0 3 * *'
workflow_dispatch:
inputs:
git-ref:
@@ -14,8 +16,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
-env:
- PYOMO_SETUP_ARGS: "--with-cython --with-distributable-extensions"
+defaults:
+ run:
+ shell: bash -l {0}
jobs:
native_wheels:
@@ -24,36 +27,59 @@ jobs:
strategy:
fail-fast: true
matrix:
- os: [ubuntu-22.04, windows-latest, macos-latest]
+ os: [ubuntu-latest, windows-latest, macos-latest]
arch: [all]
- wheel-version: ['cp38*', 'cp39*', 'cp310*', 'cp311*', 'cp312*']
+ wheel-version: ['cp39*', 'cp310*', 'cp311*', 'cp312*', 'cp313*']
include:
- - wheel-version: 'cp38*'
- TARGET: 'py38'
- wheel-version: 'cp39*'
TARGET: 'py39'
+ GLOBAL_OPTIONS: "--with-cython --with-distributable-extensions"
- wheel-version: 'cp310*'
TARGET: 'py310'
+ GLOBAL_OPTIONS: "--with-cython --with-distributable-extensions"
- wheel-version: 'cp311*'
TARGET: 'py311'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
- wheel-version: 'cp312*'
TARGET: 'py312'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
+ - wheel-version: 'cp313*'
+ TARGET: 'py313'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
+
+ # We use pure python for any Windows/python greater than 3.10
+ exclude:
+ - wheel-version: 'cp311*'
+ os: windows-latest
+ - wheel-version: 'cp312*'
+ os: windows-latest
+ - wheel-version: 'cp313*'
+ os: windows-latest
+
steps:
- uses: actions/checkout@v4
+ - name: Create pyproject.toml
+ run: |
+ # Per the cibuildwheel documentation, you can technically use
+ # CIBW_BEFORE_BUILD to do these steps; however, as of the newest
+ # version (2.21.3) this feature does not work. This is a hack
+ # to make cibuildwheel recognize our pre-build requirements
+ echo -e '[build-system]\n\nrequires = [ "setuptools", "wheel", "cython", "pybind11" ]' > $GITHUB_WORKSPACE/pyproject.toml
+ cat $GITHUB_WORKSPACE/pyproject.toml
+ ls -la $GITHUB_WORKSPACE
- name: Build wheels
- uses: pypa/cibuildwheel@v2.16.5
+ uses: pypa/cibuildwheel@v2.21.3
with:
output-dir: dist
env:
CIBW_ARCHS_LINUX: "native"
- CIBW_ARCHS_MACOS: "native arm64"
- CIBW_ARCHS_WINDOWS: "native ARM64"
- CIBW_SKIP: "*-musllinux*"
+ CIBW_ARCHS_MACOS: "x86_64 arm64"
+ CIBW_ARCHS_WINDOWS: "AMD64 ARM64"
CIBW_BUILD: ${{ matrix.wheel-version }}
+ CIBW_SKIP: "*-musllinux*"
CIBW_BUILD_VERBOSITY: 1
- CIBW_BEFORE_BUILD: pip install cython pybind11
- CIBW_CONFIG_SETTINGS: '--global-option="--with-cython --with-distributable-extensions"'
+ CIBW_ENVIRONMENT: PYOMO_SETUP_ARGS="${{ matrix.GLOBAL_OPTIONS }}"
- uses: actions/upload-artifact@v4
with:
name: native_wheels-${{ matrix.os }}-${{ matrix.TARGET }}
@@ -65,21 +91,26 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [ubuntu-22.04]
+ os: [ubuntu-latest]
arch: [all]
- wheel-version: ['cp38*', 'cp39*', 'cp310*', 'cp311*', 'cp312*']
+ wheel-version: ['cp39*', 'cp310*', 'cp311*', 'cp312*', 'cp313*']
include:
- - wheel-version: 'cp38*'
- TARGET: 'py38'
- wheel-version: 'cp39*'
TARGET: 'py39'
+ GLOBAL_OPTIONS: "--with-cython --with-distributable-extensions"
- wheel-version: 'cp310*'
TARGET: 'py310'
+ GLOBAL_OPTIONS: "--with-cython --with-distributable-extensions"
- wheel-version: 'cp311*'
TARGET: 'py311'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
- wheel-version: 'cp312*'
TARGET: 'py312'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
+ - wheel-version: 'cp313*'
+ TARGET: 'py313'
+ GLOBAL_OPTIONS: "--without-cython --with-distributable-extensions"
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
@@ -87,23 +118,57 @@ jobs:
uses: docker/setup-qemu-action@v3
with:
platforms: all
+ - name: Create pyproject.toml
+ run: |
+ # Per the cibuildwheel documentation, you can technically use
+ # CIBW_BEFORE_BUILD to do these steps; however, as of the newest
+ # version (2.21.3) this feature does not work. This is a hack
+ # to make cibuildwheel recognize our pre-build requirements
+ echo -e '[build-system]\n\nrequires = [ "setuptools", "wheel", "cython", "pybind11" ]' > $GITHUB_WORKSPACE/pyproject.toml
+ cat $GITHUB_WORKSPACE/pyproject.toml
+ ls -la $GITHUB_WORKSPACE
- name: Build wheels
- uses: pypa/cibuildwheel@v2.16.5
+ uses: pypa/cibuildwheel@v2.21.3
with:
output-dir: dist
env:
CIBW_ARCHS_LINUX: "aarch64"
- CIBW_SKIP: "*-musllinux*"
CIBW_BUILD: ${{ matrix.wheel-version }}
+ CIBW_SKIP: "*-musllinux*"
CIBW_BUILD_VERBOSITY: 1
- CIBW_BEFORE_BUILD: pip install cython pybind11
- CIBW_CONFIG_SETTINGS: '--global-option="--with-cython --with-distributable-extensions"'
+ CIBW_ENVIRONMENT: PYOMO_SETUP_ARGS="${{ matrix.GLOBAL_OPTIONS }}"
- uses: actions/upload-artifact@v4
with:
name: alt_wheels-${{ matrix.os }}-${{ matrix.TARGET }}
path: dist/*.whl
overwrite: true
+ pure_python:
+ name: pure_python_wheel
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ['3.11']
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install twine wheel setuptools pybind11
+ - name: Build pure python wheel
+ run: |
+ python setup.py --without-cython sdist --format=gztar bdist_wheel
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: purepythonwheel
+ path: dist/*.whl
+ overwrite: true
+
generictarball:
name: ${{ matrix.TARGET }}
runs-on: ${{ matrix.os }}
@@ -114,7 +179,7 @@ jobs:
include:
- os: ubuntu-latest
TARGET: generic_tarball
- python-version: [3.8]
+ python-version: [3.9]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
diff --git a/.github/workflows/test_branches.yml b/.github/workflows/test_branches.yml
index 77f47b505ff..47a36ef5917 100644
--- a/.github/workflows/test_branches.yml
+++ b/.github/workflows/test_branches.yml
@@ -21,15 +21,19 @@ defaults:
env:
PYTHONWARNINGS: ignore::UserWarning
PYTHON_CORE_PKGS: wheel
- PYPI_ONLY: z3-solver
- PYPY_EXCLUDE: scipy numdifftools seaborn statsmodels
+ PYPI_ONLY: z3-solver linear-tree
+ PYPY_EXCLUDE: scipy numdifftools seaborn statsmodels linear-tree
CACHE_VER: v221013.1
NEOS_EMAIL: tests@pyomo.org
SRC_REF: ${{ github.head_ref || github.ref }}
+ PYOMO_WORKFLOW: branch
jobs:
lint:
name: lint/style-and-typos
+ if: |
+ ${{ ! ( contains(github.event.pull_request.title, '[WIP]') ||
+ github.event.pull_request.draft ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout Pyomo source
@@ -40,12 +44,28 @@ jobs:
python-version: '3.10'
- name: Black Formatting Check
run: |
- pip install black
+ # Note v24.4.1 fails due to a bug in the parser
+ pip install 'black!=24.4.1'
black . -S -C --check --diff --exclude examples/pyomobook/python-ch/BadIndent.py
- name: Spell Check
uses: crate-ci/typos@master
with:
config: ./.github/workflows/typos.toml
+ - name: URL Checker
+ if: env.PYOMO_WORKFLOW == 'branch'
+ uses: urlstechie/urlchecker-action@0.0.34
+ with:
+ # A comma-separated list of file types to cover in the URL checks
+ file_types: .md,.rst,.py
+ # Choose whether to include file with no URLs in the prints.
+ print_all: false
+ # More verbose summary at the end of a run
+ verbose: true
+ # How many times to retry a failed request (defaults to 1)
+ retry_count: 3
+ # Exclude Jenkins because it's behind a firewall; ignore RTD because
+ # a magically-generated string is triggering a failure
+ exclude_urls: https://pyomo-jenkins.sandia.gov/,https://pyomo.readthedocs.io/en/%s/errors.html
build:
@@ -56,57 +76,56 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
- python: ['3.12']
+ python: [3.13]
other: [""]
category: [""]
include:
- os: ubuntu-latest
- python: '3.12'
+ python: 3.13
+ test_docs: 1
TARGET: linux
PYENV: pip
- os: macos-latest
- python: '3.10'
+ python: 3.12
+ test_docs: 1
TARGET: osx
PYENV: pip
- os: windows-latest
- python: 3.9
+ python: 3.11
+ test_docs: 1
TARGET: win
PYENV: conda
PACKAGES: glpk pytest-qt filelock
- os: ubuntu-latest
- python: '3.11'
+ python: 3.11
other: /conda
- skip_doctest: 1
TARGET: linux
PYENV: conda
PACKAGES: pytest-qt
- os: ubuntu-latest
- python: 3.9
+ python: '3.10'
other: /mpi
mpi: 3
- skip_doctest: 1
TARGET: linux
PYENV: conda
- PACKAGES: mpi4py
+ PACKAGES: openmpi mpi4py
- os: ubuntu-latest
- python: '3.10'
+ python: 3.12
other: /cython
setup_options: --with-cython
- skip_doctest: 1
TARGET: linux
PYENV: pip
PACKAGES: cython
- os: windows-latest
- python: 3.8
+ python: 3.9
other: /pip
- skip_doctest: 1
TARGET: win
PYENV: pip
@@ -180,7 +199,7 @@ jobs:
# Notes:
# - install glpk
# - pyodbc needs: gcc pkg-config unixodbc freetds
- for pkg in bash pkg-config unixodbc freetds glpk; do
+ for pkg in bash pkg-config unixodbc freetds glpk ginac; do
brew list $pkg || brew install $pkg
done
@@ -192,13 +211,15 @@ jobs:
# - install glpk
# - ipopt needs: libopenblas-dev gfortran liblapack-dev
sudo apt-get -o Dir::Cache=${GITHUB_WORKSPACE}/cache/os \
- install libopenblas-dev gfortran liblapack-dev glpk-utils
+ install libopenblas-dev gfortran liblapack-dev glpk-utils \
+ libginac-dev
sudo chmod -R 777 ${GITHUB_WORKSPACE}/cache/os
- name: Update Windows
if: matrix.TARGET == 'win'
run: |
echo "SETUPTOOLS_USE_DISTUTILS=local" >> $GITHUB_ENV
+ choco install pkgconfiglite
- name: Set up Python ${{ matrix.python }}
if: matrix.PYENV == 'pip'
@@ -217,7 +238,7 @@ jobs:
# have support for OSX.
- name: Set up UI testing infrastructure
if: ${{ matrix.TARGET != 'osx' }}
- uses: pyvista/setup-headless-display-action@v2
+ uses: pyvista/setup-headless-display-action@v3
with:
qt: true
pyvista: false
@@ -263,11 +284,12 @@ jobs:
if test -z "${{matrix.slim}}"; then
python -m pip install --cache-dir cache/pip cplex docplex \
|| echo "WARNING: CPLEX Community Edition is not available"
- python -m pip install --cache-dir cache/pip \
- -i https://pypi.gurobi.com gurobipy==10.0.3 \
+ python -m pip install --cache-dir cache/pip gurobipy \
|| echo "WARNING: Gurobi is not available"
python -m pip install --cache-dir cache/pip xpress \
|| echo "WARNING: Xpress Community Edition is not available"
+ python -m pip install --cache-dir cache/pip maingopy \
+ || echo "WARNING: MAiNGO is not available"
if [[ ${{matrix.python}} == pypy* ]]; then
echo "skipping wntr for pypy"
else
@@ -287,15 +309,21 @@ jobs:
# Set up environment
conda config --set always_yes yes
conda config --set auto_update_conda false
+ conda config --set channel_priority strict
conda config --remove channels defaults
conda config --append channels nodefaults
conda config --append channels conda-forge
# Try to install mamba
- conda install --update-deps -q -y -n base conda-libmamba-solver \
- || MAMBA_FAILED=1
- if test -z "$MAMBA_FAILED"; then
- echo "*** Activating the mamba environment solver ***"
- conda config --set solver libmamba
+ CONDA_VER=$(conda --version | cut -d\ -f2)
+ if test 23.10 = "`echo -e "23.10\n$CONDA_VER" | sort -V | tail -1`"; then
+ # Note: removed '--update-deps' on 2025-02-28 to work around
+ # broken libffi(?)
+ conda install -q -y -n base conda-libmamba-solver \
+ || MAMBA_FAILED=1
+ if test -z "$MAMBA_FAILED"; then
+ echo "*** Activating the mamba environment solver ***"
+ conda config --set solver libmamba
+ fi
fi
# Add the rest of the channels
conda config --append channels gurobi
@@ -320,6 +348,10 @@ jobs:
if test "${{matrix.TARGET}}" == linux; then
EXCLUDE="casadi numdifftools $EXCLUDE"
fi
+ if [[ "${{matrix.TARGET}}" == win && "${{matrix.python}}" == "3.13" ]]; then
+ # As of Nov 7, 2024, qtconsole is not compatible with python 3.13 on win
+ EXCLUDE="qtconsole $EXCLUDE"
+ fi
EXCLUDE=`echo "$EXCLUDE" | xargs`
if test -n "$EXCLUDE"; then
for WORD in $EXCLUDE; do
@@ -333,16 +365,35 @@ jobs:
CONDA_DEPENDENCIES="$CONDA_DEPENDENCIES $PKG"
fi
done
+ echo ""
echo "*** Install Pyomo dependencies ***"
+ # For windows, cannot use newer setuptools because of APPSI compilation issues
+ if test "${{matrix.TARGET}}" == 'win'; then
+ CONDA_DEPENDENCIES="$CONDA_DEPENDENCIES setuptools<74.0.0"
+ fi
# Note: this will fail the build if any installation fails (or
# possibly if it outputs messages to stderr)
conda install --update-deps -q -y $CONDA_DEPENDENCIES
if test -z "${{matrix.slim}}"; then
+ # xpress.init() (xpress 9.5.1 from conda) hangs indefinitely
+ # on GHA/Windows under Python 3.10 and 3.11. Exclude that
+ # release on that platform.
+ if [[ ${{matrix.TARGET}} == win && ${{matrix.python}} =~ 3.1[01] ]]; then
+ # We would like to just use something like:
+ # - "!=9.5.1" (conda errors)
+ # - "<9.5.1|>9.5.1" (conda installs 9.1.2, which also hangs)
+ # - "<=9.5.0|>9.5.1" (conda seg faults)
+ XPRESS='xpress>=9.5.2'
+ else
+ XPRESS='xpress'
+ fi
+ TIMEOUT_MSG="TIMEOUT: killing conda install process"
PYVER=$(echo "py${{matrix.python}}" | sed 's/\.//g')
echo "Installing for $PYVER"
- for PKG in 'cplex>=12.10' docplex 'gurobi=10.0.3' xpress cyipopt pymumps scip; do
+ for PKG in 'cplex>=12.10' docplex gurobi "$XPRESS" cyipopt pymumps scip; do
echo ""
echo "*** Install $PKG ***"
+ echo ""
# conda can literally take an hour to determine that a
# package is not available. Perform a quick search to see
# if the package is available for this interpreter before
@@ -361,15 +412,37 @@ jobs:
if test -z "$_ISPY" -o -n "$_PYOK"; then
echo ""
echo "... INSTALLING $PKG"
- conda install -y "$PKG" || _BUILDS=""
+ # Because conda can occasionally hang
+ # indefinitely (lately while installing SCIP),
+ # we will run "conda install" in a subshell and
+ # kill it after 5-minutes.
+ (conda install -q -y $PKG |& tee conda.log) &
+ conda_subshell_pid=$!
+ sleep 1
+ conda_pid=$(ps | grep conda | sed 's/^ *//' | sed 's/ .*//')
+ # Only timeout the conda process if it's not to
+ # the installation phase yet. Signalling conda
+ # after it has started the installation process
+ # can irrecoverably corrupt the environment.
+ (sleep 300 \
+ && if test `grep 'Package Plan' conda.log | wc -l` -eq 0; \
+ then echo "$TIMEOUT_MSG $conda_pid (TERM)" \
+ && kill -TERM $conda_pid 2>/dev/null ; fi) &
+ timeout_pid=$!
+ wait $conda_subshell_pid || _BUILDS=""
+ kill $timeout_pid 2>/dev/null \
+ || echo "TIMEOUT: time limit expired"
fi
fi
+ echo ""
if test -z "$_BUILDS"; then
echo "WARNING: $PKG is not available"
fi
done
fi
# Re-try Pyomo (optional) dependencies with pip
+ echo ""
+ echo "Installing packages only available on PyPI"
if test -n "$PYPI_DEPENDENCIES"; then
python -m pip install --cache-dir cache/pip $PYPI_DEPENDENCIES
fi
@@ -401,6 +474,9 @@ jobs:
mkdir -p "$DOWNLOAD_DIR"
echo "TPL_DIR=$TPL_DIR" >> $GITHUB_ENV
echo "DOWNLOAD_DIR=$DOWNLOAD_DIR" >> $GITHUB_ENV
+ # Create a new PYOMO_PATH variable so we can ensure that we are actually
+ # getting the right PATH at the end
+ echo "PYOMO_PATH=$PATH" >> $GITHUB_ENV
- name: Install Ipopt
if: ${{ ! matrix.slim }}
@@ -408,14 +484,13 @@ jobs:
IPOPT_DIR=$TPL_DIR/ipopt
echo "$IPOPT_DIR" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV
+ echo "DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV
+ NEW_PYOMO_PATH="$IPOPT_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
mkdir -p $IPOPT_DIR
IPOPT_TAR=${DOWNLOAD_DIR}/ipopt.tar.gz
if test ! -e $IPOPT_TAR; then
echo "...downloading Ipopt"
- if test "${{matrix.TARGET}}" == osx; then
- echo "IDAES Ipopt not available on OSX"
- exit 0
- fi
URL=https://github.com/IDAES/idaes-ext
RELEASE=$(curl --max-time 150 --retry 8 \
-L -s -H 'Accept: application/json' ${URL}/releases/latest)
@@ -423,8 +498,12 @@ jobs:
URL=${URL}/releases/download/$VER
if test "${{matrix.TARGET}}" == linux; then
curl --max-time 150 --retry 8 \
- -L $URL/idaes-solvers-ubuntu2004-x86_64.tar.gz \
- > $IPOPT_TAR
+ -L $URL/idaes-solvers-ubuntu2204-x86_64.tar.gz \
+ -o $IPOPT_TAR
+ elif test "${{matrix.TARGET}}" == osx; then
+ curl --max-time 150 --retry 8 \
+ -L $URL/idaes-solvers-darwin-aarch64.tar.gz \
+ -o $IPOPT_TAR
else
curl --max-time 150 --retry 8 \
-L $URL/idaes-solvers-windows-x86_64.tar.gz \
@@ -432,7 +511,11 @@ jobs:
fi
fi
cd $IPOPT_DIR
- tar -xzi < $IPOPT_TAR
+ if test "${{matrix.TARGET}}" == win; then
+ tar -xzi < $IPOPT_TAR
+ else
+ tar -xzf $IPOPT_TAR
+ fi
echo ""
echo "$IPOPT_DIR"
ls -l $IPOPT_DIR
@@ -484,7 +567,9 @@ jobs:
- name: Install GAMS Python bindings
if: ${{ ! matrix.slim }}
run: |
- GAMS_DIR="${env:TPL_DIR}/gams"
+ GAMS_DIR="$TPL_DIR/gams"
+ NEW_PYOMO_PATH="$GAMS_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
py_ver=$($PYTHON_EXE -c 'import sys;v="_%s%s" % sys.version_info[:2] \
;print(v if v != "_27" else "")')
if test -e $GAMS_DIR/apifiles/Python/api$py_ver; then
@@ -501,7 +586,18 @@ jobs:
$BARON_DIR = "${env:TPL_DIR}/baron"
echo "$BARON_DIR" | `
Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- $URL = "https://www.minlp.com/downloads/xecs/baron/current/"
+ $CURRENT_PYOMO_PATH="${env:PYOMO_PATH}"
+ # Prepend BARON_DIR with appropriate path separator
+ if ( "${{matrix.TARGET}}" -eq "win" ) {
+ $PATH_SEPARATOR = ";"
+ } else {
+ $PATH_SEPARATOR = ":"
+ }
+ $NEW_PYOMO_PATH = "$BARON_DIR$PATH_SEPARATOR$CURRENT_PYOMO_PATH"
+ echo "New PYOMO_PATH: $NEW_PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" | `
+ Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ $URL = "https://minlp-downloads.nyc3.cdn.digitaloceanspaces.com/xecs/baron/current/"
if ( "${{matrix.TARGET}}" -eq "win" ) {
$INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.exe"
$URL += "baron-win64.exe"
@@ -535,6 +631,8 @@ jobs:
run: |
GJH_DIR="$TPL_DIR/gjh"
echo "${GJH_DIR}" >> $GITHUB_PATH
+ NEW_PYOMO_PATH="$GJH_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
INSTALL_DIR="${DOWNLOAD_DIR}/gjh"
if test ! -e "$INSTALL_DIR/bin"; then
mkdir -p "$INSTALL_DIR"
@@ -597,7 +695,7 @@ jobs:
> ${SITE_PACKAGES}/run_coverage_at_startup.pth
- name: Download and install extensions
- if: ${{ ! matrix.slim }}
+ if: ${{ ! matrix.slim && matrix.category != 'notests' }}
run: |
echo ""
echo "Pyomo download-extensions"
@@ -610,34 +708,48 @@ jobs:
- name: Report pyomo plugin information
run: |
+ # MRM / Jan 9, 2025: We update the PATH manually to make sure we
+ # capture all of our changes. This is necessary because of an
+ # issue with how the PATH rearranges on Windows.
+ # Issue: https://github.com/actions/runner-images/issues/11328
+ export PATH=$PYOMO_PATH
echo "$PATH"
pyomo help --solvers || exit 1
pyomo help --transformations || exit 1
pyomo help --writers || exit 1
- name: Run Pyomo tests
- if: matrix.mpi == 0
+ if: ${{ matrix.mpi == 0 && matrix.category != 'notests' }}
run: |
+ export PATH=$PYOMO_PATH
$PYTHON_EXE -m pytest -v \
-W ignore::Warning ${{matrix.category}} \
pyomo `pwd`/pyomo-model-libraries \
`pwd`/examples `pwd`/doc --junitxml="TEST-pyomo.xml"
- name: Run Pyomo MPI tests
- if: matrix.mpi != 0
+ if: ${{ matrix.mpi != 0 && matrix.category != 'notests' }}
run: |
# Manually invoke the DAT parser so that parse_table_datacmds.py
# is fully generated by a single process before invoking MPI
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \
parse_data_commands; parse_data_commands(data='')"
# Note: if we are testing with openmpi, add '--oversubscribe'
- mpirun -np ${{matrix.mpi}} pytest -v \
+ mpirun -np ${{matrix.mpi}} -oversubscribe pytest -v \
--junit-xml=TEST-pyomo-mpi.xml \
-m "mpi" -W ignore::Warning \
pyomo `pwd`/pyomo-model-libraries
+ - name: Build documentation
+ if: matrix.build_docs != 0
+ run: |
+ sudo apt-get -y install graphviz latexmk texlive texlive-latex-extra \
+ texlive-pictures
+ make -C doc/OnlineDocs html
+ make -C doc/OnlineDocs latexpdf
+
- name: Run documentation tests
- if: matrix.skip_doctest == 0
+ if: matrix.test_docs != 0
run: |
make -C doc/OnlineDocs doctest -d
@@ -651,6 +763,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: ${{github.job}}_${{env.GHA_JOBGROUP}}-${{env.GHA_JOBNAME}}
+ include-hidden-files: true
path: |
.coverage
coverage.xml
@@ -660,17 +773,17 @@ jobs:
bare-python-env:
- name: linux/3.8/bare-env
+ name: linux/3.9/bare-env
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout Pyomo source
uses: actions/checkout@v4
- - name: Set up Python 3.8
+ - name: Set up Python 3.9
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.9
- name: Install Pyomo
run: |
@@ -702,18 +815,19 @@ jobs:
cover:
name: process-coverage-${{ matrix.TARGET }}
needs: build
- if: ${{ false }} # turn off for branches
+ # run even if a build job fails, but not if canceled (except for branches)
+ if: ${{ false }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
- os: [ubuntu-latest, macos-latest, windows-latest]
+ os: [ubuntu-latest, macos-13, windows-latest]
include:
- os: ubuntu-latest
TARGET: linux
- - os: macos-latest
+ - os: macos-13
TARGET: osx
- os: windows-latest
TARGET: win
@@ -728,17 +842,17 @@ jobs:
# id: pip-cache
# with:
# path: cache/pip
- # key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-3.8
+ # key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-3.9
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- - name: Set up Python 3.8
+ - name: Set up Python 3.9
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.9
- name: Install Python Packages (pip)
shell: bash # DO NOT REMOVE: see note above
@@ -773,26 +887,6 @@ jobs:
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \
parse_data_commands; parse_data_commands(data='')"
- - name: Update codecov uploader
- run: |
- set +e
- CODECOV="${GITHUB_WORKSPACE}/codecov.sh"
- echo "CODECOV=$CODECOV" >> $GITHUB_ENV
- for i in `seq 3`; do
- echo "Downloading current codecov script (attempt ${i})"
- curl -L https://codecov.io/bash -o $CODECOV
- if test $? == 0; then
- break
- fi
- DELAY=$(( RANDOM % 30 + 30))
- echo "Pausing $DELAY seconds before re-attempting download"
- sleep $DELAY
- done
- if test ! -e $CODECOV; then
- echo "Failed to download codecov.sh"
- exit 1
- fi
-
- name: Combine coverage reports
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main'
run: |
@@ -831,7 +925,7 @@ jobs:
- name: Upload codecov reports
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main'
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
files: coverage.xml
token: ${{ secrets.PYOMO_CODECOV_TOKEN }}
@@ -843,10 +937,10 @@ jobs:
if: |
hashFiles('coverage-other.xml') != '' &&
(github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main')
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
files: coverage-other.xml
token: ${{ secrets.PYOMO_CODECOV_TOKEN }}
name: ${{ matrix.TARGET }}/other
- flags: ${{ matrix.TARGET }},other
+ flags: ${{ matrix.TARGET }}_other
fail_ci_if_error: true
diff --git a/.github/workflows/test_pr_and_main.yml b/.github/workflows/test_pr_and_main.yml
index 87d6aa4d7a8..2af9b4469a8 100644
--- a/.github/workflows/test_pr_and_main.yml
+++ b/.github/workflows/test_pr_and_main.yml
@@ -7,6 +7,11 @@ on:
pull_request:
branches:
- main
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - ready_for_review
workflow_dispatch:
inputs:
git-ref:
@@ -24,15 +29,22 @@ defaults:
env:
PYTHONWARNINGS: ignore::UserWarning
PYTHON_CORE_PKGS: wheel
- PYPI_ONLY: z3-solver
- PYPY_EXCLUDE: scipy numdifftools seaborn statsmodels
+ PYPI_ONLY: z3-solver linear-tree
+ PYPY_EXCLUDE: scipy numdifftools seaborn statsmodels linear-tree
CACHE_VER: v221013.1
NEOS_EMAIL: tests@pyomo.org
SRC_REF: ${{ github.head_ref || github.ref }}
+ PYOMO_WORKFLOW: |
+ ${{ ( contains(github.event.pull_request.title, '[WIP]') ||
+ github.event.pull_request.draft ) && 'draft_pr'
+ || github.event.pull_request.number && 'pr' || 'main' }}
jobs:
lint:
name: lint/style-and-typos
+ if: |
+ ${{ ! ( contains(github.event.pull_request.title, '[WIP]') ||
+ github.event.pull_request.draft ) }}
runs-on: ubuntu-latest
steps:
- name: Checkout Pyomo source
@@ -43,12 +55,28 @@ jobs:
python-version: '3.10'
- name: Black Formatting Check
run: |
- pip install black
+ # Note v24.4.1 fails due to a bug in the parser
+ pip install 'black!=24.4.1'
black . -S -C --check --diff --exclude examples/pyomobook/python-ch/BadIndent.py
- name: Spell Check
uses: crate-ci/typos@master
with:
config: ./.github/workflows/typos.toml
+ - name: URL Checker
+ if: env.PYOMO_WORKFLOW == 'branch'
+ uses: urlstechie/urlchecker-action@0.0.34
+ with:
+ # A comma-separated list of file types to cover in the URL checks
+ file_types: .md,.rst,.py
+ # Choose whether to include file with no URLs in the prints.
+ print_all: false
+ # More verbose summary at the end of a run
+ verbose: true
+ # How many times to retry a failed request (defaults to 1)
+ retry_count: 3
+ # Exclude Jenkins because it's behind a firewall; ignore RTD because
+ # a magically-generated string is triggering a failure
+ exclude_urls: https://pyomo-jenkins.sandia.gov/,https://pyomo.readthedocs.io/en/%s/errors.html
build:
@@ -60,86 +88,99 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- python: [ 3.8, 3.9, '3.10', '3.11', '3.12' ]
+ python: [ 3.9, '3.10', 3.11, 3.12, 3.13 ]
other: [""]
category: [""]
include:
- os: ubuntu-latest
+ test_docs: 1
TARGET: linux
PYENV: pip
- os: macos-latest
+ test_docs: 1
TARGET: osx
PYENV: pip
- os: windows-latest
+ test_docs: 1
TARGET: win
PYENV: conda
PACKAGES: glpk pytest-qt filelock
- os: ubuntu-latest
- python: '3.11'
+ python: 3.11
other: /conda
- skip_doctest: 1
TARGET: linux
PYENV: conda
PACKAGES: pytest-qt
- os: ubuntu-latest
- python: 3.9
+ python: '3.10'
other: /mpi
mpi: 3
- skip_doctest: 1
TARGET: linux
PYENV: conda
- PACKAGES: mpi4py
+ PACKAGES: openmpi mpi4py
- os: ubuntu-latest
- python: '3.11'
- other: /singletest
- category: "-m 'neos or importtest'"
- skip_doctest: 1
- TARGET: linux
- PYENV: pip
-
- - os: ubuntu-latest
- python: '3.10'
+ python: 3.12
other: /cython
setup_options: --with-cython
- skip_doctest: 1
TARGET: linux
PYENV: pip
PACKAGES: cython
- os: windows-latest
- python: 3.8
+ python: 3.9
other: /pip
- skip_doctest: 1
TARGET: win
PYENV: pip
- os: ubuntu-latest
- python: 3.8
+ python: 3.11
+ other: /singletest
+ category: "-m 'neos or importtest'"
+ TARGET: linux
+ PYENV: pip
+
+ - os: ubuntu-latest
+ python: 3.9
other: /slim
slim: 1
- skip_doctest: 1
TARGET: linux
PYENV: pip
- os: ubuntu-latest
- python: 3.9
+ python: 3.12
+ other: /numpy2
+ slim: 1
+ TARGET: linux
+ PYENV: pip
+ PACKAGES: "gurobipy dill numpy>2.0 scipy networkx"
+
+ - os: ubuntu-latest
+ python: '3.10'
other: /pyutilib
TARGET: linux
PYENV: pip
PACKAGES: pyutilib
- os: ubuntu-latest
- python: pypy-3.9
- skip_doctest: 1
+ python: 'pypy-3.10'
TARGET: linux
PYENV: pip
+ - os: ubuntu-latest
+ python: 3.11
+ other: /rtd
+ category: notests
+ build_docs: 1
+ TARGET: linux
+ PYENV: pip
+
+
steps:
- name: Checkout Pyomo source
uses: actions/checkout@v4
@@ -210,7 +251,7 @@ jobs:
# Notes:
# - install glpk
# - pyodbc needs: gcc pkg-config unixodbc freetds
- for pkg in bash pkg-config unixodbc freetds glpk; do
+ for pkg in bash pkg-config unixodbc freetds glpk ginac; do
brew list $pkg || brew install $pkg
done
@@ -222,13 +263,15 @@ jobs:
# - install glpk
# - ipopt needs: libopenblas-dev gfortran liblapack-dev
sudo apt-get -o Dir::Cache=${GITHUB_WORKSPACE}/cache/os \
- install libopenblas-dev gfortran liblapack-dev glpk-utils
+ install libopenblas-dev gfortran liblapack-dev glpk-utils \
+ libginac-dev
sudo chmod -R 777 ${GITHUB_WORKSPACE}/cache/os
- name: Update Windows
if: matrix.TARGET == 'win'
run: |
echo "SETUPTOOLS_USE_DISTUTILS=local" >> $GITHUB_ENV
+ choco install pkgconfiglite
- name: Set up Python ${{ matrix.python }}
if: matrix.PYENV == 'pip'
@@ -247,7 +290,7 @@ jobs:
# have support for OSX.
- name: Set up UI testing infrastructure
if: ${{ matrix.TARGET != 'osx' }}
- uses: pyvista/setup-headless-display-action@v2
+ uses: pyvista/setup-headless-display-action@v3
with:
qt: true
pyvista: false
@@ -293,11 +336,12 @@ jobs:
if test -z "${{matrix.slim}}"; then
python -m pip install --cache-dir cache/pip cplex docplex \
|| echo "WARNING: CPLEX Community Edition is not available"
- python -m pip install --cache-dir cache/pip \
- -i https://pypi.gurobi.com gurobipy==10.0.3 \
+ python -m pip install --cache-dir cache/pip gurobipy \
|| echo "WARNING: Gurobi is not available"
python -m pip install --cache-dir cache/pip xpress \
|| echo "WARNING: Xpress Community Edition is not available"
+ python -m pip install --cache-dir cache/pip maingopy \
+ || echo "WARNING: MAiNGO is not available"
if [[ ${{matrix.python}} == pypy* ]]; then
echo "skipping wntr for pypy"
else
@@ -317,15 +361,21 @@ jobs:
# Set up environment
conda config --set always_yes yes
conda config --set auto_update_conda false
+ conda config --set channel_priority strict
conda config --remove channels defaults
conda config --append channels nodefaults
conda config --append channels conda-forge
# Try to install mamba
- conda install --update-deps -q -y -n base conda-libmamba-solver \
- || MAMBA_FAILED=1
- if test -z "$MAMBA_FAILED"; then
- echo "*** Activating the mamba environment solver ***"
- conda config --set solver libmamba
+ CONDA_VER=$(conda --version | cut -d\ -f2)
+ if test 23.10 = "`echo -e "23.10\n$CONDA_VER" | sort -V | tail -1`"; then
+ # Note: removed '--update-deps' on 2025-02-28 to work around
+ # broken libffi(?)
+ conda install -q -y -n base conda-libmamba-solver \
+ || MAMBA_FAILED=1
+ if test -z "$MAMBA_FAILED"; then
+ echo "*** Activating the mamba environment solver ***"
+ conda config --set solver libmamba
+ fi
fi
# Add the rest of the channels
conda config --append channels gurobi
@@ -350,6 +400,10 @@ jobs:
if test "${{matrix.TARGET}}" == linux; then
EXCLUDE="casadi numdifftools $EXCLUDE"
fi
+ if [[ "${{matrix.TARGET}}" == win && "${{matrix.python}}" == "3.13" ]]; then
+ # As of Nov 7, 2024, qtconsole is not compatible with python 3.13 on win
+ EXCLUDE="qtconsole $EXCLUDE"
+ fi
EXCLUDE=`echo "$EXCLUDE" | xargs`
if test -n "$EXCLUDE"; then
for WORD in $EXCLUDE; do
@@ -363,16 +417,35 @@ jobs:
CONDA_DEPENDENCIES="$CONDA_DEPENDENCIES $PKG"
fi
done
+ echo ""
echo "*** Install Pyomo dependencies ***"
+ # For windows, cannot use newer setuptools because of APPSI compilation issues
+ if test "${{matrix.TARGET}}" == 'win'; then
+ CONDA_DEPENDENCIES="$CONDA_DEPENDENCIES setuptools<74.0.0"
+ fi
# Note: this will fail the build if any installation fails (or
# possibly if it outputs messages to stderr)
conda install --update-deps -q -y $CONDA_DEPENDENCIES
if test -z "${{matrix.slim}}"; then
+ # xpress.init() (xpress 9.5.1 from conda) hangs indefinitely
+ # on GHA/Windows under Python 3.10 and 3.11. Exclude that
+ # release on that platform.
+ if [[ ${{matrix.TARGET}} == win && ${{matrix.python}} =~ 3.1[01] ]]; then
+ # We would like to just use something like:
+ # - "!=9.5.1" (conda errors)
+ # - "<9.5.1|>9.5.1" (conda installs 9.1.2, which also hangs)
+ # - "<=9.5.0|>9.5.1" (conda seg faults)
+ XPRESS='xpress>=9.5.2'
+ else
+ XPRESS='xpress'
+ fi
+ TIMEOUT_MSG="TIMEOUT: killing conda install process"
PYVER=$(echo "py${{matrix.python}}" | sed 's/\.//g')
echo "Installing for $PYVER"
- for PKG in 'cplex>=12.10' docplex 'gurobi=10.0.3' xpress cyipopt pymumps scip; do
+ for PKG in 'cplex>=12.10' docplex gurobi "$XPRESS" cyipopt pymumps scip; do
echo ""
echo "*** Install $PKG ***"
+ echo ""
# conda can literally take an hour to determine that a
# package is not available. Perform a quick search to see
# if the package is available for this interpreter before
@@ -391,15 +464,37 @@ jobs:
if test -z "$_ISPY" -o -n "$_PYOK"; then
echo ""
echo "... INSTALLING $PKG"
- conda install -y "$PKG" || _BUILDS=""
+ # Because conda can occasionally hang
+ # indefinitely (lately while installing SCIP),
+ # we will run "conda install" in a subshell and
+ # kill it after 5-minutes.
+ (conda install -q -y $PKG |& tee conda.log) &
+ conda_subshell_pid=$!
+ sleep 1
+ conda_pid=$(ps | grep conda | sed 's/^ *//' | sed 's/ .*//')
+ # Only timeout the conda process if it's not to
+ # the installation phase yet. Signalling conda
+ # after it has started the installation process
+ # can irrecoverably corrupt the environment.
+ (sleep 300 \
+ && if test `grep 'Package Plan' conda.log | wc -l` -eq 0; \
+ then echo "$TIMEOUT_MSG $conda_pid (TERM)" \
+ && kill -TERM $conda_pid 2>/dev/null ; fi) &
+ timeout_pid=$!
+ wait $conda_subshell_pid || _BUILDS=""
+ kill $timeout_pid 2>/dev/null \
+ || echo "TIMEOUT: time limit expired"
fi
fi
+ echo ""
if test -z "$_BUILDS"; then
echo "WARNING: $PKG is not available"
fi
done
fi
# Re-try Pyomo (optional) dependencies with pip
+ echo ""
+ echo "Installing packages only available on PyPI"
if test -n "$PYPI_DEPENDENCIES"; then
python -m pip install --cache-dir cache/pip $PYPI_DEPENDENCIES
fi
@@ -431,6 +526,9 @@ jobs:
mkdir -p "$DOWNLOAD_DIR"
echo "TPL_DIR=$TPL_DIR" >> $GITHUB_ENV
echo "DOWNLOAD_DIR=$DOWNLOAD_DIR" >> $GITHUB_ENV
+ # Create a new PYOMO_PATH variable so we can ensure that we are actually
+ # getting the right PATH at the end
+ echo "PYOMO_PATH=$PATH" >> $GITHUB_ENV
- name: Install Ipopt
if: ${{ ! matrix.slim }}
@@ -438,14 +536,13 @@ jobs:
IPOPT_DIR=$TPL_DIR/ipopt
echo "$IPOPT_DIR" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV
+ echo "DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$IPOPT_DIR" >> $GITHUB_ENV
+ NEW_PYOMO_PATH="$IPOPT_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
mkdir -p $IPOPT_DIR
IPOPT_TAR=${DOWNLOAD_DIR}/ipopt.tar.gz
if test ! -e $IPOPT_TAR; then
echo "...downloading Ipopt"
- if test "${{matrix.TARGET}}" == osx; then
- echo "IDAES Ipopt not available on OSX"
- exit 0
- fi
URL=https://github.com/IDAES/idaes-ext
RELEASE=$(curl --max-time 150 --retry 8 \
-L -s -H 'Accept: application/json' ${URL}/releases/latest)
@@ -453,8 +550,12 @@ jobs:
URL=${URL}/releases/download/$VER
if test "${{matrix.TARGET}}" == linux; then
curl --max-time 150 --retry 8 \
- -L $URL/idaes-solvers-ubuntu2004-x86_64.tar.gz \
- > $IPOPT_TAR
+ -L $URL/idaes-solvers-ubuntu2204-x86_64.tar.gz \
+ -o $IPOPT_TAR
+ elif test "${{matrix.TARGET}}" == osx; then
+ curl --max-time 150 --retry 8 \
+ -L $URL/idaes-solvers-darwin-aarch64.tar.gz \
+ -o $IPOPT_TAR
else
curl --max-time 150 --retry 8 \
-L $URL/idaes-solvers-windows-x86_64.tar.gz \
@@ -462,7 +563,11 @@ jobs:
fi
fi
cd $IPOPT_DIR
- tar -xzi < $IPOPT_TAR
+ if test "${{matrix.TARGET}}" == win; then
+ tar -xzi < $IPOPT_TAR
+ else
+ tar -xzf $IPOPT_TAR
+ fi
echo ""
echo "$IPOPT_DIR"
ls -l $IPOPT_DIR
@@ -514,7 +619,9 @@ jobs:
- name: Install GAMS Python bindings
if: ${{ ! matrix.slim }}
run: |
- GAMS_DIR="${env:TPL_DIR}/gams"
+ GAMS_DIR="$TPL_DIR/gams"
+ NEW_PYOMO_PATH="$GAMS_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
py_ver=$($PYTHON_EXE -c 'import sys;v="_%s%s" % sys.version_info[:2] \
;print(v if v != "_27" else "")')
if test -e $GAMS_DIR/apifiles/Python/api$py_ver; then
@@ -531,7 +638,18 @@ jobs:
$BARON_DIR = "${env:TPL_DIR}/baron"
echo "$BARON_DIR" | `
Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- $URL = "https://www.minlp.com/downloads/xecs/baron/current/"
+ $CURRENT_PYOMO_PATH="${env:PYOMO_PATH}"
+ # Prepend BARON_DIR with appropriate path separator
+ if ( "${{matrix.TARGET}}" -eq "win" ) {
+ $PATH_SEPARATOR = ";"
+ } else {
+ $PATH_SEPARATOR = ":"
+ }
+ $NEW_PYOMO_PATH = "$BARON_DIR$PATH_SEPARATOR$CURRENT_PYOMO_PATH"
+ echo "New PYOMO_PATH: $NEW_PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" | `
+ Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+ $URL = "https://minlp-downloads.nyc3.cdn.digitaloceanspaces.com/xecs/baron/current/"
if ( "${{matrix.TARGET}}" -eq "win" ) {
$INSTALLER = "${env:DOWNLOAD_DIR}/baron_install.exe"
$URL += "baron-win64.exe"
@@ -565,6 +683,8 @@ jobs:
run: |
GJH_DIR="$TPL_DIR/gjh"
echo "${GJH_DIR}" >> $GITHUB_PATH
+ NEW_PYOMO_PATH="$GJH_DIR:$PYOMO_PATH"
+ echo "PYOMO_PATH=$NEW_PYOMO_PATH" >> $GITHUB_ENV
INSTALL_DIR="${DOWNLOAD_DIR}/gjh"
if test ! -e "$INSTALL_DIR/bin"; then
mkdir -p "$INSTALL_DIR"
@@ -627,7 +747,7 @@ jobs:
> ${SITE_PACKAGES}/run_coverage_at_startup.pth
- name: Download and install extensions
- if: ${{ ! matrix.slim }}
+ if: ${{ ! matrix.slim && matrix.category != 'notests' }}
run: |
echo ""
echo "Pyomo download-extensions"
@@ -640,34 +760,48 @@ jobs:
- name: Report pyomo plugin information
run: |
+ # MRM / Jan 9, 2025: We update the PATH manually to make sure we
+ # capture all of our changes. This is necessary because of an
+ # issue with how the PATH rearranges on Windows.
+ # Issue: https://github.com/actions/runner-images/issues/11328
+ export PATH=$PYOMO_PATH
echo "$PATH"
pyomo help --solvers || exit 1
pyomo help --transformations || exit 1
pyomo help --writers || exit 1
- name: Run Pyomo tests
- if: matrix.mpi == 0
+ if: ${{ matrix.mpi == 0 && matrix.category != 'notests' }}
run: |
+ export PATH=$PYOMO_PATH
$PYTHON_EXE -m pytest -v \
-W ignore::Warning ${{matrix.category}} \
pyomo `pwd`/pyomo-model-libraries \
`pwd`/examples `pwd`/doc --junitxml="TEST-pyomo.xml"
- name: Run Pyomo MPI tests
- if: matrix.mpi != 0
+ if: ${{ matrix.mpi != 0 && matrix.category != 'notests' }}
run: |
# Manually invoke the DAT parser so that parse_table_datacmds.py
# is fully generated by a single process before invoking MPI
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \
parse_data_commands; parse_data_commands(data='')"
# Note: if we are testing with openmpi, add '--oversubscribe'
- mpirun -np ${{matrix.mpi}} pytest -v \
+ mpirun -np ${{matrix.mpi}} -oversubscribe pytest -v \
--junit-xml=TEST-pyomo-mpi.xml \
-m "mpi" -W ignore::Warning \
pyomo `pwd`/pyomo-model-libraries
+ - name: Build documentation
+ if: matrix.build_docs != 0
+ run: |
+ sudo apt-get -y install graphviz latexmk texlive texlive-latex-extra \
+ texlive-pictures
+ make -C doc/OnlineDocs html
+ make -C doc/OnlineDocs latexpdf
+
- name: Run documentation tests
- if: matrix.skip_doctest == 0
+ if: matrix.test_docs != 0
run: |
make -C doc/OnlineDocs doctest -d
@@ -681,6 +815,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: ${{github.job}}_${{env.GHA_JOBGROUP}}-${{env.GHA_JOBNAME}}
+ include-hidden-files: true
path: |
.coverage
coverage.xml
@@ -690,7 +825,7 @@ jobs:
bare-python-env:
- name: linux/3.8/bare-env
+ name: linux/3.9/bare-env
needs: lint # the linter job is a prerequisite for PRs
runs-on: ubuntu-latest
timeout-minutes: 10
@@ -698,10 +833,10 @@ jobs:
- name: Checkout Pyomo source
uses: actions/checkout@v4
- - name: Set up Python 3.8
+ - name: Set up Python 3.9
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.9
- name: Install Pyomo
run: |
@@ -733,18 +868,19 @@ jobs:
cover:
name: process-coverage-${{ matrix.TARGET }}
needs: build
- if: always() # run even if a build job fails
+ # run even if a build job fails, but not if canceled (except for branches)
+ if: success() || failure()
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
- os: [ubuntu-latest, macos-latest, windows-latest]
+ os: [ubuntu-latest, macos-13, windows-latest]
include:
- os: ubuntu-latest
TARGET: linux
- - os: macos-latest
+ - os: macos-13
TARGET: osx
- os: windows-latest
TARGET: win
@@ -759,17 +895,17 @@ jobs:
# id: pip-cache
# with:
# path: cache/pip
- # key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-3.8
+ # key: pip-${{env.CACHE_VER}}.0-${{runner.os}}-3.9
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- - name: Set up Python 3.8
+ - name: Set up Python 3.9
uses: actions/setup-python@v5
with:
- python-version: 3.8
+ python-version: 3.9
- name: Install Python Packages (pip)
shell: bash # DO NOT REMOVE: see note above
@@ -804,26 +940,6 @@ jobs:
$PYTHON_EXE -c "from pyomo.dataportal.parse_datacmds import \
parse_data_commands; parse_data_commands(data='')"
- - name: Update codecov uploader
- run: |
- set +e
- CODECOV="${GITHUB_WORKSPACE}/codecov.sh"
- echo "CODECOV=$CODECOV" >> $GITHUB_ENV
- for i in `seq 3`; do
- echo "Downloading current codecov script (attempt ${i})"
- curl -L https://codecov.io/bash -o $CODECOV
- if test $? == 0; then
- break
- fi
- DELAY=$(( RANDOM % 30 + 30))
- echo "Pausing $DELAY seconds before re-attempting download"
- sleep $DELAY
- done
- if test ! -e $CODECOV; then
- echo "Failed to download codecov.sh"
- exit 1
- fi
-
- name: Combine coverage reports
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main'
run: |
@@ -862,7 +978,7 @@ jobs:
- name: Upload codecov reports
if: github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main'
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
files: coverage.xml
token: ${{ secrets.PYOMO_CODECOV_TOKEN }}
@@ -874,10 +990,10 @@ jobs:
if: |
hashFiles('coverage-other.xml') != '' &&
(github.repository_owner == 'Pyomo' || github.ref != 'refs/heads/main')
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
files: coverage-other.xml
token: ${{ secrets.PYOMO_CODECOV_TOKEN }}
name: ${{ matrix.TARGET }}/other
- flags: ${{ matrix.TARGET }},other
+ flags: ${{ matrix.TARGET }}_other
fail_ci_if_error: true
diff --git a/.github/workflows/typos.toml b/.github/workflows/typos.toml
index 23f94fc8afd..80d50477ca4 100644
--- a/.github/workflows/typos.toml
+++ b/.github/workflows/typos.toml
@@ -38,6 +38,37 @@ caf = "caf"
WRONLY = "WRONLY"
# Ignore the name Hax
Hax = "Hax"
+# Ignore dout (short for dual output in SAS solvers)
+dout = "dout"
# Big Sur
Sur = "Sur"
+# contrib package named mis and the acronym whence the name comes
+mis = "mis"
+MIS = "MIS"
+# Ignore the shorthand ans for answer
+ans = "ans"
+# Ignore the keyword arange
+arange = "arange"
+# Ignore IIS
+IIS = "IIS"
+iis = "iis"
+# Ignore PN
+PN = "PN"
+# Ignore hd
+hd = "hd"
+# Ignore opf
+opf = "opf"
+# Ignore FRE
+FRE = "FRE"
+# Ignore MCH
+MCH = "MCH"
+# Ignore RO
+ro = "ro"
+RO = "RO"
+# Ignore EOF - end of file
+EOF = "EOF"
+# Ignore lst as shorthand for list
+lst = "lst"
+# Abbreviation of gamma (used in stochpdegas1_automatic.py)
+gam = "gam"
# AS NEEDED: Add More Words Below
diff --git a/.github/workflows/url_check.yml b/.github/workflows/url_check.yml
new file mode 100644
index 00000000000..797574574b4
--- /dev/null
+++ b/.github/workflows/url_check.yml
@@ -0,0 +1,32 @@
+name: URL Validation
+
+on:
+ schedule:
+ - cron: '0 3 * * 0'
+ workflow_dispatch:
+ inputs:
+ git-ref:
+ description: Git Hash (Optional)
+ required: false
+
+jobs:
+ url_check:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Pyomo source
+ uses: actions/checkout@v4
+ - name: URL Checker
+ uses: urlstechie/urlchecker-action@0.0.34
+ with:
+ # A comma-separated list of file types to cover in the URL checks
+ file_types: .md,.rst,.py
+ # Choose whether to include file with no URLs in the prints.
+ print_all: false
+ # More verbose summary at the end of a run
+ verbose: true
+ # How many times to retry a failed request (defaults to 1)
+ retry_count: 3
+ # Exclude:
+ # - Jenkins because it's behind a firewall
+ # - RTD because a magically-generated string triggers failures
+ exclude_urls: https://pyomo-jenkins.sandia.gov/,https://pyomo.readthedocs.io/en/%s/errors.html
diff --git a/.gitignore b/.gitignore
index 638dc70d13e..9550b0773f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,19 @@
+# temporary editor files
+*~
+.#*
+\#*#
+
# IDE configuration files
.idea
.spyder*
.ropeproject
.vscode
+
# Python generates numerous files when byte compiling / installing packages
+__pycache__/
*.pyx
-*.pyc
-*.pyo
-*.egg-info
+*.py[cod]
+*.egg-info/
# Documentation builds
doc/OnlineDocs/_build
@@ -17,6 +23,7 @@ doc/OnlineDocs/**/*.spy
*.out
pyomo/dataportal/parse_table_datacmds.py
gurobi.log
+cplex.log
# Results from pytest --with-coverage
.coverage
@@ -24,7 +31,6 @@ gurobi.log
# Jupyterhub/Jupyterlab checkpoints
.ipynb_checkpoints
-cplex.log
# Mac tracking files
*.DS_Store*
diff --git a/.jenkins.sh b/.jenkins.sh
index 37be6113ed9..45c401d2722 100644
--- a/.jenkins.sh
+++ b/.jenkins.sh
@@ -20,8 +20,11 @@
#
# CODECOV_TOKEN: the token to use when uploading results to codecov.io
#
-# CODECOV_ARGS: additional arguments to pass to the codecov uploader
-# (e.g., to support SSL certificates)
+# CODECOV_SOURCE_BRANCH: passed to the 'codecov-cli' command; branch of Pyomo
+# (e.g., to enable correct codecov uploads)
+#
+# CODECOV_REPO_OWNER: passed to the 'codecov-cli' command; owner of repo
+# (e.g., to enable correct codecov uploads)
#
# DISABLE_COVERAGE: if nonempty, then coverage analysis is disabled
#
@@ -43,9 +46,6 @@ fi
if test -z "$SLIM"; then
export VENV_SYSTEM_PACKAGES='--system-site-packages'
fi
-if test ! -z "$CATEGORY"; then
- export PY_CAT="-m $CATEGORY"
-fi
if test "$WORKSPACE" != "`pwd`"; then
echo "ERROR: pwd is not WORKSPACE"
@@ -122,10 +122,23 @@ if test -z "$MODE" -o "$MODE" == setup; then
echo "PYOMO_CONFIG_DIR=$PYOMO_CONFIG_DIR"
echo ""
+ # Call Pyomo build scripts to build TPLs that would normally be
+ # skipped by the pyomo download-extensions / build-extensions
+ # actions below
+ if [[ " $CATEGORY " == *" builders "* ]]; then
+ echo ""
+ echo "Running local build scripts..."
+ echo ""
+ set -x
+ python pyomo/contrib/simplification/build.py --build-deps || exit 1
+ set +x
+ fi
+
# Use Pyomo to download & compile binary extensions
i=0
while /bin/true; do
i=$[$i+1]
+ echo ""
echo "Downloading pyomo extensions (attempt $i)"
pyomo download-extensions $PYOMO_DOWNLOAD_ARGS
if test $? == 0; then
@@ -178,7 +191,7 @@ if test -z "$MODE" -o "$MODE" == test; then
python -m pytest -v \
-W ignore::Warning \
--junitxml="TEST-pyomo.xml" \
- $PY_CAT $TEST_SUITES $PYTEST_EXTRA_ARGS
+ -m "$CATEGORY" $TEST_SUITES $PYTEST_EXTRA_ARGS
# Combine the coverage results and upload
if test -z "$DISABLE_COVERAGE"; then
@@ -192,22 +205,51 @@ if test -z "$MODE" -o "$MODE" == test; then
# Note, that the PWD should still be $WORKSPACE/pyomo
#
coverage combine || exit 1
- coverage report -i
+ coverage report -i || exit 1
+ coverage xml -i || exit 1
export OS=`uname`
- if test -z "$CODECOV_TOKEN"; then
- coverage xml
- else
- CODECOV_JOB_NAME=`echo ${JOB_NAME} | sed -r 's/^(.*autotest_)?Pyomo_([^\/]+).*/\2/'`.$BUILD_NUMBER.$python
+ if test -z "$PYOMO_SOURCE_SHA"; then
+ PYOMO_SOURCE_SHA=$GIT_COMMIT
+ fi
+ if test -n "$CODECOV_TOKEN" -a -n "$PYOMO_SOURCE_SHA"; then
+ _NAME=$(echo $JOB_NAME | sed -r 's/^(.*(autotest|Build)_)?([^\/]+).*/\3/')
+ _MATRIX=$(echo $JOB_NAME | sed -r "s/,/\n/g" | grep -v host \
+ | sed -r 's/.*=//' | tr '\n' , | sed -r 's/,+$//')
+ CODECOV_JOB_NAME=${_NAME}/${_MATRIX}.${BUILD_NUMBER}
+ CODECOV_FLAG=$(echo $JOB_NAME | sed -r "s/,/\n/g" | grep CATEGORY \
+ | sed -r 's/.*=//')
+ if test -z "$CODECOV_FLAG"; then
+ CODECOV_FLAG=linux
+ fi
+ if test -z "$CODECOV_REPO_OWNER"; then
+ if test -n "$PYOMO_SOURCE_REPO"; then
+ CODECOV_REPO_OWNER=$(echo "$PYOMO_SOURCE_REPO" | cut -d '/' -f 4)
+ elif test -n "$GIT_URL"; then
+ CODECOV_REPO_OWNER=$(echo "$GIT_URL" | cut -d '/' -f 4)
+ else
+ CODECOV_REPO_OWNER=""
+ fi
+ fi
+ if test -z "$CODECOV_SOURCE_BRANCH"; then
+ CODECOV_SOURCE_BRANCH=$(git branch -av --contains "$PYOMO_SOURCE_SHA" \
+ | grep "${PYOMO_SOURCE_SHA:0:7}" | grep "/origin/" \
+ | cut -d '/' -f 3 | cut -d' ' -f 1)
+ if test -z "$CODECOV_SOURCE_BRANCH"; then
+ CODECOV_SOURCE_BRANCH=main
+ fi
+ fi
i=0
while /bin/true; do
i=$[$i+1]
echo "Uploading coverage to codecov (attempt $i)"
- codecov -X gcovcodecov -X gcov -X s3 --no-color \
- -t $CODECOV_TOKEN --root `pwd` -e OS,python \
- --name $CODECOV_JOB_NAME $CODECOV_ARGS \
- | tee .cover.upload
- if test $? == 0 -a `grep -i error .cover.upload \
- | grep -v branch= | wc -l` -eq 0; then
+ codecovcli -v upload-process --sha $PYOMO_SOURCE_SHA \
+ --fail-on-error --git-service github --token $CODECOV_TOKEN \
+ --slug pyomo/pyomo --file coverage.xml --disable-search \
+ --flag $CODECOV_FLAG \
+ --name $CODECOV_JOB_NAME \
+ --branch $CODECOV_REPO_OWNER:$CODECOV_SOURCE_BRANCH \
+ --env OS,python --network-root-folder `pwd` --plugin noop
+ if test $? == 0; then
break
elif test $i -ge 4; then
exit 1
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index dc77164f866..4046cecebb7 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -8,12 +8,27 @@ version: 2
build:
os: ubuntu-22.04
tools:
- python: "3.8"
+ python: "3.11"
+ apt_packages:
+ - graphviz
+ - latexmk
+ - texlive
+ - texlive-latex-extra
+ - texlive-pictures
+ jobs:
+ post_build:
+ - |
+ for pdf in $READTHEDOCS_OUTPUT/pdf/*.pdf; do
+ if test [[ `basename $pdf` == graphviz* ]]; then
+ rm -v $pdf;
+ fi;
+ done
sphinx:
configuration: doc/OnlineDocs/conf.py
-formats: all
+formats:
+ - pdf
# Set the version of Python and requirements required to build the docs
python:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 553a4f1c3bd..09418d4d627 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,415 @@
Pyomo CHANGELOG
===============
+-------------------------------------------------------------------------------
+Pyomo 6.9.2 (16 Apr 2025)
+-------------------------------------------------------------------------------
+
+- General
+ - Update Copyright to 2025 (#3515)
+ - `capture_output`: do not output to captured file descriptors (#3537, #3560)
+ - `calc_variable_from_constraint`: guard against expression overflow (#3541)
+ - Standardize the usage of pyomo.environ imports (#3545)
+ - Update ASL CMake builders (#3548)
+ - Support passing LoggerAdapter objects to LogStream (#3547)
+- Core
+ - Support multi-column DataFrames in Initializer (#3552)
+ - Multiple dispatch for relational expression generation (#3483)
+ - Type check `exception` args in component `__call__` implementations (#3538)
+- Documentation
+ - Move RTD ads to the sidebar (#3536)
+ - Standardize Example Imports (#3543)
+ - LD-SDA Documentation (#3539)
+ - Fix broken URLs in documentation (#3529, #3544)
+ - Update future solver interface documentation (#3526)
+ - Document `BlockData.clone` (#3542)
+- Solver Interfaces
+ - Fix bug in `XpressPersistent.update_var` (#3566)
+ - Avoid duplicate `AMPLFUNC` entries in `ipopt_v2` (#3554)
+ - Update deprecation warnings in `contrib.solver` (#3553, #3555)
+ - Support for upcoming knitro python package (#3478)
+ - Future solver interface reorganization and updates (#3476)
+ - Update HiGHS interface to allow keyboard interrupts (#3509, #3511)
+ - Fix/extend MOSEK option handling (#3488)
+- Testing
+ - Defer `pathlib` import, remove test output file (#3563)
+ - Add IDAES Solvers to Mac; Update to Ubuntu 22.04 (#3556)
+ - Clean up numeric_expr dispatcher test driver (#3551)
+ - Testing and coverage fixes (#3549)
+ - Resolve intermittent test failure (increase sleep time) (#3517)
+ - Be more careful when/how we timeout conda install (#3514)
+- Contributed Packages
+ - cspline_external: Add a function for cubic spline interpolation (#3216)
+ - DoE: Correct initialization when using lower diagonal of FIM (#3532)
+ - FBBT: Resolve bug registering native type handlers (#3567)
+ - parmest/DoE: Ordering and param bug fixes (#3512)
+ - PyNumero: Add support for greybox models (#3364)
+ - PyROS: Modify Decision Rule Order Efficiency (#3562)
+ - PyROS: Revise second-stage equality reformulation under discrete
+ (scenario-based) uncertainty (#3533)
+ - PyROS: Add Uncertain Parameter Reduction (#3503)
+
+-------------------------------------------------------------------------------
+Pyomo 6.9.1 (5 Mar 2025)
+-------------------------------------------------------------------------------
+
+- General
+ - Remove URL and replace with full citation (#3490)
+ - Rename project "pyomo" in setup.py [PEP 625] (#3430)
+ - Resolve errors in `TeeStream` and `capture_output` (#3497)
+- Documentation
+ - Update autosummary for Sphinx 8.2.1 (#3492)
+ - Resolve errors building documentation PDF (#3495)
+- Testing
+ - conda: disable '--update-deps' to work around buggy libffi(?) (#3499)
+ - Update for March 2024 typos release (#3500)
+ - Add timeout when installing optional packages (solvers) in conda (#3501)
+ - Updates to CodeCov configuration (#3491)
+- Contributed Packages
+ - APPSI: Add warmstart for appsi_highs (issue #3450) (#3494)
+
+-------------------------------------------------------------------------------
+Pyomo 6.9.0 (21 Feb 2025)
+-------------------------------------------------------------------------------
+
+- General
+ - Big Wheel of Misfortune - A Practice in Reviewing Old Issues (#3460, #3473)
+ - Resolve buffering issues in `TeeStream` and `capture_output` (#3449)
+ - Update GHA badges on README.md (#3457)
+ - Fix incompatibility with `imp` and `DeferredImportCallbackFinder` (#3444)
+ - Remove Python 3.8 Support (#3438)
+- Core
+ - Resolve error parenthesizing pow mantissa (#3472)
+ - Resolve OSX error accessing closed filehandle (#3467)
+ - Allow construction of CUID from another CUID (#3464)
+ - Clean up `identify_variables` / `identify_mutable_parameters`;
+ deprecate `SimpleExpressionVisitor` (#3436)
+- Solver Interfaces
+ - Solver refactor: BUGFIX, f-string in contrib/solver (#3481)
+ - Update Gurobi NL interface for Gurobi 12.x (#3470)
+ - Defer starting the SAS session until needed (#3448)
+ - Solver refactor: Validator for `tee` in `contrib.solver.config` (#3482)
+- Testing
+ - Pin Sphinx to not 8.2.0 (#3479)
+ - Typos corrections (#3437, #3474)
+ - Address intermittent TeeStream test failure (#3465)
+ - 2025 Testing update: Black 25.1.0, testing Qt without X11 (#3463)
+ - Testing: exclude Xpress 9.5.1 on Windows/GHA/Python3.{0,1} (#3455)
+ - CY25 CI Infrastructure and typo fixes (#3453)
+ - Verify we are testing all NEOS solvers (#3433)
+- Contributed Packages
+ - GDPOpt: Add Logic-Based Discrete-Steepest Descent Algorithm (#3331)
+ - PyROS: Fix/Tweak Documentation and Solver Output Logging (#3475)
+ - PyROS: Fix Treatment of Fixed Model Variables and Initialization of
+ Auxiliary Uncertain Parameters (#3461)
+ - PyROS: Improve handling of separation problem sub-solver errors (#3441)
+ - PyROS: Extend valid types for solver argument `uncertain_params` (#3439)
+ - PyROS: Add Gaussian confidence level attribute to `EllipsoidalSet` (#3434)
+
+-------------------------------------------------------------------------------
+Pyomo 6.8.2 (18 Nov 2024)
+-------------------------------------------------------------------------------
+
+- Core
+ - Resolve errors in mapping ScalarVar to numpy ndarray (#3423)
+- Documentation
+ - Update Documentation URLs (#3425)
+- Solver Interfaces
+ - Resolve error in xpress_direct interface retrieving reduced costs (#3422)
+- Testing
+ - Remove (unused) legacy test drivers (#3427)
+
+-------------------------------------------------------------------------------
+Pyomo 6.8.1 (15 Nov 2024)
+-------------------------------------------------------------------------------
+
+"Annie"
+
+SIGNIFICANT CHANGE NOTICE
+
+- This will be the last release to support Python 3.8
+- This is the first release to be tested against Python 3.13
+- Complete reorganization of our online documentation (#3382, #3378)
+
+CHANGELOG
+
+- General
+ - Add a 'Do not delete' Disclaimer to Issues/PR Templates (#3361)
+ - Add URL Status Badge to README (#3373)
+ - Resolve change in `InvalidNumber` handling in writers (#3390)
+ - Update `common.timing` to make tests more deterministic (#3397)
+ - Defer processing `ConfigValue`/`ConfigList` default until first use (#3394)
+ - Improved support for moved/renamed/deprecated modules (#3385)
+ - Fix `ConfigValue` initialization in multithreaded environments (#3405)
+ - `ConfigDict`: prevent recursion on partially-constructed objects (#3409)
+ - Fix bug in `AutoSlots` deepcopy (#3412, #3413)
+ - Update `mpi4py_available` to work around `conda-forge/openmpi` (#3416)
+- Core
+ - Resolve bugs in `create_node_with_local_data` (#3376)
+ - Resolve issue in filter/validate deprecation path (#3368)
+ - Support `Param.pprint()` for non-finite Params (#3387)
+ - Add (parameterized) linear programming dual transformation (#3402)
+- Documentation
+ - Autogenerate API documentation (#3378)
+ - Add Alternative Solutions documentation (#3370)
+ - Reorganize online documentation (#3382)
+ - Fix broken doc URLs (#3398)
+ - Improved autoenum documentation (#3389)
+ - Reduce the number of formats built on readthedocs to avoid timeout (#3404)
+- Solver Interfaces
+ - Remove deprecated `gurobipy` `addConstr` call (#3350)
+ - Update Xpress interfaces to support 9.5 (#3392)
+ - Add support for templatized models in `gurobi_direct_v2` (#3362)
+ - Update test for GAMS mapping 'infeasible or unbounded' to infeasible (#3396)
+ - `XpressDirect.available()`: check there is a valid license (#3400)
+ - Move away from dependence on gurobi.sh (#3384)
+ - Fix error when xpress is imported before `xpress_direct` (#3410)
+- Testing
+ - Move URL Checker to Weekly Job (#3360)
+ - Correct newly discovered typos (#3365, #3399)
+ - Remove Octeract from NEOS solvers list (and other testing fixes) (#3374)
+ - Guard tests against broken Gurobi licenses (#3383)
+ - Remove pin to Gurobi 10.0.3 (#3393)
+ - Add Python 3.13 to Testing Infrastructure (#3401, #3419)
+ - Resolve `timeout()` failures on Windows/py3.13 (#3415)
+- GDP
+ - Fix performance degradation in hull transformation (#3366)
+- Contributed Packages
+ - DoE: Fix bug from using hardcoded value (#3358)
+ - iis: Catch catastrophic solver failure when building MIS (#3403)
+ - PyNumero: Reverse `BlockVector`/`MPIBlockVector` base class order (#3380)
+ - PyNumero: Resolve incompatibilities with NumPy2 (#3408)
+ - PyROS: Overhaul preprocessor subroutine and subproblem objects (#3341)
+
+-------------------------------------------------------------------------------
+Pyomo 6.8.0 (20 Aug 2024)
+-------------------------------------------------------------------------------
+
+SIGNIFICANT CHANGE NOTICE
+
+- Internal data storage for Constraint objects (see #3293)
+- No longer release cythonized wheel for Python 3.11+ (see #3355)
+
+CHANGELOG
+
+- General
+ - Add ParameterizedQuadraticRepn and corresponding walker (#3324)
+ - Update Pyomo for NumPy 2.0 compatibility (#3292, #3353)
+ - Add ParameterizedLinearRepn and corresponding walker (#3268)
+ - Update Release Process Workflow for changes in `pip` (#3355)
+- Core
+ - Handle uninitialized variable in `propagate_solution` of scaling
+ transformation (#3275)
+ - Add `context` option to `SuffixFinder` (#3348)
+ - Remove the `_suppress_ctypes` attribute from Block (#3347)
+ - Improve `Set` initialization performance (#3302)
+ - Update Constraint to only store the original expression (not
+ lower/body/upper) (#3293)
+ - Kernel: fix bug in conic geomean (#3310)
+ - Fix bug with IndexedSet objects and the within argument (#3288)
+ - Support validate/filter for IndexedSet components using index (#3338)
+- Solver Interfaces
+ - Resolve NLv2 incompatibility with multithreading (#3332)
+ - Resolve writer performance degradation (#3343)
+ - Fix bug with inconsistent use of `result` and `results` (#3337)
+ - LegacySolverWrapper: restore 'options' attribute (#3334)
+ - Fix bug in XpressDirect._load_slacks (#3318)
+ - NLv2: support expressions with nested external functions (#3319)
+ - Ignore errors on ASL solver version check (#3298)
+ - Add SAS solver interface (#2886, #3309)
+- Testing
+ - Omnibus testing / platform portability fixes (#3335)
+ - Change BARON download URL (#3328)
+ - Disable interface/testing for NEOS/octeract (#3322)
+ - Fix typo in Jenkins driver (#3312)
+ - Jenkins: update logic for recording variables (#3311)
+ - Unpin Codecov / Update coverage (#3303)
+- GDP
+ - Don't transform known-to-be infeasible Disjuncts in multiple BigM (#3314)
+- Contributed Packages
+ - alternative_solutions: Add a new contrib package for generating
+ alternative solutions (#3270)
+ - APPSI: Allow maingo_solvermodel to be imported without maingopy (#3330)
+ - APPSI: Sort indices while removing constraints to fix bug in HiGHs
+ interface (#3281)
+ - CP: Add beforeChild handling for bools in logical expressions (#3315)
+ - DoE: Refactor to improve API and maintainability (#3317)
+ - incidence_analysis: Raise error in `generate_strongly_connected_components`
+ instead of asserting (#3305)
+ - parmest: Add missing main call for example file (#3349)
+ - piecewise: Add incremental PW linear to MIP transformation (#3287)
+ - piecewise: Add nonlinear-to-piecewise-linear transformation (#3333)
+ - PyNumero: Support user-provided CyIpopt callbacks with 13 arguments (#3289)
+ - PyNumero: Support PyomoNLP scaling factors on sub-blocks (#3295)
+ - PyROS: Temporarily Adjust NL Writer Feasibility Tolerance (#3280)
+ - viewer: Add option to specify the model by variable name (#3271)
+
+-------------------------------------------------------------------------------
+Pyomo 6.7.3 (29 May 2024)
+-------------------------------------------------------------------------------
+
+- Core
+ - Deprecate `pyomo.core.plugins.transform.model.to_standard_form()` (#3265)
+ - Reorder definitions to avoid `NameError` in some situations (#3264)
+- Solver Interfaces
+ - NLv2: Fix linear presolver with constant defined vars/external fcns (#3276)
+- Testing
+ - Add URL checking to GHA linting job (#3259, #3261)
+ - Skip Windows Python 3.8 conda GHA job (#3269)
+- Contributed Packages
+ - DoE: Bug fixes for workshop (#3267)
+ - viewer: Update guard for pint import (#3277)
+
+-------------------------------------------------------------------------------
+Pyomo 6.7.2 (9 May 2024)
+-------------------------------------------------------------------------------
+
+- General
+ - Support config domains with either method or attribute domain_name (#3159)
+ - Automate TPL callback registrations (#3167)
+ - Fix type registrations for ExternalFunction arguments (#3168)
+ - Only modify module path and spec for deferred import modules (#3176)
+ - Add "mixed" standard form representation (#3201)
+ - Support "default" dispatchers in `ExitNodeDispatcher` (#3194)
+ - Redefine objective sense as a proper `IntEnum` (#3224)
+ - Fix division-by-0 bug in linear walker (#3246)
+- Core
+ - Allow `Var` objects in `LinearExpression.args` (#3189)
+ - Add type hints to components (#3173)
+ - Simplify expressions generated by `TemplateSumExpression` (#3196)
+ - Make component data public classes (#3221, #3253)
+ - Exploit repeated named expressions in `identify_variables` (#3190)
+- Documentation
+ - NFC: Add link to the HOMOWP companion notebooks (#3195)
+ - Update installation documentation to include Cython instructions (#3208)
+ - Add links to the Pyomo Book Springer page (#3211)
+- Solver Interfaces
+ - Fix division by zero error in linear presolve (#3161)
+ - Subprocess timeout update (#3183)
+ - Solver Refactor - Bug fixes for various components (#3181, #3214, #3228)
+ - NLv2: handle presolved independent linear subsystems (#3193)
+ - Update `LegacySolverWrapper` compatibility with the `pyomo` script (#3202)
+ - Fix mosek_direct to use putqconk instead of putqcon (#3199)
+ - Check _skip_trivial_constraints before the constraint body (#3226)
+ - Fix AMPL solver duplicate funcadd (#3206)
+ - Disable the use of universal newlines in the ipopt_v2 NL file (#3231)
+ - NLv2: fix reporting numbers of nonlinear discrete variables (#3238)
+ - Fix: Get SCIP solving time considering float number with some text (#3234)
+ - Solver Refactor - Add `gurobi_direct` implementation (#3225)
+- Testing
+ - Update TPL package list due to `contrib.solver` (#3164)
+ - Set maxDiff=None on the base TestCase class (#3171)
+ - Testing infrastructure updates (#3175)
+ - Typos update for March 2024 (#3219)
+ - Add openmpi to testing environment to resolve issue in mpi4py (#3236, #3239)
+ - Skip black 24.4.1 due to a bug in the parser (#3247)
+ - Skip tests on draft and WIP pull requests (#3223)
+ - Update GHA to grab gurobipy from PyPI (#3254)
+- GDP
+ - Use private_data for all original / transformed component mappings (#3166)
+ - Fix a bug in gdp.bigm transformation for nested GDPs (#3213)
+- Contributed Packages
+ - APPSI: cmodel: handle non-mutable params in var / constraint bounds (#3182)
+ - APPSI: Allow APPSI FBBT to handle nested named Expressions (#3185)
+ - APPSI: Add MAiNGO solver interface (#3165)
+ - CP: Add SequenceVar and other logical expressions for scheduling (#3227)
+ - DoE: Bug fixes (#3245)
+ - iis: Add minimal intractable system infeasibility diagnostics (#3172)
+ - incidence_analysis: Improve `solve_strongly_connected_components`
+ performance for models with named expressions (#3186)
+ - incidence_analysis: Add function to plot incidence graph in
+ Dulmage-Mendelsohn order (#3207)
+ - incidence_analysis: Require variables and constraints to be specified
+ separately in `IncidenceGraphInterface.remove_nodes` (#3212)
+ - latex_printer: bugfix for set operations / multidimensional sets (#3177)
+ - MindtPy: Add HiGHS support (#2971)
+ - MindtPy: Add call_before_subproblem_solve callback (#3251)
+ - Parmest: New UI using experiment lists (#3160)
+ - piecewise: Add piecewise linear transformations (#3036)
+ - preprocessing: bugfix: intersect domains in variable aggregator (#3241)
+ - PyNumero: Allow CyIpopt to solve problems without objectives (#3163)
+ - PyNumero: Work around bug in CyIpopt 1.4.0 (#3222)
+ - PyNumero: Include "inventory" in readme (#3248)
+ - PyROS: Simplify custom domain validators (#3169)
+ - PyROS: Fix iteration logging for edge case involving discrete sets (#3170)
+ - PyROS: Update solver timing system (#3198)
+ - simplification: expression simplification using GiNaC or SymPy (#3088)
+
+-------------------------------------------------------------------------------
+Pyomo 6.7.1 (21 Feb 2024)
+-------------------------------------------------------------------------------
+
+- General
+ - Add support for tuples in `ComponentMap`; add `DefaultComponentMap` (#3150)
+ - Update `Path`, `PathList`, and `IsInstance` Domain Validators (#3144)
+ - Remove usage of `__all__` (#3142)
+ - Extend Path and Type Checking Validators of `common.config` (#3140)
+ - Update Copyright Statements (#3139)
+ - Update `ExitNodeDispatcher` to better support extensibility (#3125)
+ - Create contributors data gathering script (#3117)
+ - Prevent duplicate entries in ConfigDict declaration order (#3116)
+ - Remove unnecessary `__future__` imports (#3109)
+ - Import pandas through pyomo.common.dependencies (#3102)
+ - Update links to workshop slides (#3079)
+ - Remove incorrect use of identity (is) comparisons (#3061)
+- Core
+ - Add `Block.register_private_data_initializer()` (#3153)
+ - Generalize the simple_constraint_rule decorator (#3152)
+ - Fix edge case assigning new numeric types to Var/Param with units (#3151)
+ - Add private_data to `_BlockData` (#3138)
+ - IndexComponent create implicit sets as "anonymous" sets (#3075)
+ - Add `all_different` and `count_if` to the logical expression system (#3058)
+ - Fix RangeSet.__len__ when defined by floats (#3119)
+ - Overhaul the `Suffix` component (#3072)
+ - Enforce expression immutability in `expr.args` (#3099)
+ - Improve NumPy registration when assigning numpy to Param (#3093)
+ - Track changes in PyPy behavior introduced in 7.3.14 (#3087)
+ - Remove automatic numpy import (#3077)
+ - Fix `range_difference` for Sets with nonzero anchor points (#3063)
+ - Clarify errors raised by accessing Sets by positional index (#3062)
+- Documentation
+ - Update intersphinx links, remove docs for nonfunctional code (#3155)
+ - Update MPC documentation and citation (#3148)
+ - Fix an error in the documentation for LinearExpression (#3090)
+ - Fix Pyomo.DoE documentation (#3070)
+ - Fix latex_printer documentation (#3066)
+- Solver Interfaces
+ - Preview release of new solver interfaces as pyomo.contrib.solver
+ (#3137, #3156)
+ - Make error msg more explicit wrt different interfaces (#3141)
+ - NLv2: only raise exception for empty models in the legacy API (#3135)
+ - Add `to_expr()` to AMPLRepn, fix NLWriterInfo return type (#3095)
+- Testing
+ - Update Release Wheel Builder Action (#3149)
+ - Actions Version Update: Address node.js deprecations (#3118)
+ - New Black Major Release (24.1.0) (#3108)
+ - Use scip for PyROS tests (#3104)
+ - Add missing solver dependency flags for OnlineDocs tests (#3094)
+ - Re-enable `contrib.viewer.tests.test_qt.py` (#3085)
+ - Add automated testing of OnlineDocs examples (#3080)
+ - Silence deprecation warnings emitted by Pyomo tests (#3076)
+ - Fix Python 3.12 tests (manage `pyutilib`, `distutils` dependencies) (#3065)
+- DAE
+ - Replace deprecated `numpy.math` alias with standard `math` module (#3074)
+- GDP
+ - Handle nested GDPs correctly in all the transformations (#3145)
+ - Fix bugs in nested models in gdp.hull transformation (#3143)
+ - Various bug fixes in gdp.mbigm transformation (#3073)
+ - Add GDP => MINLP Transformation (#3082)
+- Contributed Packages
+ - GDPopt: Fix lbb solve_data bug (#3133)
+ - GDPopt: Adding missing import for gdpopt.enumerate (#3105)
+ - FBBT: Extend `fbbt.ExpressionBoundsVisitor` to handle relational
+ expressions and Expr_if (#3129)
+ - incidence_analysis: Method to add an edge in IncidenceGraphInterface (#3120)
+ - incidence_analysis: Add subgraph method to IncidencegraphInterface (#3122)
+ - incidence_analysis: Add `ampl_repn` option (#3069)
+ - incidence_analysis: Update documentation (#3067)
+ - interior_point: Resolve test failure due to Mumps update (#3114)
+ - MindtPy: Various bug fixes (#3034)
+ - PyROS: Update Solver Argument Resolution and Validation Routines (#3126)
+ - PyROS: Update Subproblem Initialization Routines (#3071)
+ - PyROS: Fix DR polishing under nominal objective focus (#3060)
-------------------------------------------------------------------------------
Pyomo 6.7.0 (29 Nov 2023)
diff --git a/LICENSE.md b/LICENSE.md
index 9fd5d9b810c..2350f7c8d99 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,7 +1,7 @@
LICENSE
=======
-Copyright (c) 2008-2024 National Technology and Engineering Solutions of
+Copyright (c) 2008-2025 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.
diff --git a/README.md b/README.md
index 2f8a25403c2..384d7234533 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://github.com/Pyomo/pyomo/actions?query=event%3Apush+workflow%3A%22GitHub+CI%22)
+[](https://github.com/Pyomo/pyomo/actions/workflows/test_pr_and_main.yml?query=branch%3Amain+event%3Apush)
[](https://pyomo-jenkins.sandia.gov/)
[](https://codecov.io/gh/Pyomo/pyomo)
[](http://pyomo.readthedocs.org/en/latest/)
@@ -51,8 +51,8 @@ Pyomo is available under the BSD License - see the
Pyomo is currently tested with the following Python implementations:
-* CPython: 3.8, 3.9, 3.10, 3.11, 3.12
-* PyPy: 3.9
+* CPython: 3.9, 3.10, 3.11, 3.12, 3.13
+* PyPy: 3.10
_Testing and support policy_:
@@ -71,8 +71,11 @@ version, we will remove testing for that Python version.
### Tutorials and Examples
+* [Pyomo — Optimization Modeling in Python](https://link.springer.com/book/10.1007/978-3-030-68928-5)
* [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/)
+* The [companion notebooks](https://mobook.github.io/MO-book/intro.html)
+ for *Hands-On Mathematical Optimization with Python*
* [Pyomo Gallery](https://github.com/Pyomo/PyomoGallery)
### Getting Help
@@ -83,7 +86,7 @@ To get help from the Pyomo community ask a question on one of the following:
### Developers
-Pyomo development moved to this repository in June, 2016 from
+Pyomo development moved to this repository in June 2016 from
Sandia National Laboratories. Developer discussions are hosted by
[Google Groups](https://groups.google.com/forum/#!forum/pyomo-developers).
diff --git a/RELEASE.md b/RELEASE.md
index 03baa803ac9..f5506f93848 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,17 +1,18 @@
-We are pleased to announce the release of Pyomo 6.7.0.
+We are pleased to announce the release of Pyomo 6.9.2.
Pyomo is a collection of Python software packages that supports a
diverse set of optimization capabilities for formulating and analyzing
optimization models.
-The following are highlights of the 6.7 release series:
+The following are highlights of the 6.9 release series:
- - Added support for Python 3.12
- - Removed support for Python 3.7
- - New writer for converting linear models to matrix form
- - New packages:
- - latex_printer (print Pyomo models to a LaTeX compatible format)
- - ...and of course numerous minor bug fixes and performance enhancements
+- Removed support for Python 3.8
+- New Logic-Based Discrete-Steepest Descent Algorithm in GDPOpt
+- New External Function for Cubic Spline Interpolation
+- New solver interfaces:
+ - Support for upcoming knitro Python package
+ - v2: Ongoing solver interface refactor
+- ...and of course numerous minor bug fixes and performance enhancements
A full list of updates and changes is available in the
[`CHANGELOG.md`](https://github.com/Pyomo/pyomo/blob/main/CHANGELOG.md).
diff --git a/conftest.py b/conftest.py
index 7faad6fc89b..e73871b8b40 100644
--- a/conftest.py
+++ b/conftest.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,6 +11,22 @@
import pytest
+_implicit_markers = {'default'}
+_extended_implicit_markers = _implicit_markers.union({'solver'})
+
+
+def pytest_collection_modifyitems(items):
+ """
+ This method will mark any unmarked tests with the implicit marker ('default')
+
+ """
+ for item in items:
+ try:
+ next(item.iter_markers())
+ except StopIteration:
+ for marker in _implicit_markers:
+ item.add_marker(getattr(pytest.mark, marker))
+
def pytest_runtest_setup(item):
"""
@@ -32,13 +48,10 @@ def pytest_runtest_setup(item):
the default mode; but if solver tests are also marked with an explicit
category (e.g., "expensive"), we will skip them.
"""
- marker = item.iter_markers()
solvernames = [mark.args[0] for mark in item.iter_markers(name="solver")]
solveroption = item.config.getoption("--solver")
markeroption = item.config.getoption("-m")
- implicit_markers = ['default']
- extended_implicit_markers = implicit_markers + ['solver']
- item_markers = set(mark.name for mark in marker)
+ item_markers = set(mark.name for mark in item.iter_markers())
if solveroption:
if solveroption not in solvernames:
pytest.skip("SKIPPED: Test not marked {!r}".format(solveroption))
@@ -46,9 +59,9 @@ def pytest_runtest_setup(item):
elif markeroption:
return
elif item_markers:
- if not set(implicit_markers).issubset(
- item_markers
- ) and not item_markers.issubset(set(extended_implicit_markers)):
+ if not _implicit_markers.issubset(item_markers) and not item_markers.issubset(
+ _extended_implicit_markers
+ ):
pytest.skip('SKIPPED: Only running default, solver, and unmarked tests.')
diff --git a/doc/OnlineDocs/Makefile b/doc/OnlineDocs/Makefile
index 3625325ef73..dfb9df8e7db 100644
--- a/doc/OnlineDocs/Makefile
+++ b/doc/OnlineDocs/Makefile
@@ -7,6 +7,7 @@ SPHINXBUILD = sphinx-build
SPHINXPROJ = Pyomo
SOURCEDIR = .
BUILDDIR = _build
+APIDIR = api
# Put it first so that "make" without argument is like "make help".
help:
@@ -19,8 +20,17 @@ help:
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-clean clean_tests:
+clean:
@$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
- @echo "Removing *.spy, *.out"
+ @echo "Removing *.spy"
@find . -name \*.spy -delete
- @find src -name \*.out -delete
+ @for D in $(BUILDDIR) $(SOURCEDIR)/$(APIDIR); do \
+ if test -d "$$D"; then echo "Removing $$D"; rm -r "$$D"; fi \
+ done
+ @for D in ext src; do \
+ if test -d "$$D/__pycache__"; then \
+ echo "Removing $$D/__pycache__"; rm -r "$$D/__pycache__" ; \
+ fi \
+ done
+
+rebuild: clean html
diff --git a/doc/OnlineDocs/README.md b/doc/OnlineDocs/README.md
index a2d4e5997dc..53587d2d97d 100644
--- a/doc/OnlineDocs/README.md
+++ b/doc/OnlineDocs/README.md
@@ -1,27 +1,70 @@
+Pyomo leverages ``make`` to generate documentation. The following two
+sections describe how to build and test the online documentation
+locally.
+
+> **NOTE**: All commands assume you are running from the *root Pyomo source directory*.
+
+
Preview Changes Locally
-------------------------
+-----------------------
-1. Install Sphinx
+1. Install documentation dependencies (e.g., Sphinx, etc):
```bash
- $ pip install sphinx sphinx_rtd_theme sphinx_copybutton
+ $ pip install -e .[docs]
```
- **NOTE**: You may get a warning about the `dot` command if you do not have
- `graphviz` installed.
+ > **NOTE**: You may get a warning about the `dot` command if you do
+ > not have `graphviz` installed.
-1. Build the documentation
+
+2. Build the documentation. Sphinx (and Pyomo) support multiple
+ documentation *targets*. These instructions describe building the
+ `html` target, but the same process applies for other targets.
```bash
- $ make html # Option 1
- $ make latexpdf # Option 2
+ $ make -C doc/OnlineDocs html
```
-1. View `_build/html/index.html` in your browser
+3. View ``doc/OnlineDocs/_build/html/index.html`` in your browser
Test Changes Locally
--------------------
```bash
- $ make -C doc/OnlineDocs doctest -d # from the pyomo root folder
+ $ make -C doc/OnlineDocs doctest
+ ```
+
+Rebuilding the documentation
+----------------------------
+
+Sphinx caches significant amounts of work at the end of a documentation
+build. However, if you are in the process of editing the documentation,
+it may not correctly invalidate the cache. You can purge the entire
+cache with
+
+ ```bash
+ $ make -C doc/OnlineDocs clean
```
+
+Combining steps
+---------------
+
+These steps can, of course, be combined into a single command:
+
+ ```bash
+ $ make -c doc/OnlineDocs clean html doctest
+ ```
+
+Documentation history
+---------------------
+
+The Pyomo online documentation went through a significant overhaul in
+2024. If you need to go back and look at the old documentation, the
+following git hashes might be relevant:
+
+ - [23fb726ce](https://github.com/Pyomo/pyomo/commit/23fb726ce0e092412081bd70e8a0370af46f6d0f):
+ main (close to just) before the reorg was merged
+
+ - [c157587fc](https://github.com/Pyomo/pyomo/commit/c157587fc9a03300b53879b99c1f350a26a9519f):
+ reorg branch just before the `Archive` subdirectory was removed
diff --git a/doc/OnlineDocs/_static/theme_overrides.css b/doc/OnlineDocs/_static/theme_overrides.css
index 43d48693e03..936b3f95b13 100644
--- a/doc/OnlineDocs/_static/theme_overrides.css
+++ b/doc/OnlineDocs/_static/theme_overrides.css
@@ -31,6 +31,27 @@ dl.py.method dt em span.n {
}
}
+.rst-content table.diataxis td {
+ vertical-align: top;
+}
+
+.rst-content table.diataxis li.toctree-l1 {
+ list-style-type: none;
+ font-weight: bold;
+ font-size: x-large;
+}
+
+.rst-content table.diataxis li ul li {
+ list-style-type: none;
+ font-weight: normal;
+ font-size: medium;
+}
+
+.rst-content table.diataxis li ul li ul li {
+ list-style-type: "- ";
+}
+
+
/* Remove space after tables in definition lists (e.g., for function
"Parameters" lists*/
.rst-content dl div.wy-table-responsive {
diff --git a/doc/OnlineDocs/_templates/layout.html b/doc/OnlineDocs/_templates/layout.html
new file mode 100644
index 00000000000..777a884bfe5
--- /dev/null
+++ b/doc/OnlineDocs/_templates/layout.html
@@ -0,0 +1,15 @@
+{% extends "!layout.html" %}
+{# Explicitly put RTD's ads in the sidebar. If we don't specify a
+ location, RTD puts them at the bottom of the page content in a
+ style that is easily visually confused with the documentation
+ content.
+#}
+{%- block navigation %}
+{{ super() }}
+
+
+
+{% endblock %}
diff --git a/doc/OnlineDocs/_templates/recursive-base.rst b/doc/OnlineDocs/_templates/recursive-base.rst
new file mode 100644
index 00000000000..6a4e827fbe2
--- /dev/null
+++ b/doc/OnlineDocs/_templates/recursive-base.rst
@@ -0,0 +1,13 @@
+{{ name | escape | underline}}
+
+({{ objtype }} from :py:mod:`{{ module }}`)
+
+.. testsetup:: *
+
+ # import everything from the module containing this class so that
+ # doctests for the class docstrings see the correct environment
+ from {{ module }} import *
+
+.. currentmodule:: {{ module }}
+
+.. auto{{ objtype }}:: {{ objname }}
diff --git a/doc/OnlineDocs/_templates/recursive-class.rst b/doc/OnlineDocs/_templates/recursive-class.rst
new file mode 100644
index 00000000000..0691af291aa
--- /dev/null
+++ b/doc/OnlineDocs/_templates/recursive-class.rst
@@ -0,0 +1,49 @@
+{{ name | escape | underline}}
+
+(class from :py:mod:`{{ module }}`)
+
+.. testsetup:: *
+
+ # import everything from the module containing this class so that
+ # doctests for the class docstrings see the correct environment
+ from {{ module }} import *
+
+.. currentmodule:: {{ module }}
+
+{# Note that numpy.ndarray examples fail doctest; disable documentation
+ of inherited members for classes derived from ndarray #}
+
+.. autoclass:: {{ module }}::{{ objname }}
+ :members:
+ :show-inheritance:
+ {{ '' if (module + '.' + name) in (
+ 'pyomo.contrib.pynumero.sparse.block_vector.BlockVector',
+ 'pyomo.contrib.pynumero.sparse.mpi_block_vector.MPIBlockVector',
+ 'pyomo.core.expr.ndarray.NumericNDArray',
+ ) else ':inherited-members:' }}
+
+ {% block methods %}
+ .. automethod:: __init__
+
+ {% if methods %}
+ .. rubric:: {{ _('Methods') }}
+
+ .. autosummary::
+ {% for item in methods %}
+ ~{{ name }}.{{ item }}
+ {%- endfor %}
+ {% endif %}
+ {% endblock %}
+
+ {% block attributes %}
+ {% if attributes %}
+ .. rubric:: {{ _('Attributes') }}
+
+ .. autosummary::
+ {% for item in attributes %}
+ ~{{ name }}.{{ item }}
+ {%- endfor %}
+ {% endif %}
+ {% endblock %}
+
+ .. rubric:: Member Documentation
diff --git a/doc/OnlineDocs/_templates/recursive-enum.rst b/doc/OnlineDocs/_templates/recursive-enum.rst
new file mode 100644
index 00000000000..966cb178b78
--- /dev/null
+++ b/doc/OnlineDocs/_templates/recursive-enum.rst
@@ -0,0 +1,54 @@
+{{ name | escape | underline}}
+
+(enum from :py:mod:`{{ module }}`)
+
+.. testsetup:: *
+
+ # import everything from the module containing this class so that
+ # doctests for the class docstrings see the correct environment
+ from {{ module }} import *
+
+.. currentmodule:: {{ module }}
+
+.. autoenum:: {{ module }}::{{ objname }}
+ :members:
+ :inherited-members:
+ :undoc-members:
+ :show-inheritance:
+
+ {% block enum_members %}
+ {% if enum_members %}
+ .. rubric:: {{ _('Enum Members') }}
+
+ {{ member_type }}
+
+ .. autosummary::
+ {% for item in enum_members %}
+ ~{{ name }}.{{ item }}
+ {%- endfor %}
+ {% endif %}
+ {% endblock %}
+
+ {% block methods %}
+ {% if methods %}
+ .. rubric:: {{ _('Methods') }}
+
+ .. autosummary::
+ {% for item in methods %}
+ ~{{ name }}.{{ item }}
+ {%- endfor %}
+ {% endif %}
+ {% endblock %}
+
+ {% block attributes %}
+ {% if attributes %}
+ .. rubric:: {{ _('Attributes') }}
+
+ .. autosummary::
+ {% for item in attributes %}
+ ~{{ name }}.{{ item }}
+ {%- endfor %}
+ {% endif %}
+ {% endblock %}
+
+ .. rubric:: Member Documentation
diff --git a/doc/OnlineDocs/_templates/recursive-module.rst b/doc/OnlineDocs/_templates/recursive-module.rst
new file mode 100644
index 00000000000..dc69e33731d
--- /dev/null
+++ b/doc/OnlineDocs/_templates/recursive-module.rst
@@ -0,0 +1,92 @@
+{% if fullname == 'pyomo' %}
+Library Reference
+=================
+{% else %}
+{{ name | escape | underline}}
+{% endif %}
+
+.. automodule:: {{ fullname }}
+ :undoc-members:
+
+ {% block attributes %}
+ {%- if attributes %}
+ .. rubric:: {{ _('Module Attributes') }}
+
+ .. autosummary::
+ :toctree:
+ :template: recursive-base.rst
+ {% for item in attributes %}
+ {{ item }}
+ {%- endfor %}
+ {% endif %}
+ {%- endblock %}
+
+ {% block enums %}
+ {%- if enums %}
+ .. rubric:: {{ _('Enums') }}
+
+ .. autosummary::
+ :toctree:
+ :template: recursive-enum.rst
+ {% for item in enums %}
+ {{ item }}
+ {%- endfor %}
+ {% endif %}
+ {%- endblock %}
+
+ {%- block classes %}
+ {%- if classes %}
+ .. rubric:: {{ _('Classes') }}
+
+ .. autosummary::
+ :toctree:
+ :template: recursive-class.rst
+ {% for item in classes %}
+ {{ item }}
+ {%- endfor %}
+ {% endif %}
+ {%- endblock %}
+
+ {%- block exceptions %}
+ {%- if exceptions %}
+ .. rubric:: {{ _('Exceptions') }}
+
+ .. autosummary::
+ :toctree:
+ :template: recursive-class.rst
+ {% for item in exceptions %}
+ {{ item }}
+ {%- endfor %}
+ {% endif %}
+ {%- endblock %}
+
+ {%- block functions %}
+ {%- if functions %}
+ .. rubric:: {{ _('Functions') }}
+
+ .. autosummary::
+ :toctree:
+ :template: recursive-base.rst
+ {% for item in functions %}
+ {{ item }}
+ {%- endfor %}
+ {% endif %}
+ {%- endblock %}
+
+{%- block modules %}
+{%- if modules %}
+.. rubric:: Modules
+
+.. autosummary::
+ :toctree:
+ :template: recursive-module.rst
+ :recursive:
+{% for item in modules %}
+{# Need item != tests for Sphinx >= 8.0; !endswith(.tests) for < 8.0 #}
+{% if item != 'tests' and not item.endswith('.tests')
+ and item != 'examples' and not item.endswith('.examples') %}
+ {{ item }}
+{% endif %}
+{%- endfor %}
+{% endif %}
+{%- endblock %}
diff --git a/doc/OnlineDocs/advanced_topics/index.rst b/doc/OnlineDocs/advanced_topics/index.rst
deleted file mode 100644
index d5293bfa40c..00000000000
--- a/doc/OnlineDocs/advanced_topics/index.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-Advanced Topics
-===============
-
-.. toctree::
- :maxdepth: 1
-
- persistent_solvers.rst
- units_container.rst
- linearexpression.rst
- flattener/index.rst
- sos_constraints.rst
diff --git a/doc/OnlineDocs/advanced_topics/linearexpression.rst b/doc/OnlineDocs/advanced_topics/linearexpression.rst
deleted file mode 100644
index 8b43c3fa03a..00000000000
--- a/doc/OnlineDocs/advanced_topics/linearexpression.rst
+++ /dev/null
@@ -1,44 +0,0 @@
-LinearExpression
-================
-
-Significant speed
-improvements can sometimes be obtained using the ``LinearExpression`` object
-when there are long, dense, linear expressions. The arguments are
-
-::
-
- constant, linear_coeffs, linear_vars
-
-where the second and third arguments are lists that must be of the
-same length. Here is a simple example that illustrates the
-syntax. This example creates two constraints that are the same; in this
-particular case the LinearExpression component would offer very little improvement
-because Pyomo would be able to detect that `campe2` is a linear expression:
-
-.. doctest::
-
- >>> import pyomo.environ as pyo
- >>> from pyomo.core.expr.numeric_expr import LinearExpression
- >>> model = pyo.ConcreteModel()
- >>> model.nVars = pyo.Param(initialize=4)
- >>> model.N = pyo.RangeSet(model.nVars)
- >>> model.x = pyo.Var(model.N, within=pyo.Binary)
- >>>
- >>> model.coefs = [1, 1, 3, 4]
- >>>
- >>> model.linexp = LinearExpression(constant=0,
- ... linear_coefs=model.coefs,
- ... linear_vars=[model.x[i] for i in model.N])
- >>> def caprule(m):
- ... return m.linexp <= 6
- >>> model.capme = pyo.Constraint(rule=caprule)
- >>>
- >>> def caprule2(m):
- ... return sum(model.coefs[i-1]*model.x[i] for i in model.N) <= 6
- >>> model.capme2 = pyo.Constraint(rule=caprule2)
-
-
-.. warning::
-
- The lists that are passed to ``LinearExpression`` are not copied, so caution must
- be exercised if they are modified after the component is constructed.
diff --git a/doc/OnlineDocs/advanced_topics/units_container.rst b/doc/OnlineDocs/advanced_topics/units_container.rst
deleted file mode 100644
index f09a3361b6b..00000000000
--- a/doc/OnlineDocs/advanced_topics/units_container.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Units Handling in Pyomo
-=======================
-
-.. automodule:: pyomo.core.base.units_container
-
-.. autoclass:: PyomoUnitsContainer
- :show-inheritance:
- :members:
-
-.. autoclass:: UnitsError
-
-.. autoclass:: InconsistentUnitsError
-
diff --git a/doc/OnlineDocs/bibliography.rst b/doc/OnlineDocs/bibliography.rst
deleted file mode 100644
index 6cbb96d3bfb..00000000000
--- a/doc/OnlineDocs/bibliography.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-Bibliography
-============
-
-.. [AMPL] R. Fourer, D. M. Gay, and B. W. Kernighan. AMPL: A Modeling
- Language for Mathematical Programming, 2nd Edition. Duxbury
- Press, 2002.
-
-.. [AIMMS] http://www.aimms.com/
-
-.. [GAMS] http://www.gams.com
-
-.. [Isenberg_et_al] Isenberg, NM, Akula, P, Eslick, JC, Bhattacharyya, D,
- Miller, DC, Gounaris, CE. A generalized cutting‐set approach for
- nonlinear robust optimization in process systems
- engineering. AIChE J. 2021; 67:e17175. DOI `10.1002/aic.17175
-
`_
-
-.. [mpisppy] Bernard Knueven, David Mildebrath, Christopher Muir,
- John D Siirola, Jean-Paul Watson, and David L Woodruff, A Parallel
- Hub-and-Spoke System for Large-Scale Scenario-Based Optimization
- Under Uncertainty, pre-print, 2020
-
-.. [ParmestPaper] Katherine A. Klise, Bethany L. Nicholson, Andrea
- Staid, David L.Woodruff. Parmest: Parameter Estimation Via Pyomo.
- Computer Aided Chemical Engineering, 47 (2019): 41-46.
-
-.. [PyomoBookI] William E. Hart, Carl D. Laird, Jean-Paul Watson,
- David L. Woodruff. Pyomo – Optimization Modeling in
- Python, Springer, 2012.
-
-.. [PyomoBookII] W. E. Hart, C. D. Laird,
- J.-P. Watson, D. L. Woodruff, G. A. Hackebeil, B. L. Nicholson,
- J. D. Siirola. Pyomo - Optimization Modeling in Python,
- 2nd Edition. Springer Optimization and Its
- Applications, Vol 67. Springer, 2017.
-
-.. [PyomoBookIII] Bynum, Michael L., Gabriel A. Hackebeil,
- William E. Hart, Carl D. Laird, Bethany L. Nicholson,
- John D. Siirola, Jean-Paul Watson, and David L. Woodruff.
- Pyomo - Optimization Modeling in Python, 3rd Edition.
- Vol. 67. Springer, 2021.
-
-.. [PyomoJournal] William E. Hart, Jean-Paul Watson, David L. Woodruff.
- "Pyomo: modeling and solving mathematical programs in
- Python," Mathematical Programming Computation, Volume
- 3, Number 3, August 2011
-
-.. [PyomoDAE] Bethany Nicholson, John D. Siirola, Jean-Paul Watson,
- Victor M. Zavala, and Lorenz T. Biegler. "pyomo.dae: a
- modeling and automatic discretization framework for
- optimization with differential and algebraic equations."
- Mathematical Programming Computation 10(2) (2018):
- 187-223.
-
-.. [RooneyBiegler] W.C. Rooney, L.T. Biegler, "Design for model parameter
- uncertainty using nonlinear confidence regions", AIChE
- Journal, 47(8), 2001
-
-.. [SemiBatch] O. Abel, W. Marquardt, "Scenario-integrated modeling and
- optimization of dynamic systems", AIChE Journal, 46(4), 2000
-
-.. [Vielma_et_al] J. P. Vielma, S. Ahmed, G. Nemhauser. "Mixed-Integer
- Models for Non-separable Piecewise Linear
- Optimization: Unifying framework and Extensions",
- Operations Research 58, 2010. pp. 303-315.
-
diff --git a/doc/OnlineDocs/citing_pyomo.rst b/doc/OnlineDocs/citing_pyomo.rst
deleted file mode 100644
index 458a1fe6ab7..00000000000
--- a/doc/OnlineDocs/citing_pyomo.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-Citing Pyomo
-============
-
-Pyomo
------
-
-Bynum, Michael L., Gabriel A. Hackebeil, William E. Hart, Carl D. Laird, Bethany L. Nicholson, John D. Siirola, Jean-Paul Watson, and David L. Woodruff. Pyomo - Optimization Modeling in Python, 3rd Edition. Springer, 2021.
-
-Hart, William E., Jean-Paul Watson, and David L. Woodruff. "Pyomo: modeling and solving mathematical programs in Python." Mathematical Programming Computation 3, no. 3 (2011): 219-260.
-
-
-PySP
-----
-
-Watson, Jean-Paul, David L. Woodruff, and William E. Hart. "PySP: modeling and solving stochastic programs in Python." Mathematical Programming Computation 4, no. 2 (2012): 109-149.
-
diff --git a/doc/OnlineDocs/code.rst b/doc/OnlineDocs/code.rst
new file mode 100644
index 00000000000..e03e2cfb4d9
--- /dev/null
+++ b/doc/OnlineDocs/code.rst
@@ -0,0 +1,16 @@
+:orphan:
+
+This document is a reference containing all Pyomo module, class, and
+function documentation.
+
+.. autosummary::
+ :toctree: api
+ :caption: Library Reference
+ :template: recursive-module.rst
+ :recursive:
+
+ pyomo
+
+
+* :ref:`genindex`
+* :ref:`modindex`
diff --git a/doc/OnlineDocs/conf.py b/doc/OnlineDocs/conf.py
index 04fe458407b..d4deca77508 100644
--- a/doc/OnlineDocs/conf.py
+++ b/doc/OnlineDocs/conf.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -35,6 +35,8 @@
sys.path.insert(0, os.path.abspath('../../../pyutilib'))
# top-level pyomo source directory
sys.path.insert(0, os.path.abspath('../..'))
+# our sphinx extensions
+sys.path.insert(0, os.path.abspath('ext'))
# -- Rebuild SPY files ----------------------------------------------------
sys.path.insert(0, os.path.abspath('src'))
@@ -44,7 +46,7 @@
generate_spy_files(os.path.abspath('src'))
generate_spy_files(
- os.path.abspath(os.path.join('library_reference', 'kernel', 'examples'))
+ os.path.abspath(os.path.join('explanation', 'experimental', 'kernel'))
)
finally:
sys.path.pop(0)
@@ -58,7 +60,6 @@
'pandas': ('https://pandas.pydata.org/docs/', None),
'scikit-learn': ('https://scikit-learn.org/stable/', None),
'scipy': ('https://docs.scipy.org/doc/scipy/', None),
- 'Sphinx': ('https://www.sphinx-doc.org/en/master/', None),
}
# -- General configuration ------------------------------------------------
@@ -72,19 +73,18 @@
# ones.
extensions = [
'sphinx.ext.intersphinx',
- 'sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
- 'sphinx.ext.ifconfig',
'sphinx.ext.inheritance_diagram',
- 'sphinx.ext.autosummary',
'sphinx.ext.doctest',
'sphinx.ext.todo',
'sphinx_copybutton',
- 'enum_tools.autoenum',
- #'sphinx.ext.githubpages',
+ # Our version of 'autoenum', designed to work with autosummary.
+ # This adds 'sphinx.ext.autosummary', and 'sphinx.ext.autodoc':
+ 'pyomo_autosummary_autoenum',
+ 'pyomo_tocref',
]
viewcode_follow_imported_members = True
@@ -107,8 +107,8 @@
# General information about the project.
project = u'Pyomo'
-copyright = u'2008-2023, Sandia National Laboratories'
-author = u'Pyomo Developers'
+copyright = u'2008-2025, Sandia National Laboratories'
+author = u'Pyomo Development Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -130,8 +130,22 @@
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-# This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+# These patterns also effect to html_static_path and html_extra_path
+# Notes:
+# - _build : this is the Sphinx build (output) dir
+#
+# - api/*.tests.* : this matches autosummary RST files generated for
+# test modules. Note that the _templates/recursive-modules.rst
+# should prevent these file from being generated, so this is not
+# strictly necessary, but including it makes Sphinx throw warnings if
+# the filter in the template ever "breaks"
+#
+# - **/tests/** : this matches source files in any tests directory
+# [JDS: I *believe* this is necessary, but am not 100% certain]
+#
+# - 'Thumbs.db', '.DS_Store' : these have been included from the
+# beginning. Unclear if they are still necessary
+exclude_patterns = ['_build', 'api/*.tests.*', '**/tests/**', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
@@ -167,7 +181,7 @@
# further. For a list of options available for each theme, see the
# documentation.
#
-# html_theme_options = {}
+html_theme_options = {'navigation_depth': 6, 'titles_only': True}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -195,23 +209,48 @@
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
- # 'preamble': '',
+ 'preamble': r'''
+\usepackage{enumitem}
+\setlistdepth{99}
+\DeclareUnicodeCharacter{2227}{$\wedge$}
+\DeclareUnicodeCharacter{2228}{$\vee$}
+\DeclareUnicodeCharacter{22BB}{$\veebar$}
+''',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
+ # necessary for unicode charactacters in pdf output
+ 'inputenc': '',
+ 'utf8extra': '',
+ # remove blank pages (e.g., between chapters)
+ 'classoptions': ',openany,oneside',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
-latex_documents = [(master_doc, 'pyomo.tex', 'Pyomo Documentation', 'Pyomo', 'manual')]
+latex_documents = [(master_doc, 'pyomo.tex', 'Pyomo Documentation', author, 'manual')]
+if not on_rtd:
+ latex_documents.append(
+ ('code', 'pyomo_reference.tex', 'Pyomo Code Reference', author, 'manual')
+ )
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+latex_logo = '../logos/pyomo/PyomoNewBlue.jpg'
+
+# Disable the domain indices (i.e., the module index) for LaTeX targets:
+# because we are splitting the documentation, the module index in the
+# main document would be completely broken, and having one in the
+# reference document seems redundant (JDS: and I haven't figured out how
+# to have it in only one of the documents)
+latex_domain_indices = False
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
-man_pages = [(master_doc, 'pyomo', 'Pyomo Documentation', [author], 1)]
+man_pages = []
# -- Options for Texinfo output -------------------------------------------
@@ -219,20 +258,13 @@
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
-texinfo_documents = [
- (
- master_doc,
- 'pyomo',
- 'Pyomo Documentation',
- author,
- 'Pyomo',
- 'One line description of project.',
- 'Miscellaneous',
- )
-]
+texinfo_documents = []
# autodoc_member_order = 'bysource'
-# autodoc_member_order = 'groupwise'
+autodoc_member_order = 'groupwise'
+
+autosummary_generate = True
+autosummary_ignore_module_all = True
# -- Check which conditional dependencies are available ------------------
# Used for skipping certain doctests
@@ -266,20 +298,32 @@ def check_output(self, want, got, optionflags):
platform.python_implementation()
)
+# Mark that we are testing code (in this case, testing the documentation)
+from pyomo.common.flags import in_testing_environment
+in_testing_environment(True)
+
+# We need multiprocessing because some doctests must be skipped if the
+# start method is not "fork"
+import multiprocessing
+
+# (register plugins, make environ available to tests)
+import pyomo.environ as pyo
+
from pyomo.common.dependencies import (
attempt_import, numpy_available, scipy_available, pandas_available,
yaml_available, networkx_available, matplotlib_available,
- pympler_available, dill_available,
+ pympler_available, dill_available, pint_available,
+ numpy as np,
)
-pint_available = attempt_import('pint', defer_check=False)[1]
from pyomo.contrib.parmest.parmest import parmest_available
-import pyomo.environ as _pe # (trigger all plugin registrations)
-import pyomo.opt as _opt
+# Ensure that the matplotlib import has been resolved (and the backend changed)
+bool(matplotlib_available)
# Not using SolverFactory to check solver availability because
# as of June 2020 there is no way to suppress warnings when
# solvers are not available
+import pyomo.opt as _opt
ipopt_available = bool(_opt.check_available_solvers('ipopt'))
sipopt_available = bool(_opt.check_available_solvers('ipopt_sens'))
k_aug_available = bool(_opt.check_available_solvers('k_aug'))
@@ -290,6 +334,11 @@ def check_output(self, want, got, optionflags):
baron = _opt.SolverFactory('baron')
+if numpy_available:
+ # Recent changes on GHA seem to have dropped the default precision
+ # from 8 to 4; restore the default.
+ np.set_printoptions(precision=8)
+
if numpy_available and scipy_available:
import pyomo.contrib.pynumero.asl as _asl
asl_available = _asl.AmplInterface.available()
@@ -300,4 +349,8 @@ def check_output(self, want, got, optionflags):
asl_available = False
ma27_available = False
mumps_available = False
+
+# Prevent any Pyomo logs from propagating up to the doctest logger
+import logging
+logging.getLogger('pyomo').propagate = False
'''
diff --git a/doc/OnlineDocs/contributed_packages/iis.rst b/doc/OnlineDocs/contributed_packages/iis.rst
deleted file mode 100644
index 98cb9e30771..00000000000
--- a/doc/OnlineDocs/contributed_packages/iis.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Infeasible Irreducible System (IIS) Tool
-========================================
-
-.. automodule:: pyomo.contrib.iis.iis
-
-.. autofunction:: pyomo.contrib.iis.write_iis
diff --git a/doc/OnlineDocs/contributed_packages/mpc/data.rst b/doc/OnlineDocs/contributed_packages/mpc/data.rst
deleted file mode 100644
index 73cb6543b1e..00000000000
--- a/doc/OnlineDocs/contributed_packages/mpc/data.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-Data Structures
-===============
-
-.. automodule:: pyomo.contrib.mpc.data.get_cuid
- :members:
-
-.. automodule:: pyomo.contrib.mpc.data.dynamic_data_base
- :members:
-
-.. automodule:: pyomo.contrib.mpc.data.scalar_data
- :members:
-
-.. automodule:: pyomo.contrib.mpc.data.series_data
- :members:
-
-.. automodule:: pyomo.contrib.mpc.data.interval_data
- :members:
diff --git a/doc/OnlineDocs/contributed_packages/parmest/datarec.rst b/doc/OnlineDocs/contributed_packages/parmest/datarec.rst
deleted file mode 100644
index 6b721377e46..00000000000
--- a/doc/OnlineDocs/contributed_packages/parmest/datarec.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-.. _datarecsection:
-
-Data Reconciliation
-====================
-
-The method :class:`~pyomo.contrib.parmest.parmest.Estimator.theta_est`
-can optionally return model values. This feature can be used to return
-reconciled data using a user specified objective. In this case, the list
-of variable names the user wants to estimate (theta_names) is set to an
-empty list and the objective function is defined to minimize
-measurement to model error. Note that the model used for data
-reconciliation may differ from the model used for parameter estimation.
-
-The following example illustrates the use of parmest for data
-reconciliation. The functions
-:class:`~pyomo.contrib.parmest.graphics.grouped_boxplot` or
-:class:`~pyomo.contrib.parmest.graphics.grouped_violinplot` can be used
-to visually compare the original and reconciled data.
-
-Here's a stylized code snippet showing how box plots might be created:
-
-.. doctest::
- :skipif: True
-
- >>> import pyomo.contrib.parmest.parmest as parmest
- >>> pest = parmest.Estimator(model_function, data, [], objective_function)
- >>> obj, theta, data_rec = pest.theta_est(return_values=['A', 'B'])
- >>> parmest.graphics.grouped_boxplot(data, data_rec)
-
-Returned Values
-^^^^^^^^^^^^^^^
-
-Here's a full program that can be run to see returned values (in this case it
-is the response function that is defined in the model file):
-
-.. doctest::
- :skipif: not ipopt_available or not parmest_available
-
- >>> import pandas as pd
- >>> import pyomo.contrib.parmest.parmest as parmest
- >>> from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import rooney_biegler_model
-
- >>> theta_names = ['asymptote', 'rate_constant']
-
- >>> data = pd.DataFrame(data=[[1,8.3],[2,10.3],[3,19.0],
- ... [4,16.0],[5,15.6],[7,19.8]],
- ... columns=['hour', 'y'])
-
- >>> def SSE(model, data):
- ... expr = sum((data.y[i]\
- ... - model.response_function[data.hour[i]])**2 for i in data.index)
- ... return expr
-
- >>> pest = parmest.Estimator(rooney_biegler_model, data, theta_names, SSE,
- ... solver_options=None)
- >>> obj, theta, var_values = pest.theta_est(return_values=['response_function'])
- >>> #print(var_values)
-
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/api.rst b/doc/OnlineDocs/contributed_packages/pynumero/api.rst
deleted file mode 100644
index 3d1ac8a189e..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/api.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-.. _pynumero_api:
-
-PyNumero API
-============
-
-.. automodule:: pyomo.contrib.pynumero
- :members:
- :undoc-members:
-
-.. toctree::
-
- pynumero.sparse
- pynumero.interfaces
- pynumero.linalg
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.ampl_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.ampl_nlp.rst
deleted file mode 100644
index 37dd5852351..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.ampl_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-AMPL NLP Interface
-==================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.ampl_nlp.AmplNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.asl_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.asl_nlp.rst
deleted file mode 100644
index 2537bd52fdb..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.asl_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-ASL NLP Interface
-=================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.ampl_nlp.AslNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.extended_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.extended_nlp.rst
deleted file mode 100644
index 75528ac4b45..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.extended_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Extended NLP Interface
-======================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.nlp.ExtendedNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.external_grey_box_model.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.external_grey_box_model.rst
deleted file mode 100644
index 10187b4156e..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.external_grey_box_model.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-External Grey Box Model
-=======================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.external_grey_box.ExternalGreyBoxModel
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.nlp.rst
deleted file mode 100644
index d8532873c22..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-NLP Interface
-=============
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.nlp.NLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.projected_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.projected_nlp.rst
deleted file mode 100644
index b9c6941bd93..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.projected_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Projected NLP Interface
-=======================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.nlp_projections.ProjectedNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_grey_box_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_grey_box_nlp.rst
deleted file mode 100644
index c7200038f5e..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_grey_box_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Pyomo Grey Box NLP Interface
-============================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.pyomo_nlp.PyomoGreyBoxNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_nlp.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_nlp.rst
deleted file mode 100644
index e52ce33c2d9..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.pyomo_nlp.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Pyomo NLP Interface
-===================
-
-.. autoclass:: pyomo.contrib.pynumero.interfaces.pyomo_nlp.PyomoNLP
- :members:
- :undoc-members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.rst
deleted file mode 100644
index ec0b94960f6..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.interfaces.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-PyNumero NLP Interfaces
-=======================
-
-.. automodule:: pyomo.contrib.pynumero.interfaces
- :members:
-
-.. toctree::
-
- pynumero.interfaces.nlp
- pynumero.interfaces.extended_nlp
- pynumero.interfaces.asl_nlp
- pynumero.interfaces.ampl_nlp
- pynumero.interfaces.pyomo_nlp
- pynumero.interfaces.projected_nlp
- pynumero.interfaces.external_grey_box_model
- pynumero.interfaces.pyomo_grey_box_nlp
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.base.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.base.rst
deleted file mode 100644
index 0a94f87c6be..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.base.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-Linear Solver Base Classes
-==========================
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.base.LinearSolverStatus
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.base.LinearSolverResults
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.base.LinearSolverInterface
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.base.DirectLinearSolverInterface
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma27.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma27.rst
deleted file mode 100644
index f1d2eed3ed0..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma27.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-HSL MA27
-========
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.ma27_interface.MA27
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma57.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma57.rst
deleted file mode 100644
index c97f193b5f8..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.ma57.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-HSL MA57
-========
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.ma57_interface.MA57
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.mumps.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.mumps.rst
deleted file mode 100644
index 1fd5998dd4d..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.mumps.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-MUMPS
-=====
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.mumps_interface.MumpsCentralizedAssembledLinearSolver
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.rst
deleted file mode 100644
index 70b091becbd..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-PyNumero Linear Solver Interfaces
-=================================
-
-.. automodule:: pyomo.contrib.pynumero.linalg
- :members:
-
-.. toctree::
-
- pynumero.linalg.base
- pynumero.linalg.ma27
- pynumero.linalg.ma57
- pynumero.linalg.mumps
- pynumero.linalg.scipy
-
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.scipy.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.scipy.rst
deleted file mode 100644
index 7e0a1d0b865..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.linalg.scipy.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-Scipy
-=====
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.scipy_interface.ScipyLU
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
-
-.. autoclass:: pyomo.contrib.pynumero.linalg.scipy_interface.ScipyIterative
- :members:
- :inherited-members:
- :show-inheritance:
- :undoc-members:
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.block_vector.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.block_vector.rst
deleted file mode 100644
index 6e1dc1f20e5..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.block_vector.rst
+++ /dev/null
@@ -1,154 +0,0 @@
-BlockVector
-===========
-
-Methods specific to :py:class:`pyomo.contrib.pynumero.sparse.block_vector.BlockVector`:
-
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.set_block`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.get_block`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.block_sizes`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.get_block_size`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.is_block_defined`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copyfrom`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copyto`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copy_structure`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.set_blocks`
- * :py:meth:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.pprint`
-
-Attributes specific to :py:class:`pyomo.contrib.pynumero.sparse.block_vector.BlockVector`:
-
- * :py:attr:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.nblocks`
- * :py:attr:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.bshape`
- * :py:attr:`~pyomo.contrib.pynumero.sparse.block_vector.BlockVector.has_none`
-
-
-NumPy compatible methods:
-
- * `numpy.ndarray.dot() `_
- * `numpy.ndarray.sum() `_
- * `numpy.ndarray.all() `_
- * `numpy.ndarray.any() `_
- * `numpy.ndarray.max() `_
- * `numpy.ndarray.astype() `_
- * `numpy.ndarray.clip() `_
- * `numpy.ndarray.compress() `_
- * `numpy.ndarray.conj() `_
- * `numpy.ndarray.conjugate() `_
- * `numpy.ndarray.nonzero() `_
- * `numpy.ndarray.ptp() `_
- * `numpy.ndarray.round() `_
- * `numpy.ndarray.std() `_
- * `numpy.ndarray.var() `_
- * `numpy.ndarray.tofile() `_
- * `numpy.ndarray.min() `_
- * `numpy.ndarray.mean() `_
- * `numpy.ndarray.prod() `_
- * `numpy.ndarray.fill() `_
- * `numpy.ndarray.tolist() `_
- * `numpy.ndarray.flatten() `_
- * `numpy.ndarray.ravel() `_
- * `numpy.ndarray.argmax() `_
- * `numpy.ndarray.argmin() `_
- * `numpy.ndarray.cumprod() `_
- * `numpy.ndarray.cumsum() `_
- * `numpy.ndarray.copy() `_
-
-For example,
-
-.. code-block:: python
-
- >>> import numpy as np
- >>> from pyomo.contrib.pynumero.sparse import BlockVector
- >>> v = BlockVector(2)
- >>> v.set_block(0, np.random.normal(size=100))
- >>> v.set_block(1, np.random.normal(size=30))
- >>> avg = v.mean()
-
-NumPy compatible functions:
-
- * `numpy.log10() `_
- * `numpy.sin() `_
- * `numpy.cos() `_
- * `numpy.exp() `_
- * `numpy.ceil() `_
- * `numpy.floor() `_
- * `numpy.tan() `_
- * `numpy.arctan() `_
- * `numpy.arcsin() `_
- * `numpy.arccos() `_
- * `numpy.sinh() `_
- * `numpy.cosh() `_
- * `numpy.abs() `_
- * `numpy.tanh() `_
- * `numpy.arccosh() `_
- * `numpy.arcsinh() `_
- * `numpy.arctanh() `_
- * `numpy.fabs() `_
- * `numpy.sqrt() `_
- * `numpy.log() `_
- * `numpy.log2() `_
- * `numpy.absolute() `_
- * `numpy.isfinite() `_
- * `numpy.isinf() `_
- * `numpy.isnan() `_
- * `numpy.log1p() `_
- * `numpy.logical_not() `_
- * `numpy.expm1() `_
- * `numpy.exp2() `_
- * `numpy.sign() `_
- * `numpy.rint() `_
- * `numpy.square() `_
- * `numpy.positive() `_
- * `numpy.negative() `_
- * `numpy.rad2deg() `_
- * `numpy.deg2rad() `_
- * `numpy.conjugate() `_
- * `numpy.reciprocal() `_
- * `numpy.signbit() `_
- * `numpy.add() `_
- * `numpy.multiply() `_
- * `numpy.divide() `_
- * `numpy.subtract() `_
- * `numpy.greater() `_
- * `numpy.greater_equal() `_
- * `numpy.less() `_
- * `numpy.less_equal() `_
- * `numpy.not_equal() `_
- * `numpy.maximum() `_
- * `numpy.minimum() `_
- * `numpy.fmax() `_
- * `numpy.fmin() `_
- * `numpy.equal() `_
- * `numpy.logical_and() `_
- * `numpy.logical_or() `_
- * `numpy.logical_xor() `_
- * `numpy.logaddexp() `_
- * `numpy.logaddexp2() `_
- * `numpy.remainder() `_
- * `numpy.heaviside() `_
- * `numpy.hypot() `_
-
-For example,
-
-.. code-block:: python
-
- >>> import numpy as np
- >>> from pyomo.contrib.pynumero.sparse import BlockVector
- >>> v = BlockVector(2)
- >>> v.set_block(0, np.random.normal(size=100))
- >>> v.set_block(1, np.random.normal(size=30))
- >>> inf_norm = np.max(np.abs(v))
-
-.. autoclass:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.set_block
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.get_block
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.block_sizes
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.get_block_size
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.is_block_defined
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copyfrom
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copyto
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.copy_structure
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.set_blocks
-.. automethod:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.pprint
-.. autoproperty:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.nblocks
-.. autoproperty:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.bshape
-.. autoproperty:: pyomo.contrib.pynumero.sparse.block_vector.BlockVector.has_none
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.rst b/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.rst
deleted file mode 100644
index 6d903abb5a4..00000000000
--- a/doc/OnlineDocs/contributed_packages/pynumero/pynumero.sparse.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-PyNumero Block Linear Algebra
-=============================
-
-.. automodule:: pyomo.contrib.pynumero.sparse
- :members:
-
-.. toctree::
-
- pynumero.sparse.block_vector
diff --git a/doc/OnlineDocs/contribution_guide.rst b/doc/OnlineDocs/contribution_guide.rst
index 10670627546..ba7a569d6bd 100644
--- a/doc/OnlineDocs/contribution_guide.rst
+++ b/doc/OnlineDocs/contribution_guide.rst
@@ -71,6 +71,10 @@ at least 70% coverage of the lines modified in the PR and prefer coverage
closer to 90%. We also require that all tests pass before a PR will be
merged.
+.. note::
+ If you are having issues getting tests to pass on your Pull Request,
+ please tag any of the core developers to ask for help.
+
The Pyomo main branch provides a Github Actions workflow (configured
in the ``.github/`` directory) that will test any changes pushed to
a branch with a subset of the complete test harness that includes
@@ -82,13 +86,16 @@ This will enable the tests to run automatically with each push to your fork.
At any point in the development cycle, a "work in progress" pull request
may be opened by including '[WIP]' at the beginning of the PR
-title. This allows your code changes to be tested by the full suite of
-Pyomo's automatic
-testing infrastructure. Any pull requests marked '[WIP]' will not be
+title. Any pull requests marked '[WIP]' or draft will not be
reviewed or merged by the core development team. However, any
'[WIP]' pull request left open for an extended period of time without
active development may be marked 'stale' and closed.
+.. note::
+ Draft and WIP Pull Requests will **NOT** trigger tests. This is an effort to
+ reduce our CI backlog. Please make use of the provided
+ branch test suite for evaluating / testing draft functionality.
+
Python Version Support
++++++++++++++++++++++
@@ -397,56 +404,16 @@ Contrib packages will be tested along with Pyomo. If test failures
arise, then these packages will be disabled and an issue will be
created to resolve these test failures.
-The following two examples illustrate the two ways
-that ``pyomo.contrib`` can be used to integrate third-party
-contributions.
-
-Including External Packages
-+++++++++++++++++++++++++++
-
-The `pyomocontrib_simplemodel
-`_ package
-is derived from Pyomo, and it defines the class SimpleModel that
-illustrates how Pyomo can be used in a simple, less object-oriented
-manner. Specifically, this class mimics the modeling style supported
-by `PuLP `_.
-
-While ``pyomocontrib_simplemodel`` can be installed and used separate
-from Pyomo, this package is included in ``pyomo/contrib/simplemodel``.
-This allows this package to be referenced as if were defined as a
-subpackage of ``pyomo.contrib``. For example::
-
- from pyomo.contrib.simplemodel import *
- from math import pi
-
- m = SimpleModel()
-
- r = m.var('r', bounds=(0,None))
- h = m.var('h', bounds=(0,None))
-
- m += 2*pi*r*(r + h)
- m += pi*h*r**2 == 355
-
- status = m.solve("ipopt")
-
-This example illustrates that a package can be distributed separate
-from Pyomo while appearing to be included in the ``pyomo.contrib``
-subpackage. Pyomo requires a separate directory be defined under
-``pyomo/contrib`` for each such package, and the Pyomo developer
-team will approve the inclusion of third-party packages in this
-manner.
-
-
Contrib Packages within Pyomo
+++++++++++++++++++++++++++++
-Third-party contributions can also be included directly within the
+Third-party contributions can be included directly within the
``pyomo.contrib`` package. The ``pyomo/contrib/example`` package
provides an example of how this can be done, including a directory
for plugins and package tests. For example, this package can be
imported as a subpackage of ``pyomo.contrib``::
- from pyomo.environ import *
+ import pyomo.environ as pyo
from pyomo.contrib.example import a
# Print the value of 'a' defined by this package
@@ -458,7 +425,7 @@ import this package, but if an import failure occurs, Pyomo will
silently ignore it. Otherwise, this pyomo package will be treated
like any other. Specifically:
-* Plugin classes defined in this package are loaded when `pyomo.environ` is loaded.
+* Plugin classes defined in this package are loaded when ``pyomo.environ`` is loaded.
* Tests in this package are run with other Pyomo tests.
diff --git a/doc/OnlineDocs/developer_reference/future.rst b/doc/OnlineDocs/developer_reference/future.rst
deleted file mode 100644
index 531c0fdb5c6..00000000000
--- a/doc/OnlineDocs/developer_reference/future.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-
-.. automodule:: pyomo.__future__
- :noindex:
diff --git a/doc/OnlineDocs/developer_reference/index.rst b/doc/OnlineDocs/developer_reference/index.rst
deleted file mode 100644
index 0feb33cdab9..00000000000
--- a/doc/OnlineDocs/developer_reference/index.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-Developer Reference
-===================
-
-This section provides documentation about fundamental capabilities
-in Pyomo. This documentation serves as a reference for both (1)
-Pyomo developers and (2) advanced users who are developing Python
-scripts using Pyomo.
-
-.. toctree::
- :maxdepth: 1
-
- config.rst
- deprecation.rst
- expressions/index.rst
- future.rst
- solvers.rst
diff --git a/doc/OnlineDocs/developer_reference/solvers.rst b/doc/OnlineDocs/developer_reference/solvers.rst
deleted file mode 100644
index 45945c18b12..00000000000
--- a/doc/OnlineDocs/developer_reference/solvers.rst
+++ /dev/null
@@ -1,254 +0,0 @@
-Future Solver Interface Changes
-===============================
-
-Pyomo offers interfaces into multiple solvers, both commercial and open source.
-To support better capabilities for solver interfaces, the Pyomo team is actively
-redesigning the existing interfaces to make them more maintainable and intuitive
-for use. Redesigned interfaces can be found in ``pyomo.contrib.solver``.
-
-.. currentmodule:: pyomo.contrib.solver
-
-
-New Interface Usage
--------------------
-
-The new interfaces have two modes: backwards compatible and future capability.
-The future capability mode can be accessed directly or by switching the default
-``SolverFactory`` version (see :doc:`future`). Currently, the new versions
-available are:
-
-.. list-table:: Available Redesigned Solvers
- :widths: 25 25 25
- :header-rows: 1
-
- * - Solver
- - ``SolverFactory`` (v1) Name
- - ``SolverFactory`` (v3) Name
- * - ipopt
- - ``ipopt_v2``
- - ``ipopt``
- * - Gurobi
- - ``gurobi_v2``
- - ``gurobi``
-
-Backwards Compatible Mode
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. testcode::
- :skipif: not ipopt_available
-
- import pyomo.environ as pyo
- from pyomo.contrib.solver.util import assert_optimal_termination
-
- model = pyo.ConcreteModel()
- model.x = pyo.Var(initialize=1.5)
- model.y = pyo.Var(initialize=1.5)
-
- def rosenbrock(model):
- return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
-
- model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
-
- status = pyo.SolverFactory('ipopt_v2').solve(model)
- assert_optimal_termination(status)
- model.pprint()
-
-.. testoutput::
- :skipif: not ipopt_available
- :hide:
-
- 2 Var Declarations
- ...
- 3 Declarations: x y obj
-
-Future Capability Mode
-^^^^^^^^^^^^^^^^^^^^^^
-
-There are multiple ways to utilize the future capability mode: direct import
-or changed ``SolverFactory`` version.
-
-.. testcode::
- :skipif: not ipopt_available
-
- # Direct import
- import pyomo.environ as pyo
- from pyomo.contrib.solver.util import assert_optimal_termination
- from pyomo.contrib.solver.ipopt import Ipopt
-
- model = pyo.ConcreteModel()
- model.x = pyo.Var(initialize=1.5)
- model.y = pyo.Var(initialize=1.5)
-
- def rosenbrock(model):
- return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
-
- model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
-
- opt = Ipopt()
- status = opt.solve(model)
- assert_optimal_termination(status)
- # Displays important results information; only available in future capability mode
- status.display()
- model.pprint()
-
-.. testoutput::
- :skipif: not ipopt_available
- :hide:
-
- solution_loader: ...
- ...
- 3 Declarations: x y obj
-
-Changing the ``SolverFactory`` version:
-
-.. testcode::
- :skipif: not ipopt_available
-
- # Change SolverFactory version
- import pyomo.environ as pyo
- from pyomo.contrib.solver.util import assert_optimal_termination
- from pyomo.__future__ import solver_factory_v3
-
- model = pyo.ConcreteModel()
- model.x = pyo.Var(initialize=1.5)
- model.y = pyo.Var(initialize=1.5)
-
- def rosenbrock(model):
- return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
-
- model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
-
- status = pyo.SolverFactory('ipopt').solve(model)
- assert_optimal_termination(status)
- # Displays important results information; only available in future capability mode
- status.display()
- model.pprint()
-
-.. testoutput::
- :skipif: not ipopt_available
- :hide:
-
- solution_loader: ...
- ...
- 3 Declarations: x y obj
-
-.. testcode::
- :skipif: not ipopt_available
- :hide:
-
- from pyomo.__future__ import solver_factory_v1
-
-Linear Presolve and Scaling
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The new interface will allow for direct manipulation of linear presolve and scaling
-options for certain solvers. Currently, these options are only available for
-``ipopt``.
-
-.. autoclass:: pyomo.contrib.solver.ipopt.Ipopt
- :members: solve
-
-The ``writer_config`` configuration option can be used to manipulate presolve
-and scaling options:
-
-.. testcode::
-
- from pyomo.contrib.solver.ipopt import Ipopt
- opt = Ipopt()
- opt.config.writer_config.display()
-
-.. testoutput::
-
- show_section_timing: false
- skip_trivial_constraints: true
- file_determinism: FileDeterminism.ORDERED
- symbolic_solver_labels: false
- scale_model: true
- export_nonlinear_variables: None
- row_order: None
- column_order: None
- export_defined_variables: true
- linear_presolve: true
-
-Note that, by default, both ``linear_presolve`` and ``scale_model`` are enabled.
-Users can manipulate ``linear_presolve`` and ``scale_model`` to their preferred
-states by changing their values.
-
-.. code-block:: python
-
- >>> opt.config.writer_config.linear_presolve = False
-
-
-Interface Implementation
-------------------------
-
-All new interfaces should be built upon one of two classes (currently):
-:class:`SolverBase` or
-:class:`PersistentSolverBase`.
-
-All solvers should have the following:
-
-.. autoclass:: pyomo.contrib.solver.base.SolverBase
- :members:
-
-Persistent solvers include additional members as well as other configuration options:
-
-.. autoclass:: pyomo.contrib.solver.base.PersistentSolverBase
- :show-inheritance:
- :members:
-
-Results
--------
-
-Every solver, at the end of a
-:meth:`solve` call, will
-return a :class:`Results`
-object. This object is a :py:class:`pyomo.common.config.ConfigDict`,
-which can be manipulated similar to a standard ``dict`` in Python.
-
-.. autoclass:: pyomo.contrib.solver.results.Results
- :show-inheritance:
- :members:
- :undoc-members:
-
-
-Termination Conditions
-^^^^^^^^^^^^^^^^^^^^^^
-
-Pyomo offers a standard set of termination conditions to map to solver
-returns. The intent of
-:class:`TerminationCondition`
-is to notify the user of why the solver exited. The user is expected
-to inspect the :class:`Results`
-object or any returned solver messages or logs for more information.
-
-.. autoclass:: pyomo.contrib.solver.results.TerminationCondition
- :show-inheritance:
-
-
-Solution Status
-^^^^^^^^^^^^^^^
-
-Pyomo offers a standard set of solution statuses to map to solver
-output. The intent of
-:class:`SolutionStatus`
-is to notify the user of what the solver returned at a high level. The
-user is expected to inspect the
-:class:`Results` object or any
-returned solver messages or logs for more information.
-
-.. autoclass:: pyomo.contrib.solver.results.SolutionStatus
- :show-inheritance:
-
-
-Solution
---------
-
-Solutions can be loaded back into a model using a ``SolutionLoader``. A specific
-loader should be written for each unique case. Several have already been
-implemented. For example, for ``ipopt``:
-
-.. autoclass:: pyomo.contrib.solver.ipopt.IpoptSolutionLoader
- :show-inheritance:
- :members:
- :inherited-members:
diff --git a/doc/OnlineDocs/explanation/analysis/alternative_solutions.rst b/doc/OnlineDocs/explanation/analysis/alternative_solutions.rst
new file mode 100644
index 00000000000..899db8e8757
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/alternative_solutions.rst
@@ -0,0 +1,234 @@
+###############################################
+Generating Alternative (Near-)Optimal Solutions
+###############################################
+
+Optimization solvers are generally designed to return a feasible solution
+to the user. However, there are many applications where a user needs
+more context than this result. For example,
+
+* alternative solutions can support an assessment of trade-offs between
+ competing objectives;
+
+* if the optimization formulation may be inaccurate or untrustworthy,
+ then comparisons amongst alternative solutions provide additional
+ insights into the reliability of these model predictions; or
+
+* the user may have unexpressed objectives or constraints, which only
+ are realized in later stages of model analysis.
+
+The *alternative-solutions library* provides a variety of functions that
+can be used to generate optimal or near-optimal solutions for a pyomo
+model. Conceptually, these functions are like pyomo solvers. They can
+be configured with solver names and options, and they return a list of
+solutions for the pyomo model. However, these functions are independent
+of pyomo's solver interface because they return a custom solution object.
+
+The following functions are defined in the alternative-solutions library:
+
+* ``enumerate_binary_solutions``
+
+ * Finds alternative optimal solutions for a binary problem using no-good cuts.
+
+* ``enumerate_linear_solutions``
+
+ * Finds alternative optimal solutions for a (mixed-integer) linear program.
+
+* ``enumerate_linear_solutions_soln_pool``
+
+ * Finds alternative optimal solutions for a (mixed-binary) linear
+ program using Gurobi's solution pool feature.
+
+* ``gurobi_generate_solutions``
+
+ * Finds alternative optimal solutions for discrete variables using
+ Gurobi's built-in solution pool capability.
+
+* ``obbt_analysis_bounds_and_solutions``
+
+ * Calculates the bounds on each variable by solving a series of min
+ and max optimization problems where each variable is used as the
+ objective function. This can be applied to any class of problem
+ supported by the selected solver.
+
+
+Basic Usage Example
+-------------------
+
+Many of the functions in the alternative-solutions library have similar
+options, so we simply illustrate the ``enumerate_binary_solutions``
+function. We define a simple knapsack example whose alternative
+solutions have integer objective values ranging from 0 to 90.
+
+.. doctest::
+
+ >>> import pyomo.environ as pyo
+
+ >>> values = [10, 40, 30, 50]
+ >>> weights = [5, 4, 6, 3]
+ >>> capacity = 10
+
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var(range(4), within=pyo.Binary)
+ >>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(4)), sense=pyo.maximize)
+ >>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(4)) <= capacity)
+
+We can execute the ``enumerate_binary_solutions`` function to generate a
+list of ``Solution`` objects that represent alternative optimal
+solutions:
+
+.. doctest::
+ :skipif: not glpk_available
+
+ >>> import pyomo.contrib.alternative_solutions as aos
+ >>> solns = aos.enumerate_binary_solutions(m, num_solutions=100, solver="glpk")
+ >>> assert len(solns) == 10
+
+Each ``Solution`` object contains information about the objective and
+variables, and it includes various methods to access this information.
+For example:
+
+.. doctest::
+ :skipif: not glpk_available
+
+ >>> print(solns[0])
+ {
+ "fixed_variables": [],
+ "objective": "o",
+ "objective_value": 90.0,
+ "solution": {
+ "x[0]": 0,
+ "x[1]": 1,
+ "x[2]": 0,
+ "x[3]": 1
+ }
+ }
+
+
+Gap Usage Example
+-----------------
+
+When we only want some of the solutions based off a tolerance away from
+optimal, this can be done using the ``abs_opt_gap`` parameter. This is
+shown in the following simple knapsack examples where the weights and
+values are the same.
+
+.. doctest::
+ :skipif: not glpk_available
+
+ >>> import pyomo.environ as pyo
+ >>> import pyomo.contrib.alternative_solutions as aos
+
+ >>> values = [10,9,2,1,1]
+ >>> weights = [10,9,2,1,1]
+
+ >>> K = len(values)
+ >>> capacity = 12
+
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var(range(K), within=pyo.Binary)
+ >>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(K)), sense=pyo.maximize)
+ >>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(K)) <= capacity)
+
+ >>> solns = aos.enumerate_binary_solutions(m, num_solutions=10, solver="glpk", abs_opt_gap = 0.0)
+ >>> assert(len(solns) == 4)
+
+In this example, we only get the four ``Solution`` objects that have an
+``objective_value`` of 12. Note that while we wanted only those four
+solutions with no optimality gap, using a gap of half the smallest value
+(in this case .5) will return the same solutions and avoids any machine
+precision issues.
+
+.. doctest::
+ :skipif: not glpk_available
+
+ >>> import pyomo.environ as pyo
+ >>> import pyomo.contrib.alternative_solutions as aos
+
+ >>> values = [10,9,2,1,1]
+ >>> weights = [10,9,2,1,1]
+
+ >>> K = len(values)
+ >>> capacity = 12
+
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var(range(K), within=pyo.Binary)
+ >>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(K)), sense=pyo.maximize)
+ >>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(K)) <= capacity)
+
+ >>> solns = aos.enumerate_binary_solutions(m, num_solutions=10, solver="glpk", abs_opt_gap = 0.5)
+ >>> assert(len(solns) == 4)
+ >>> for soln in sorted(solns, key=lambda s: str(s.get_variable_name_values())):
+ ... print(soln)
+ {
+ "fixed_variables": [],
+ "objective": "o",
+ "objective_value": 12.0,
+ "solution": {
+ "x[0]": 0,
+ "x[1]": 1,
+ "x[2]": 1,
+ "x[3]": 0,
+ "x[4]": 1
+ }
+ }
+ {
+ "fixed_variables": [],
+ "objective": "o",
+ "objective_value": 12.0,
+ "solution": {
+ "x[0]": 0,
+ "x[1]": 1,
+ "x[2]": 1,
+ "x[3]": 1,
+ "x[4]": 0
+ }
+ }
+ {
+ "fixed_variables": [],
+ "objective": "o",
+ "objective_value": 12.0,
+ "solution": {
+ "x[0]": 1,
+ "x[1]": 0,
+ "x[2]": 0,
+ "x[3]": 1,
+ "x[4]": 1
+ }
+ }
+ {
+ "fixed_variables": [],
+ "objective": "o",
+ "objective_value": 12.0,
+ "solution": {
+ "x[0]": 1,
+ "x[1]": 0,
+ "x[2]": 1,
+ "x[3]": 0,
+ "x[4]": 0
+ }
+ }
+
+
+Interface Documentation
+-----------------------
+
+.. currentmodule:: pyomo.contrib.alternative_solutions
+
+.. autofunction:: enumerate_binary_solutions
+ :noindex:
+
+.. autofunction:: enumerate_linear_solutions
+ :noindex:
+
+.. autofunction:: pyomo.contrib.alternative_solutions.lp_enum_solnpool.enumerate_linear_solutions_soln_pool
+ :noindex:
+
+.. autofunction:: gurobi_generate_solutions
+ :noindex:
+
+.. autofunction:: obbt_analysis_bounds_and_solutions
+ :noindex:
+
+.. autoclass:: Solution
+ :noindex:
+
diff --git a/doc/OnlineDocs/contributed_packages/communities_8pp.png b/doc/OnlineDocs/explanation/analysis/communities_8pp.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/communities_8pp.png
rename to doc/OnlineDocs/explanation/analysis/communities_8pp.png
diff --git a/doc/OnlineDocs/contributed_packages/communities_decode_1.png b/doc/OnlineDocs/explanation/analysis/communities_decode_1.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/communities_decode_1.png
rename to doc/OnlineDocs/explanation/analysis/communities_decode_1.png
diff --git a/doc/OnlineDocs/contributed_packages/community.rst b/doc/OnlineDocs/explanation/analysis/community.rst
similarity index 98%
rename from doc/OnlineDocs/contributed_packages/community.rst
rename to doc/OnlineDocs/explanation/analysis/community.rst
index b110107e604..f95e1d16261 100644
--- a/doc/OnlineDocs/contributed_packages/community.rst
+++ b/doc/OnlineDocs/explanation/analysis/community.rst
@@ -24,7 +24,7 @@ detection. Thus, this package provides the user with a lot of control over the c
function we use for this community detection is shown below:
.. autofunction:: pyomo.contrib.community_detection.detection.detect_communities
- :noindex:
+ :noindex:
As stated above, the characteristics of the NetworkX graph of the Pyomo model are very important to the
community detection. The main graph features the user can specify are the type of community map,
@@ -278,9 +278,11 @@ community_map attribute or the `repr()` function can be used:
Generate a matplotlib figure (left_figure) - a constraint graph of the community map
>>> left_figure, _ = cmo.visualize_model_graph(type_of_graph='constraint')
+ >>> left_figure.show() # doctest: +SKIP
Now, we will generate the figure on the right (a bipartite graph of the community map)
>>> right_figure, _ = cmo.visualize_model_graph(type_of_graph='bipartite')
+ >>> right_figure.show() # doctest: +SKIP
An example of the two separate graphs created for these two function calls is shown below:
.. image:: communities_decode_1.png
@@ -312,13 +314,16 @@ An example of the two separate graphs created for these two function calls is sh
Now, we follow steps similar to the example above (see above for explanations)
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='constraint', random_seed=seed)
>>> left_fig, pos = cmo.visualize_model_graph(type_of_graph='variable')
+ >>> left_fig.show() # doctest: +SKIP
As we did before, we will use the returned 'pos' to create a consistent graph layout
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='bipartite')
>>> middle_fig, _ = cmo.visualize_model_graph(type_of_graph='variable', pos=pos)
+ >>> middle_fig.show() # doctest: +SKIP
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='variable')
>>> right_fig, _ = cmo.visualize_model_graph(type_of_graph='variable', pos=pos)
+ >>> right_fig.show() # doctest: +SKIP
We can see an example for the three separate graphs created by these three function calls below:
.. image:: communities_8pp.png
@@ -383,7 +388,9 @@ We can see an example for the three separate graphs created by these three funct
Functions in this Package
-------------------------
.. automodule:: pyomo.contrib.community_detection.detection
+ :noindex:
:members:
.. automodule:: pyomo.contrib.community_detection.community_graph
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/doe/CCSI-license.txt b/doc/OnlineDocs/explanation/analysis/doe/CCSI-license.txt
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/doe/CCSI-license.txt
rename to doc/OnlineDocs/explanation/analysis/doe/CCSI-license.txt
diff --git a/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png b/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png
new file mode 100644
index 00000000000..af6b75cbbea
Binary files /dev/null and b/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png differ
diff --git a/doc/OnlineDocs/contributed_packages/doe/doe.rst b/doc/OnlineDocs/explanation/analysis/doe/doe.rst
similarity index 56%
rename from doc/OnlineDocs/contributed_packages/doe/doe.rst
rename to doc/OnlineDocs/explanation/analysis/doe/doe.rst
index 8c22ff7370d..6e77e55dfd6 100644
--- a/doc/OnlineDocs/contributed_packages/doe/doe.rst
+++ b/doc/OnlineDocs/explanation/analysis/doe/doe.rst
@@ -3,13 +3,13 @@ Pyomo.DoE
**Pyomo.DoE** (Pyomo Design of Experiments) is a Python library for model-based design of experiments using science-based models.
-Pyomo.DoE was developed by **Jialu Wang** and **Alexander W. Dowling** at the University of Notre Dame as part of the `Carbon Capture Simulation for Industry Impact (CCSI2) `_.
+Pyomo.DoE was developed by **Jialu Wang** and **Alexander W. Dowling** at the University of Notre Dame as part of the `Carbon Capture Simulation for Industry Impact (CCSI2) `_.
project, funded through the U.S. Department Of Energy Office of Fossil Energy.
If you use Pyomo.DoE, please cite:
-[Wang and Dowling, 2022] Wang, Jialu, and Alexander W. Dowling.
-"Pyomo.DOE: An open‐source package for model‐based design of experiments in Python."
+[Wang and Dowling, 2022] Wang, Jialu, and Alexander W. Dowling.
+"Pyomo.DOE: An open‐source package for model‐based design of experiments in Python."
AIChE Journal 68.12 (2022): e17813. `https://doi.org/10.1002/aic.17813`
Methodology Overview
@@ -26,7 +26,7 @@ Pyomo.DoE provides the exploratory analysis and MBDoE capabilities to the Pyomo
the allowable design spaces for design variables, and the assumed observation error model.
During exploratory analysis, Pyomo.DoE checks if the model parameters can be inferred from the postulated measurements or preliminary data.
MBDoE then recommends optimized experimental conditions for collecting more data.
-Parameter estimation packages such as `Parmest `_ can perform parameter estimation using the available data to infer values for parameters,
+Parameter estimation packages such as :ref:`Parmest ` can perform parameter estimation using the available data to infer values for parameters,
and facilitate an uncertainty analysis to approximate the parameter covariance matrix.
If the parameter uncertainties are sufficiently small, the workflow terminates and returns the final model with quantified parametric uncertainty.
If not, MBDoE recommends optimized experimental conditions to generate new data.
@@ -41,14 +41,16 @@ Below is an overview of the type of optimization models Pyomo.DoE can accommodat
The general form of a DAE problem that can be passed into Pyomo.DoE is shown below:
.. math::
- \begin{align*}
- & \dot{\mathbf{x}}(t) = \mathbf{f}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}}, \boldsymbol{\theta}) \\
- & \mathbf{g}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta})=\mathbf{0} \\
- & \mathbf{y} =\mathbf{h}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta}) \\
- & \mathbf{f}^{\mathbf{0}}\left(\dot{\mathbf{x}}\left(t_{0}\right), \mathbf{x}\left(t_{0}\right), \mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta})\right)=\mathbf{0} \\
- & \mathbf{g}^{\mathbf{0}}\left( \mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)=\mathbf{0}\\
- &\mathbf{y}^{\mathbf{0}}\left(t_{0}\right)=\mathbf{h}\left(\mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)
- \end{align*}
+ :nowrap:
+
+ \[\begin{array}{l}
+ \dot{\mathbf{x}}(t) = \mathbf{f}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}}, \boldsymbol{\theta}) \\
+ \mathbf{g}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta})=\mathbf{0} \\
+ \mathbf{y} =\mathbf{h}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta}) \\
+ \mathbf{f}^{\mathbf{0}}\left(\dot{\mathbf{x}}\left(t_{0}\right), \mathbf{x}\left(t_{0}\right), \mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta})\right)=\mathbf{0} \\
+ \mathbf{g}^{\mathbf{0}}\left( \mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)=\mathbf{0}\\
+ \mathbf{y}^{\mathbf{0}}\left(t_{0}\right)=\mathbf{h}\left(\mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)
+ \end{array}\]
where:
@@ -69,6 +71,8 @@ where:
Based on the above notation, the form of the MBDoE problem addressed in Pyomo.DoE is shown below:
.. math::
+ :nowrap:
+
\begin{equation}
\begin{aligned}
\underset{\boldsymbol{\varphi}}{\max} \quad & \Psi (\mathbf{M}(\mathbf{\hat{y}}, \boldsymbol{\varphi})) \\
@@ -116,64 +120,14 @@ In order to solve problems of the above, Pyomo.DoE implements the 2-stage stocha
Pyomo.DoE Required Inputs
--------------------------------
-The required inputs to the Pyomo.DoE solver are the following:
-
-* A function that creates the process model
-* Dictionary of parameters and their nominal value
-* A measurement object
-* A design variables object
-* A Numpy ``array`` containing the Prior FIM
-* Optimization solver
-
-Below is a list of arguments that Pyomo.DoE expects the user to provide.
-
-parameter_dict : ``dictionary``
- A ``dictionary`` of parameter names and values. If they are an indexed variable, put the variable name and index in a nested ``Dictionary``.
-
-design_variables: ``DesignVariables``
- A ``DesignVariables`` of design variables, provided by the DesignVariables class.
- If this design var is independent of time (constant), set the time to [0]
-
-measurement_variables : ``MeasurementVariables``
- A ``MeasurementVariables`` of the measurements, provided by the MeasurementVariables class.
-
-create_model : ``function``
- A ``function`` returning a deterministic process model.
-
-prior_FIM : ``array``
- An ``array`` defining the Fisher information matrix (FIM) for prior experiments, default is a zero matrix.
-
-Pyomo.DoE Solver Interface
----------------------------
+The required input to the Pyomo.DoE solver is an ``Experiment`` object. The experiment object must have a ``get_labeled_model`` function which returns a Pyomo model with four ``Suffix`` components identifying the parts of the model used in MBDoE analysis. This is in line with the convention used in the parameter estimation tool, :ref:`Parmest `. The four ``Suffix`` components are:
-.. figure:: uml.png
- :scale: 25 %
-
-
-.. autoclass:: pyomo.contrib.doe.doe.DesignOfExperiments
- :members: __init__, stochastic_program, compute_FIM, run_grid_search
-
-.. Note::
- ``stochastic_program()`` includes the following steps:
- #. Build two-stage stochastic programming optimization model where scenarios correspond to finite difference approximations for the Jacobian of the response variables with respect to calibrated model parameters
- #. Fix the experiment design decisions and solve a square (i.e., zero degrees of freedom) instance of the two-stage DOE problem. This step is for initialization.
- #. Unfix the experiment design decisions and solve the two-stage DOE problem.
-
-.. autoclass:: pyomo.contrib.doe.measurements.MeasurementVariables
- :members: __init__, add_variables
-
-.. autoclass:: pyomo.contrib.doe.measurements.DesignVariables
- :members: __init__, add_variables
-
-.. autoclass:: pyomo.contrib.doe.scenario.ScenarioGenerator
- :special-members: __init__
-
-.. autoclass:: pyomo.contrib.doe.result.FisherResults
- :members: __init__, result_analysis
-
-.. autoclass:: pyomo.contrib.doe.result.GridSearchResult
- :special-members: __init__
+* ``experiment_inputs`` - The experimental design decisions
+* ``experiment_outputs`` - The values measured during the experiment
+* ``measurement_error`` - The error associated with individual values measured during the experiment
+* ``unknown_parameters`` - Those parameters in the model that are estimated using the measured values during the experiment
+An example ``Experiment`` object that builds and labels the model is shown in the next few sections.
Pyomo.DoE Usage Example
-----------------------
@@ -183,6 +137,8 @@ The Arrhenius equations model the temperature dependence of the reaction rate co
.. math::
+ :nowrap:
+
\begin{equation}
\begin{aligned}
k_1 & = A_1 e^{-\frac{E_1}{RT}} \\
@@ -203,89 +159,87 @@ The goal of MBDoE is to optimize the experiment design variables :math:`\boldsym
The observation errors are assumed to be independent both in time and across measurements with a constant standard deviation of 1 M for each species.
-Step 0: Import Pyomo and the Pyomo.DoE module
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Step 0: Import Pyomo and the Pyomo.DoE module and create an ``Experiment`` class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. doctest::
>>> # === Required import ===
>>> import pyomo.environ as pyo
- >>> from pyomo.dae import ContinuousSet, DerivativeVar
- >>> from pyomo.contrib.doe import DesignOfExperiments, MeasurementVariables, DesignVariables
+ >>> from pyomo.contrib.doe import DesignOfExperiments
>>> import numpy as np
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
+ :start-after: ========================
+ :end-before: End constructor definition
+
Step 1: Define the Pyomo process model
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-The process model for the reaction kinetics problem is shown below.
+The process model for the reaction kinetics problem is shown below. We build the model without any data or discretization.
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_kinetics.py
- :language: python
- :pyobject: create_model
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
+ :start-after: Create flexible model without data
+ :end-before: End equation definition
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_kinetics.py
- :language: python
- :pyobject: disc_for_measure
+Step 2: Finalize the Pyomo process model
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. note::
- The model requires at least two options: "block" and "global". Both options requires the pass of a created empty Pyomo model.
- With "global" option, only design variables and their time sets need to be defined;
- With "block" option, a full model needs to be defined.
+Here we add data to the model and finalize the discretization. This step is required before the model can be labeled.
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
+ :start-after: End equation definition
+ :end-before: End model finalization
-Step 2: Define the inputs for Pyomo.DoE
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_compute_FIM.py
- :language: python
- :start-at: # Control time set
- :end-before: ### Compute
+Step 3: Label the information needed for DoE analysis
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+We label the four important groups as defined before.
-Step 3: Compute the FIM of a square MBDoE problem
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
+ :start-after: End model finalization
+ :end-before: End model labeling
-This method computes an MBDoE optimization problem with no degree of freedom.
+Step 4: Implement the ``get_labeled_model`` method
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-This method can be accomplished by two modes, ``direct_kaug`` and ``sequential_finite``.
-``direct_kaug`` mode requires the installation of the solver `k_aug `_.
+This method utilizes the previous 3 steps and is used by `Pyomo.DoE` to build the model to perform optimal experimental design.
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_compute_FIM.py
- :language: python
- :start-after: ### Compute the FIM
- :end-before: # test result
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
+ :start-after: End constructor definition
+ :end-before: Create flexible model without data
-Step 4: Exploratory analysis (Enumeration)
+Step 5: Exploratory analysis (Enumeration)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Exploratory analysis is suggested to enumerate the design space to check if the problem is identifiable,
+Exploratory analysis is suggested to enumerate the design space to check if the problem is identifiable,
i.e., ensure that D-, E-optimality metrics are not small numbers near zero, and Modified E-optimality is not a big number.
-Pyomo.DoE accomplishes the exploratory analysis with the ``run_grid_search`` function.
-It allows users to define any number of design decisions. Heatmaps can be drawn by two design variables, fixing other design variables.
-1D curve can be drawn by one design variable, fixing all other variables.
-The function ``run_grid_search`` enumerates over the design space, each MBDoE problem accomplished by ``compute_FIM`` method.
-Therefore, ``run_grid_search`` supports only two modes: ``sequential_finite`` and ``direct_kaug``.
+Pyomo.DoE can perform exploratory sensitivity analysis with the ``compute_FIM_full_factorial`` function.
+The ``compute_FIM_full_factorial`` function generates a grid over the design space as specified by the user. Each grid point represents an MBDoE problem solved using ``compute_FIM`` method. In this way, sensitivity of the FIM over the design space can be evaluated.
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_grid_search.py
- :language: python
- :pyobject: main
+The following code executes the above problem description:
-Successful run of the above code shows the following figure:
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_example.py
+ :start-after: Read in file
+ :end-before: End sensitivity analysis
-.. figure:: grid-1.png
- :scale: 35 %
+An example output of the code above, a design exploration for the initial concentration and temperature as experimental design variables with 9 values, produces the four figures summarized below:
-A heatmap shows the change of the objective function, a.k.a. the experimental information content, in the design region. Horizontal and vertical axes are two design variables, while the color of each grid shows the experimental information content. Taking the Fig. Reactor case - A optimality as example, A-optimality shows that the most informative region is around $C_{A0}=5.0$ M, $T=300.0$ K, while the least informative region is around $C_{A0}=1.0$ M, $T=700.0$ K.
+.. figure:: FIM_sensitivity.png
+ :scale: 50 %
-Step 5: Gradient-based optimization
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+A heatmap shows the change of the objective function, a.k.a. the experimental information content, in the design space. Horizontal and vertical axes are the two experimental design variables, while the color of each grid shows the experimental information content. For A optimality (top left subfigure), the figure shows that the most informative region is around :math:`C_{A0}=5.0` M, :math:`T=300.0` K, while the least informative region is around :math:`C_{A0}=1.0` M, :math:`T=700.0` K.
+
+Step 6: Performing an optimal experimental design
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Pyomo.DoE accomplishes gradient-based optimization with the ``stochastic_program`` function for A- and D-optimality design.
+In step 5, the DoE object was constructed to perform an exploratory sensitivity analysis. The same object can be used to design an optimal experiment with a single line of code.
-This function solves twice: It solves the square version of the MBDoE problem first, and then unfixes the design variables as degree of freedoms and solves again. In this way the optimization problem can be well initialized.
+.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_example.py
+ :start-after: Begin optimal DoE
+ :end-before: Print out a results summary
-.. literalinclude:: ../../../../pyomo/contrib/doe/examples/reactor_optimize_doe.py
- :language: python
- :pyobject: main
+When run, the optimal design is an initial concentration of 5.0 mol/L and an initial temperature of 494 K with all other temperatures being 300 K. The corresponding log-10 determinant of the FIM is 13.75
diff --git a/doc/OnlineDocs/contributed_packages/doe/flowchart.png b/doc/OnlineDocs/explanation/analysis/doe/flowchart.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/doe/flowchart.png
rename to doc/OnlineDocs/explanation/analysis/doe/flowchart.png
diff --git a/doc/OnlineDocs/contributed_packages/doe/grid-1.png b/doc/OnlineDocs/explanation/analysis/doe/grid-1.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/doe/grid-1.png
rename to doc/OnlineDocs/explanation/analysis/doe/grid-1.png
diff --git a/doc/OnlineDocs/contributed_packages/doe/reactor.png b/doc/OnlineDocs/explanation/analysis/doe/reactor.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/doe/reactor.png
rename to doc/OnlineDocs/explanation/analysis/doe/reactor.png
diff --git a/doc/OnlineDocs/contributed_packages/doe/uml.png b/doc/OnlineDocs/explanation/analysis/doe/uml.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/doe/uml.png
rename to doc/OnlineDocs/explanation/analysis/doe/uml.png
diff --git a/doc/OnlineDocs/explanation/analysis/iis.rst b/doc/OnlineDocs/explanation/analysis/iis.rst
new file mode 100644
index 00000000000..773560c4e28
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/iis.rst
@@ -0,0 +1,141 @@
+Infeasibility Diagnostics
+!!!!!!!!!!!!!!!!!!!!!!!!!
+
+There are two closely related tools for infeasibility diagnosis:
+
+ - :ref:`iis`
+ - :ref:`mis`
+
+The first simply provides a conduit for solvers that compute an
+infeasible irreducible system (e.g., Cplex, Gurobi, or Xpress). The
+second provides similar functionality, but uses the ``mis`` package
+contributed to Pyomo.
+
+
+.. _iis:
+
+Infeasible Irreducible System (IIS) Tool
+========================================
+
+.. automodule:: pyomo.contrib.iis.iis
+ :noindex:
+
+.. autofunction:: pyomo.contrib.iis.write_iis
+ :noindex:
+
+.. _mis:
+
+Minimal Intractable System finder (MIS) Tool
+============================================
+
+The file ``mis.py`` finds sets of actions that each, independently,
+would result in feasibility. The zero-tolerance is whatever the
+solver uses, so users may want to post-process output if it is going
+to be used for analysis. It also computes a minimal intractable system
+(which is not guaranteed to be unique). It was written by Ben Knueven
+as part of the watertap project (https://github.com/watertap-org/watertap)
+and is therefore governed by a license shown
+at the top of ``mis.py``.
+
+The algorithms come from John Chinneck's slides, see: https://www.sce.carleton.ca/faculty/chinneck/docs/CPAIOR07InfeasibilityTutorial.pdf
+
+Solver
+------
+
+At the time of this writing, you need to use IPopt even for LPs.
+
+Quick Start
+-----------
+
+The file ``trivial_mis.py`` is a tiny example listed at the bottom of
+this help file, which references a Pyomo model with the Python variable
+`m` and has these lines:
+
+.. code-block:: python
+
+ from pyomo.contrib.mis import compute_infeasibility_explanation
+ ipopt = pyo.SolverFactory("ipopt")
+ compute_infeasibility_explanation(m, solver=ipopt)
+
+.. Note::
+ This is done instead of solving the problem.
+
+.. Note::
+ IDAES users can pass ``get_solver()`` imported from ``ideas.core.solvers``
+ as the solver.
+
+Interpreting the Output
+-----------------------
+
+Assuming the dependencies are installed, running ``trivial_mis.py``
+(shown below) will
+produce a lot of warnings from IPopt and then meaningful output (using a logger).
+
+Repair Options
+^^^^^^^^^^^^^^
+
+This output for the trivial example shows three independent ways that the model could be rendered feasible:
+
+
+.. code-block:: text
+
+ Model Trivial Quad may be infeasible. A feasible solution was found with only the following variable bounds relaxed:
+ ub of var x[1] by 4.464126126706818e-05
+ lb of var x[2] by 0.9999553410114216
+ Another feasible solution was found with only the following variable bounds relaxed:
+ lb of var x[1] by 0.7071067726864677
+ ub of var x[2] by 0.41421355687130673
+ ub of var y by 0.7071067651855212
+ Another feasible solution was found with only the following inequality constraints, equality constraints, and/or variable bounds relaxed:
+ constraint: c by 0.9999999861866736
+
+
+Minimal Intractable System (MIS)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This output shows a minimal intractable system:
+
+
+.. code-block:: text
+
+ Computed Minimal Intractable System (MIS)!
+ Constraints / bounds in MIS:
+ lb of var x[2]
+ lb of var x[1]
+ constraint: c
+
+Constraints / bounds in guards for stability
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This part of the report is for nonlinear programs (NLPs).
+
+When we’re trying to reduce the constraint set, for an NLP there may be constraints that when missing cause the solver
+to fail in some catastrophic fashion. In this implementation this is interpreted as failing to get a `results`
+object back from the call to `solve`. In these cases we keep the constraint in the problem but it’s in the
+set of “guard” constraints – we can’t really be sure they’re a source of infeasibility or not,
+just that “bad things” happen when they’re not included.
+
+Perhaps ideally we would put a constraint in the “guard” set if IPopt failed to converge, and only put it in the
+MIS if IPopt converged to a point of local infeasibility. However, right now the code generally makes the
+assumption that if IPopt fails to converge the subproblem is infeasible, though obviously that is far from the truth.
+Hence for difficult NLPs even the “Phase 1” may “fail” – in that when finished the subproblem containing just the
+constraints in the elastic filter may be feasible -- because IPopt failed to converge and we assumed that meant the
+subproblem was not feasible.
+
+Dealing with NLPs is far from clean, but that doesn’t mean the tool can’t return useful results even when its assumptions are not satisfied.
+
+trivial_mis.py
+--------------
+
+.. code-block:: python
+
+ import pyomo.environ as pyo
+ m = pyo.ConcreteModel("Trivial Quad")
+ m.x = pyo.Var([1,2], bounds=(0,1))
+ m.y = pyo.Var(bounds=(0, 1))
+ m.c = pyo.Constraint(expr=m.x[1] * m.x[2] == -1)
+ m.d = pyo.Constraint(expr=m.x[1] + m.y >= 1)
+
+ from pyomo.contrib.mis import compute_infeasibility_explanation
+ ipopt = pyo.SolverFactory("ipopt")
+ compute_infeasibility_explanation(m, solver=ipopt)
diff --git a/doc/OnlineDocs/contributed_packages/incidence/api.rst b/doc/OnlineDocs/explanation/analysis/incidence/api.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/api.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/api.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/config.rst b/doc/OnlineDocs/explanation/analysis/incidence/config.rst
similarity index 89%
rename from doc/OnlineDocs/contributed_packages/incidence/config.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/config.rst
index 06e4f5c5626..5260d3de256 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/config.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/config.rst
@@ -2,4 +2,5 @@ Incidence Options
=================
.. automodule:: pyomo.contrib.incidence_analysis.config
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/connected.rst b/doc/OnlineDocs/explanation/analysis/incidence/connected.rst
similarity index 90%
rename from doc/OnlineDocs/contributed_packages/incidence/connected.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/connected.rst
index 4cf60f62eba..301d78f8a95 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/connected.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/connected.rst
@@ -2,4 +2,5 @@ Weakly Connected Components
===========================
.. automodule:: pyomo.contrib.incidence_analysis.connected
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/dulmage_mendelsohn.rst b/doc/OnlineDocs/explanation/analysis/incidence/dulmage_mendelsohn.rst
similarity index 91%
rename from doc/OnlineDocs/contributed_packages/incidence/dulmage_mendelsohn.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/dulmage_mendelsohn.rst
index 6fe2bd59324..dfcd3ea1a33 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/dulmage_mendelsohn.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/dulmage_mendelsohn.rst
@@ -2,4 +2,5 @@ Dulmage-Mendelsohn Partition
============================
.. automodule:: pyomo.contrib.incidence_analysis.dulmage_mendelsohn
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/incidence.rst b/doc/OnlineDocs/explanation/analysis/incidence/incidence.rst
similarity index 89%
rename from doc/OnlineDocs/contributed_packages/incidence/incidence.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/incidence.rst
index ebf481c00a7..d8bbab089ba 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/incidence.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/incidence.rst
@@ -2,4 +2,5 @@ Incident Variables
==================
.. automodule:: pyomo.contrib.incidence_analysis.incidence
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/index.rst b/doc/OnlineDocs/explanation/analysis/incidence/index.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/index.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/index.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/interface.rst b/doc/OnlineDocs/explanation/analysis/incidence/interface.rst
similarity index 89%
rename from doc/OnlineDocs/contributed_packages/incidence/interface.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/interface.rst
index 29c92d8193c..1f6cd20bec3 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/interface.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/interface.rst
@@ -2,4 +2,5 @@ Pyomo Interfaces
================
.. automodule:: pyomo.contrib.incidence_analysis.interface
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/matching.rst b/doc/OnlineDocs/explanation/analysis/incidence/matching.rst
similarity index 89%
rename from doc/OnlineDocs/contributed_packages/incidence/matching.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/matching.rst
index 1941c7116cd..83aeb06a7fa 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/matching.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/matching.rst
@@ -2,4 +2,5 @@ Maximum Matching
================
.. automodule:: pyomo.contrib.incidence_analysis.matching
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/overview.rst b/doc/OnlineDocs/explanation/analysis/incidence/overview.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/overview.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/overview.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/scc_solver.rst b/doc/OnlineDocs/explanation/analysis/incidence/scc_solver.rst
similarity index 92%
rename from doc/OnlineDocs/contributed_packages/incidence/scc_solver.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/scc_solver.rst
index 35f494af1a1..5f20a96191d 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/scc_solver.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/scc_solver.rst
@@ -2,4 +2,5 @@ Block Triangular Decomposition Solver
=====================================
.. automodule:: pyomo.contrib.incidence_analysis.scc_solver
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/triangularize.rst b/doc/OnlineDocs/explanation/analysis/incidence/triangularize.rst
similarity index 90%
rename from doc/OnlineDocs/contributed_packages/incidence/triangularize.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/triangularize.rst
index a051086a859..e1e60a39677 100644
--- a/doc/OnlineDocs/contributed_packages/incidence/triangularize.rst
+++ b/doc/OnlineDocs/explanation/analysis/incidence/triangularize.rst
@@ -2,4 +2,5 @@ Block Triangularization
=======================
.. automodule:: pyomo.contrib.incidence_analysis.triangularize
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/incidence/tutorial.bt.rst b/doc/OnlineDocs/explanation/analysis/incidence/tutorial.bt.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/tutorial.bt.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/tutorial.bt.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/tutorial.btsolve.rst b/doc/OnlineDocs/explanation/analysis/incidence/tutorial.btsolve.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/tutorial.btsolve.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/tutorial.btsolve.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/tutorial.dm.rst b/doc/OnlineDocs/explanation/analysis/incidence/tutorial.dm.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/tutorial.dm.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/tutorial.dm.rst
diff --git a/doc/OnlineDocs/contributed_packages/incidence/tutorial.rst b/doc/OnlineDocs/explanation/analysis/incidence/tutorial.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/incidence/tutorial.rst
rename to doc/OnlineDocs/explanation/analysis/incidence/tutorial.rst
diff --git a/doc/OnlineDocs/explanation/analysis/index.rst b/doc/OnlineDocs/explanation/analysis/index.rst
new file mode 100644
index 00000000000..0a8e3c3b416
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/index.rst
@@ -0,0 +1,20 @@
+Analysis in Pyomo
+=================
+
+.. toctree::
+ :maxdepth: 2
+
+ alternative_solutions
+ community
+ doe/doe
+ iis
+ incidence/index
+ mpc/index
+ parmest/index
+ sensitivity_toolbox
+
+..
+ Reorganization notes:
+
+ Analysis in Pyomo
+ `FBBT`
diff --git a/doc/OnlineDocs/contributed_packages/mpc/api.rst b/doc/OnlineDocs/explanation/analysis/mpc/api.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/mpc/api.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/api.rst
diff --git a/doc/OnlineDocs/contributed_packages/mpc/conversion.rst b/doc/OnlineDocs/explanation/analysis/mpc/conversion.rst
similarity index 87%
rename from doc/OnlineDocs/contributed_packages/mpc/conversion.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/conversion.rst
index 9d9406edb75..e78a1d69e0b 100644
--- a/doc/OnlineDocs/contributed_packages/mpc/conversion.rst
+++ b/doc/OnlineDocs/explanation/analysis/mpc/conversion.rst
@@ -2,4 +2,5 @@ Data Conversion
===============
.. automodule:: pyomo.contrib.mpc.data.convert
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/explanation/analysis/mpc/data.rst b/doc/OnlineDocs/explanation/analysis/mpc/data.rst
new file mode 100644
index 00000000000..da65bf40814
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/data.rst
@@ -0,0 +1,22 @@
+Data Structures
+===============
+
+.. automodule:: pyomo.contrib.mpc.data.get_cuid
+ :members:
+ :noindex:
+
+ automodule:: pyomo.contrib.mpc.data.dynamic_data_base
+ :members:
+ :noindex:
+
+ automodule:: pyomo.contrib.mpc.data.scalar_data
+ :members:
+ :noindex:
+
+ automodule:: pyomo.contrib.mpc.data.series_data
+ :members:
+ :noindex:
+
+ automodule:: pyomo.contrib.mpc.data.interval_data
+ :members:
+ :noindex:
diff --git a/doc/OnlineDocs/contributed_packages/mpc/examples.rst b/doc/OnlineDocs/explanation/analysis/mpc/examples.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/mpc/examples.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/examples.rst
diff --git a/doc/OnlineDocs/contributed_packages/mpc/faq.rst b/doc/OnlineDocs/explanation/analysis/mpc/faq.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/mpc/faq.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/faq.rst
diff --git a/doc/OnlineDocs/contributed_packages/mpc/index.rst b/doc/OnlineDocs/explanation/analysis/mpc/index.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/mpc/index.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/index.rst
diff --git a/doc/OnlineDocs/contributed_packages/mpc/interface.rst b/doc/OnlineDocs/explanation/analysis/mpc/interface.rst
similarity index 86%
rename from doc/OnlineDocs/contributed_packages/mpc/interface.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/interface.rst
index eb5bac548fd..13a5bf24360 100644
--- a/doc/OnlineDocs/contributed_packages/mpc/interface.rst
+++ b/doc/OnlineDocs/explanation/analysis/mpc/interface.rst
@@ -2,7 +2,9 @@ Interfaces
==========
.. automodule:: pyomo.contrib.mpc.interfaces.model_interface
+ :noindex:
:members:
.. automodule:: pyomo.contrib.mpc.interfaces.var_linker
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/mpc/modeling.rst b/doc/OnlineDocs/explanation/analysis/mpc/modeling.rst
similarity index 86%
rename from doc/OnlineDocs/contributed_packages/mpc/modeling.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/modeling.rst
index cbae03161b1..2bc213f1702 100644
--- a/doc/OnlineDocs/contributed_packages/mpc/modeling.rst
+++ b/doc/OnlineDocs/explanation/analysis/mpc/modeling.rst
@@ -2,10 +2,13 @@ Modeling Components
===================
.. automodule:: pyomo.contrib.mpc.modeling.constraints
+ :noindex:
:members:
.. automodule:: pyomo.contrib.mpc.modeling.cost_expressions
+ :noindex:
:members:
.. automodule:: pyomo.contrib.mpc.modeling.terminal
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/contributed_packages/mpc/overview.rst b/doc/OnlineDocs/explanation/analysis/mpc/overview.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/mpc/overview.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/overview.rst
diff --git a/doc/OnlineDocs/contributed_packages/parmest/api.rst b/doc/OnlineDocs/explanation/analysis/parmest/api.rst
similarity index 91%
rename from doc/OnlineDocs/contributed_packages/parmest/api.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/api.rst
index 4d6896a8582..a1456361260 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/api.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/api.rst
@@ -6,6 +6,7 @@ API
parmest
---------
.. automodule:: pyomo.contrib.parmest.parmest
+ :noindex:
:members:
:undoc-members:
:show-inheritance:
@@ -13,6 +14,7 @@ parmest
scenariocreator
------------------
.. automodule:: pyomo.contrib.parmest.scenariocreator
+ :noindex:
:members:
:undoc-members:
:show-inheritance:
@@ -20,6 +22,7 @@ scenariocreator
graphics
---------
.. automodule:: pyomo.contrib.parmest.graphics
+ :noindex:
:members:
:undoc-members:
:show-inheritance:
diff --git a/doc/OnlineDocs/contributed_packages/parmest/boxplot.png b/doc/OnlineDocs/explanation/analysis/parmest/boxplot.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/boxplot.png
rename to doc/OnlineDocs/explanation/analysis/parmest/boxplot.png
diff --git a/doc/OnlineDocs/contributed_packages/parmest/covariance.rst b/doc/OnlineDocs/explanation/analysis/parmest/covariance.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/covariance.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/covariance.rst
diff --git a/doc/OnlineDocs/explanation/analysis/parmest/datarec.rst b/doc/OnlineDocs/explanation/analysis/parmest/datarec.rst
new file mode 100644
index 00000000000..3c6e12196f7
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/parmest/datarec.rst
@@ -0,0 +1,54 @@
+.. _datarecsection:
+
+Data Reconciliation
+====================
+
+The optional argument ``return_values`` in :class:`~pyomo.contrib.parmest.parmest.Estimator.theta_est`
+can be used for data reconciliation or to return model values based on the specified objective.
+
+For data reconciliation, the ``m.unknown_parameters`` is empty
+and the objective function is defined to minimize
+measurement to model error. Note that the model used for data
+reconciliation may differ from the model used for parameter estimation.
+
+The functions
+:class:`~pyomo.contrib.parmest.graphics.grouped_boxplot` or
+:class:`~pyomo.contrib.parmest.graphics.grouped_violinplot` can be used
+to visually compare the original and reconciled data.
+
+The following example from the reactor design subdirectory returns reconciled values for experiment outputs
+(`ca`, `cb`, `cc`, and `cd`) and then uses those values in
+parameter estimation (`k1`, `k2`, and `k3`).
+
+.. literalinclude:: /../../pyomo/contrib/parmest/examples/reactor_design/datarec_example.py
+ :language: python
+
+The following example returns model values from a Pyomo Expression.
+
+.. doctest::
+ :skipif: not ipopt_available or not parmest_available
+
+ >>> import pandas as pd
+ >>> import pyomo.contrib.parmest.parmest as parmest
+ >>> from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import RooneyBieglerExperiment
+
+ >>> # Generate data
+ >>> data = pd.DataFrame(data=[[1,8.3],[2,10.3],[3,19.0],
+ ... [4,16.0],[5,15.6],[7,19.8]],
+ ... columns=['hour', 'y'])
+
+ >>> # Create an experiment list
+ >>> exp_list = []
+ >>> for i in range(data.shape[0]):
+ ... exp_list.append(RooneyBieglerExperiment(data.loc[i, :]))
+
+ >>> # Define objective
+ >>> def SSE(model):
+ ... expr = (model.experiment_outputs[model.y]
+ ... - model.response_function[model.experiment_outputs[model.hour]]
+ ... ) ** 2
+ ... return expr
+
+ >>> pest = parmest.Estimator(exp_list, obj_function=SSE, solver_options=None)
+ >>> obj, theta, var_values = pest.theta_est(return_values=['response_function'])
+ >>> #print(var_values)
diff --git a/doc/OnlineDocs/contributed_packages/parmest/driver.rst b/doc/OnlineDocs/explanation/analysis/parmest/driver.rst
similarity index 53%
rename from doc/OnlineDocs/contributed_packages/parmest/driver.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/driver.rst
index 28238928b83..b3f212008ca 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/driver.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/driver.rst
@@ -4,9 +4,9 @@ Parameter Estimation
==================================
Parameter Estimation using parmest requires a Pyomo model, experimental
-data which defines multiple scenarios, and a list of parameter names
-(thetas) to estimate. parmest uses Pyomo [PyomoBookII]_ and (optionally)
-mpi-sppy [mpisppy]_ to solve a
+data which defines multiple scenarios, and parameters
+(thetas) to estimate. parmest uses Pyomo [PyomoBookIII]_ and (optionally)
+mpi-sppy [KMM+23]_ to solve a
two-stage stochastic programming problem, where the experimental data is
used to create a scenario tree. The objective function needs to be
written with the Pyomo Expression for first stage cost
@@ -36,13 +36,12 @@ which includes the following methods:
~pyomo.contrib.parmest.parmest.Estimator.likelihood_ratio_test
~pyomo.contrib.parmest.parmest.Estimator.leaveNout_bootstrap_test
-Additional functions are available in parmest to group data, plot
-results, and fit distributions to theta values.
+Additional functions are available in parmest to plot
+results and fit distributions to theta values.
.. autosummary::
:nosignatures:
- ~pyomo.contrib.parmest.parmest.group_data
~pyomo.contrib.parmest.graphics.pairwise_plot
~pyomo.contrib.parmest.graphics.grouped_boxplot
~pyomo.contrib.parmest.graphics.grouped_violinplot
@@ -58,21 +57,33 @@ Section.
.. testsetup:: *
:skipif: not __import__('pyomo.contrib.parmest.parmest').contrib.parmest.parmest.parmest_available
+ # Data
import pandas as pd
- from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import rooney_biegler_model as model_function
- data = pd.DataFrame(data=[[1,8.3],[2,10.3],[3,19.0],
- [4,16.0],[5,15.6],[6,19.8]],
- columns=['hour', 'y'])
- theta_names = ['asymptote', 'rate_constant']
- def objective_function(model, data):
- expr = sum((data.y[i] - model.response_function[data.hour[i]])**2 for i in data.index)
+ data = pd.DataFrame(
+ data=[[1, 8.3], [2, 10.3], [3, 19.0],
+ [4, 16.0], [5, 15.6], [7, 19.8]],
+ columns=['hour', 'y'],
+ )
+
+ # Sum of squared error function
+ def SSE(model):
+ expr = (
+ model.experiment_outputs[model.y]
+ - model.response_function[model.experiment_outputs[model.hour]]
+ ) ** 2
return expr
+ # Create an experiment list
+ from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import RooneyBieglerExperiment
+ exp_list = []
+ for i in range(data.shape[0]):
+ exp_list.append(RooneyBieglerExperiment(data.loc[i, :]))
+
.. doctest::
:skipif: not __import__('pyomo.contrib.parmest.parmest').contrib.parmest.parmest.parmest_available
>>> import pyomo.contrib.parmest.parmest as parmest
- >>> pest = parmest.Estimator(model_function, data, theta_names, objective_function)
+ >>> pest = parmest.Estimator(exp_list, obj_function=SSE)
Optionally, solver options can be supplied, e.g.,
@@ -80,66 +91,44 @@ Optionally, solver options can be supplied, e.g.,
:skipif: not __import__('pyomo.contrib.parmest.parmest').contrib.parmest.parmest.parmest_available
>>> solver_options = {"max_iter": 6000}
- >>> pest = parmest.Estimator(model_function, data, theta_names, objective_function, solver_options)
-
-
-
-Model function
---------------
-
-The first argument is a function which uses data for a single scenario
-to return a populated and initialized Pyomo model for that scenario.
-
-Parameters that the user would like to estimate can be defined as
-**mutable parameters (Pyomo `Param`) or variables (Pyomo `Var`)**.
-Within parmest, any parameters that are to be estimated are converted to unfixed variables.
-Variables that are to be estimated are also unfixed.
-
-The model does not have to be specifically written as a
-two-stage stochastic programming problem for parmest.
-That is, parmest can modify the
-objective, see :ref:`ObjFunction` below.
-
-Data
-----
-
-The second argument is the data which will be used to populate the Pyomo
-model. Supported data formats include:
-
-* **Pandas Dataframe** where each row is a separate scenario and column
- names refer to observed quantities. Pandas DataFrames are easily
- stored and read in from csv, excel, or databases, or created directly
- in Python.
-* **List of Pandas Dataframe** where each entry in the list is a separate scenario.
- Dataframes store observed quantities, referenced by index and column.
-* **List of dictionaries** where each entry in the list is a separate
- scenario and the keys (or nested keys) refer to observed quantities.
- Dictionaries are often preferred over DataFrames when using static and
- time series data. Dictionaries are easily stored and read in from
- json or yaml files, or created directly in Python.
-* **List of json file names** where each entry in the list contains a
- json file name for a separate scenario. This format is recommended
- when using large datasets in parallel computing.
-
-The data must be compatible with the model function that returns a
-populated and initialized Pyomo model for a single scenario. Data can
-include multiple entries per variable (time series and/or duplicate
-sensors). This information can be included in custom objective
-functions, see :ref:`ObjFunction` below.
-
-Theta names
------------
-
-The third argument is a list of parameters or variable names that the user wants to
-estimate. The list contains strings with `Param` and/or `Var` names from the Pyomo
-model.
+ >>> pest = parmest.Estimator(exp_list, obj_function=SSE, solver_options=solver_options)
+
+
+List of experiment objects
+--------------------------
+
+The first argument is a list of experiment objects which is used to
+create one labeled model for each expeirment.
+The template :class:`~pyomo.contrib.parmest.experiment.Experiment`
+can be used to generate a list of experiment objects.
+
+A labeled Pyomo model ``m`` has the following additional suffixes (Pyomo `Suffix`):
+
+* ``m.experiment_outputs`` which defines experiment output (Pyomo `Param`, `Var`, or `Expression`)
+ and their associated data values (float, int).
+* ``m.unknown_parameters`` which defines the mutable parameters or variables (Pyomo `Param` or `Var`)
+ to estimate along with their component unique identifier (Pyomo `ComponentUID`).
+ Within parmest, any parameters that are to be estimated are converted to unfixed variables.
+ Variables that are to be estimated are also unfixed.
+
+The experiment class has one required method:
+
+* :class:`~pyomo.contrib.parmest.experiment.Experiment.get_labeled_model` which returns the labeled Pyomo model.
+ Note that the model does not have to be specifically written as a
+ two-stage stochastic programming problem for parmest.
+ That is, parmest can modify the
+ objective, see :ref:`ObjFunction` below.
+
+Parmest comes with several :ref:`examplesection` that illustrates how to set up the list of experiment objects.
+The examples commonly include additional :class:`~pyomo.contrib.parmest.experiment.Experiment` class methods to
+create the model, finalize the model, and label the model. The user can customize methods to suit their needs.
.. _ObjFunction:
Objective function
------------------
-The fourth argument is an optional argument which defines the
+The second argument is an optional argument which defines the
optimization objective function to use in parameter estimation.
If no objective function is specified, the Pyomo model is used "as is" and
@@ -150,20 +139,27 @@ stochastic programming problem.
If the Pyomo model is not written as a two-stage stochastic programming problem in
this format, and/or if the user wants to use an objective that is
different than the original model, a custom objective function can be
-defined for parameter estimation. The objective function arguments
-include `model` and `data` and the objective function returns a Pyomo
+defined for parameter estimation. The objective function has a single argument,
+which is the model from a single experiment.
+The objective function returns a Pyomo
expression which is used to define "SecondStageCost". The objective
function can be used to customize data points and weights that are used
in parameter estimation.
+Parmest includes one built in objective function to compute the sum of squared errors ("SSE") between the
+``m.experiment_outputs`` model values and data values.
+
Suggested initialization procedure for parameter estimation problems
--------------------------------------------------------------------
To check the quality of initial guess values provided for the fitted parameters, we suggest solving a
square instance of the problem prior to solving the parameter estimation problem using the following steps:
-1. Create :class:`~pyomo.contrib.parmest.parmest.Estimator` object. To initialize the parameter estimation solve from the square problem solution, set optional argument ``solver_options = {bound_push: 1e-8}``.
+1. Create :class:`~pyomo.contrib.parmest.parmest.Estimator` object. To initialize the parameter
+estimation solve from the square problem solution, set optional argument ``solver_options = {bound_push: 1e-8}``.
-2. Call :class:`~pyomo.contrib.parmest.parmest.Estimator.objective_at_theta` with optional argument ``(initialize_parmest_model=True)``. Different initial guess values for the fitted parameters can be provided using optional argument `theta_values` (**Pandas Dataframe**)
+2. Call :class:`~pyomo.contrib.parmest.parmest.Estimator.objective_at_theta` with optional
+argument ``(initialize_parmest_model=True)``. Different initial guess values for the fitted
+parameters can be provided using optional argument `theta_values` (**Pandas Dataframe**)
3. Solve parameter estimation problem by calling :class:`~pyomo.contrib.parmest.parmest.Estimator.theta_est`
diff --git a/doc/OnlineDocs/contributed_packages/parmest/examples.rst b/doc/OnlineDocs/explanation/analysis/parmest/examples.rst
similarity index 76%
rename from doc/OnlineDocs/contributed_packages/parmest/examples.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/examples.rst
index 793ff3d0c8d..275e2177503 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/examples.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/examples.rst
@@ -5,9 +5,9 @@ Examples
Examples can be found in `pyomo/contrib/parmest/examples` and include:
-* Reactor design example [PyomoBookII]_
-* Semibatch example [SemiBatch]_
-* Rooney Biegler example [RooneyBiegler]_
+* Reactor design example [PyomoBookIII]_
+* Semibatch example [AM00]_
+* Rooney Biegler example [RB01]_
Each example includes a Python file that contains the Pyomo model and a
Python file to run parameter estimation.
@@ -20,13 +20,13 @@ Additional use cases include:
* Parameter estimation using mpi4py, the example saves results to a file
for later analysis/graphics (semibatch example)
-The description below uses the reactor design example. The file
+The example below uses the reactor design example. The file
**reactor_design.py** includes a function which returns an populated
instance of the Pyomo model. Note that the model is defined to maximize
`cb` and that `k1`, `k2`, and `k3` are fixed. The _main_ program is
included for easy testing of the model declaration.
-.. literalinclude:: ../../../../pyomo/contrib/parmest/examples/reactor_design/reactor_design.py
+.. literalinclude:: /../../pyomo/contrib/parmest/examples/reactor_design/reactor_design.py
:language: python
The file **parameter_estimation_example.py** uses parmest to estimate values of `k1`,
@@ -35,7 +35,7 @@ observed values of `ca`, `cb`, `cc`, and `cd`. Additional example files use
parmest to run parameter estimation with bootstrap resampling and
perform a likelihood ratio test over a range of theta values.
-.. literalinclude:: ../../../../pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.py
+.. literalinclude:: /../../pyomo/contrib/parmest/examples/reactor_design/parameter_estimation_example.py
:language: python
The semibatch and Rooney Biegler examples are defined in a similar
diff --git a/doc/OnlineDocs/contributed_packages/parmest/graphics.rst b/doc/OnlineDocs/explanation/analysis/parmest/graphics.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/graphics.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/graphics.rst
diff --git a/doc/OnlineDocs/contributed_packages/parmest/index.rst b/doc/OnlineDocs/explanation/analysis/parmest/index.rst
similarity index 64%
rename from doc/OnlineDocs/contributed_packages/parmest/index.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/index.rst
index 2bf4942e632..4616a2134d4 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/index.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/index.rst
@@ -1,14 +1,16 @@
-Parameter Estimation with ``parmest``
-=====================================
+.. _parmest:
+
+Parameter Estimation
+====================
``parmest`` is a Python package built on the Pyomo optimization modeling
-language ([PyomoJournal]_, [PyomoBookII]_) to support parameter estimation using experimental data along with
+language ([Pyomo-paper]_, [PyomoBookIII]_) to support parameter estimation using experimental data along with
confidence regions and subsequent creation of scenarios for stochastic programming.
Citation for parmest
^^^^^^^^^^^^^^^^^^^^
-If you use parmest, please cite [ParmestPaper]_
+If you use parmest, please cite [Parmest-paper]_
Index of parmest documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,10 +28,3 @@ Index of parmest documentation
examples.rst
parallel.rst
api.rst
-
-Indices and Tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/OnlineDocs/contributed_packages/parmest/installation.rst b/doc/OnlineDocs/explanation/analysis/parmest/installation.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/installation.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/installation.rst
diff --git a/doc/OnlineDocs/contributed_packages/parmest/overview.rst b/doc/OnlineDocs/explanation/analysis/parmest/overview.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/overview.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/overview.rst
diff --git a/doc/OnlineDocs/contributed_packages/parmest/pairwise_plot_CI.png b/doc/OnlineDocs/explanation/analysis/parmest/pairwise_plot_CI.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/pairwise_plot_CI.png
rename to doc/OnlineDocs/explanation/analysis/parmest/pairwise_plot_CI.png
diff --git a/doc/OnlineDocs/contributed_packages/parmest/pairwise_plot_LR.png b/doc/OnlineDocs/explanation/analysis/parmest/pairwise_plot_LR.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/parmest/pairwise_plot_LR.png
rename to doc/OnlineDocs/explanation/analysis/parmest/pairwise_plot_LR.png
diff --git a/doc/OnlineDocs/contributed_packages/parmest/parallel.rst b/doc/OnlineDocs/explanation/analysis/parmest/parallel.rst
similarity index 93%
rename from doc/OnlineDocs/contributed_packages/parmest/parallel.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/parallel.rst
index 3b60c5777de..e1d6548b105 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/parallel.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/parallel.rst
@@ -16,7 +16,7 @@ model in parallel::
The file **parallel_example.py** is shown below.
Results are saved to file for later analysis.
-.. literalinclude:: ../../../../pyomo/contrib/parmest/examples/semibatch/parallel_example.py
+.. literalinclude:: /../../pyomo/contrib/parmest/examples/semibatch/parallel_example.py
:language: python
Installation
diff --git a/doc/OnlineDocs/contributed_packages/parmest/scencreate.rst b/doc/OnlineDocs/explanation/analysis/parmest/scencreate.rst
similarity index 82%
rename from doc/OnlineDocs/contributed_packages/parmest/scencreate.rst
rename to doc/OnlineDocs/explanation/analysis/parmest/scencreate.rst
index 66d41d4c606..79dfc31fbbb 100644
--- a/doc/OnlineDocs/contributed_packages/parmest/scencreate.rst
+++ b/doc/OnlineDocs/explanation/analysis/parmest/scencreate.rst
@@ -14,9 +14,9 @@ correspond one-to-one with the experiments used as input data. It also
creates a few scenarios using the bootstrap methods and outputs prints the
scenarios to the screen, accessing them via the ``ScensItator`` a ``print``
-.. literalinclude:: ../../../../pyomo/contrib/parmest/examples/semibatch/scenario_example.py
+.. literalinclude:: /../../pyomo/contrib/parmest/examples/semibatch/scenario_example.py
:language: python
.. note::
- This example may produce an error message your version of Ipopt is not based
+ This example may produce an error message if your version of Ipopt is not based
on a good linear solver.
diff --git a/doc/OnlineDocs/contributed_packages/sensitivity_toolbox.rst b/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst
similarity index 78%
rename from doc/OnlineDocs/contributed_packages/sensitivity_toolbox.rst
rename to doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst
index 2a2ccff4b09..f0069565ff6 100644
--- a/doc/OnlineDocs/contributed_packages/sensitivity_toolbox.rst
+++ b/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst
@@ -1,7 +1,7 @@
Sensitivity Toolbox
===================
-The sensitivity toolbox provides a Pyomo interface to sIPOPT and k_aug to very quickly compute approximate solutions to nonlinear programs with a small perturbation in model parameters.
+The sensitivity toolbox provides a Pyomo interface to sIPOPT and k_aug to very quickly compute approximate solutions to nonlinear programs with a small perturbation in model parameters.
See the `sIPOPT documentation `_ or the `following paper `_ for additional details:
@@ -17,37 +17,39 @@ Using the Sensitivity Toolbox
We will start with a motivating example:
.. math::
- \begin{align*}
- \min_{x_1,x_2,x_3} \quad & x_1^2 + x_2^2 + x_3^2 \\
- \mathrm{s.t.} \qquad & 6 x_1 + 3 x_2 + 2 x_3 - p_1 = 0 \\
- & p_2 x_1 + x_2 - x_3 - 1 = 0 \\
- & x_1, x_2, x_3 \geq 0
- \end{align*}
+ :nowrap:
+
+ \[\begin{array}{ll}
+ \min_{x_1,x_2,x_3} & x_1^2 + x_2^2 + x_3^2 \\
+ \mathrm{s.t.} & 6 x_1 + 3 x_2 + 2 x_3 - p_1 = 0 \\
+ & p_2 x_1 + x_2 - x_3 - 1 = 0 \\
+ & x_1, x_2, x_3 \geq 0
+ \end{array}\]
Here :math:`x_1`, :math:`x_2`, and :math:`x_3` are the decision variables while :math:`p_1` and :math:`p_2` are parameters. At first, let's consider :math:`p_1 = 4.5` and :math:`p_2 = 1.0`. Below is the model implemented in Pyomo.
.. doctest:: python
# Import Pyomo and the sensitivity toolbox
- >>> from pyomo.environ import *
+ >>> import pyomo.environ as pyo
>>> from pyomo.contrib.sensitivity_toolbox.sens import sensitivity_calculation
# Create a concrete model
- >>> m = ConcreteModel()
+ >>> m = pyo.ConcreteModel()
# Define the variables with bounds and initial values
- >>> m.x1 = Var(initialize = 0.15, within=NonNegativeReals)
- >>> m.x2 = Var(initialize = 0.15, within=NonNegativeReals)
- >>> m.x3 = Var(initialize = 0.0, within=NonNegativeReals)
+ >>> m.x1 = pyo.Var(initialize = 0.15, within=pyo.NonNegativeReals)
+ >>> m.x2 = pyo.Var(initialize = 0.15, within=pyo.NonNegativeReals)
+ >>> m.x3 = pyo.Var(initialize = 0.0, within=pyo.NonNegativeReals)
# Define the parameters
- >>> m.eta1 = Param(initialize=4.5,mutable=True)
- >>> m.eta2 = Param(initialize=1.0,mutable=True)
+ >>> m.eta1 = pyo.Param(initialize=4.5,mutable=True)
+ >>> m.eta2 = pyo.Param(initialize=1.0,mutable=True)
# Define the constraints and objective
- >>> m.const1 = Constraint(expr=6*m.x1+3*m.x2+2*m.x3-m.eta1 ==0)
- >>> m.const2 = Constraint(expr=m.eta2*m.x1+m.x2-m.x3-1 ==0)
- >>> m.cost = Objective(expr=m.x1**2+m.x2**2+m.x3**2)
+ >>> m.const1 = pyo.Constraint(expr=6*m.x1+3*m.x2+2*m.x3-m.eta1 ==0)
+ >>> m.const2 = pyo.Constraint(expr=m.eta2*m.x1+m.x2-m.x3-1 ==0)
+ >>> m.cost = pyo.Objective(expr=m.x1**2+m.x2**2+m.x3**2)
The solution of this optimization problem is :math:`x_1^* = 0.5`, :math:`x_2^* = 0.5`, and :math:`x_3^* = 0.0`. But what if we change the parameter values to :math:`\hat{p}_1 = 4.0` and :math:`\hat{p}_2 = 1.0`? Is there a quick way to approximate the new solution :math:`\hat{x}_1^*`, :math:`\hat{x}_2^*`, and :math:`\hat{x}_3^*`? Yes! This is the main functionality of sIPOPT and k_aug.
@@ -56,8 +58,8 @@ Next we define the perturbed parameter values :math:`\hat{p}_1` and :math:`\hat{
.. doctest:: python
- >>> m.perturbed_eta1 = Param(initialize = 4.0)
- >>> m.perturbed_eta2 = Param(initialize = 1.0)
+ >>> m.perturbed_eta1 = pyo.Param(initialize = 4.0)
+ >>> m.perturbed_eta2 = pyo.Param(initialize = 1.0)
And finally we call sIPOPT or k_aug:
@@ -67,11 +69,23 @@ And finally we call sIPOPT or k_aug:
>>> m_sipopt = sensitivity_calculation('sipopt', m, [m.eta1, m.eta2], [m.perturbed_eta1, m.perturbed_eta2], tee=False)
>>> m_kaug_dsdp = sensitivity_calculation('k_aug', m, [m.eta1, m.eta2], [m.perturbed_eta1, m.perturbed_eta2], tee=False)
-The first argument specifies the method, either 'sipopt' or 'k_aug'. The second argument is the Pyomo model. The third argument is a list of the original parameters. The fourth argument is a list of the perturbed parameters. It's important that these two lists are the same length and in the same order.
+.. testcode:: python
+ :skipif: not sipopt_available or not k_aug_available or not dot_sens_available
+ :hide:
+
+ # The x3 result can come back -0.000 depending on the platform or
+ # solver version; map it so that tests don't fail.
+ for _m in (m, m_sipopt, m_kaug_dsdp):
+ if f'{_m.x3():.3f}' == '-0.000':
+ _m.x3 = 0.
+ if f'{m_sipopt.sens_sol_state_1[m_sipopt.x3]:.3f}' == '-0.000':
+ m_sipopt.sens_sol_state_1[m_sipopt.x3] = 0.
+
+The first argument specifies the method, either 'sipopt' or 'k_aug'. The second argument is the Pyomo model. The third argument is a list of the original parameters. The fourth argument is a list of the perturbed parameters. It's important that these two lists are the same length and in the same order.
First, we can inspect the initial point:
-.. doctest:: python
+.. doctest:: python
:skipif: not sipopt_available or not k_aug_available or not dot_sens_available
>>> print("eta1 = %0.3f" % m.eta1())
@@ -115,7 +129,7 @@ Note that k_aug does not save the solution with the original parameter values. F
.. doctest:: python
:skipif: not sipopt_available or not k_aug_available or not dot_sens_available
-
+
# *sIPOPT*
# New parameter values:
>>> print("eta1 = %0.3f" %m_sipopt.perturbed_eta1())
@@ -138,7 +152,7 @@ Note that k_aug does not save the solution with the original parameter values. F
x2 = 0.667
>>> print("x3 = %0.3f" % x3)
- x3 = -0.000
+ x3 = 0.000
# *k_aug*
# New parameter values:
@@ -162,7 +176,7 @@ Note that k_aug does not save the solution with the original parameter values. F
x2 = 0.667
>>> print("x3 = %0.3f" % x3)
- x3 = -0.000
+ x3 = 0.000
Installing sIPOPT and k_aug
@@ -175,7 +189,7 @@ The sensitivity toolbox requires either sIPOPT or k_aug to be installed and avai
* https://coin-or.github.io/coinbrew/
* https://github.com/dthierry/k_aug
-.. note::
+.. note::
If you get an error that ``ipopt_sens`` or ``k_aug`` and ``dot_sens`` cannot be found, double check your installation and make sure the build directories containing the executables were added to your system PATH.
@@ -183,3 +197,4 @@ Sensitivity Toolbox Interface
-----------------------------
.. autofunction:: pyomo.contrib.sensitivity_toolbox.sens.sensitivity_calculation
+ :noindex:
diff --git a/doc/OnlineDocs/contributed_packages/index.rst b/doc/OnlineDocs/explanation/contrib_index.txt
similarity index 97%
rename from doc/OnlineDocs/contributed_packages/index.rst
rename to doc/OnlineDocs/explanation/contrib_index.txt
index b1d9cbbad3b..65c14a721df 100644
--- a/doc/OnlineDocs/contributed_packages/index.rst
+++ b/doc/OnlineDocs/explanation/contrib_index.txt
@@ -15,6 +15,7 @@ Contributed packages distributed with Pyomo:
.. toctree::
:maxdepth: 1
+ alternative_solutions.rst
community.rst
doe/doe.rst
gdpopt.rst
diff --git a/doc/OnlineDocs/developer_reference/config.rst b/doc/OnlineDocs/explanation/developer_utils/config.rst
similarity index 100%
rename from doc/OnlineDocs/developer_reference/config.rst
rename to doc/OnlineDocs/explanation/developer_utils/config.rst
diff --git a/doc/OnlineDocs/developer_reference/deprecation.rst b/doc/OnlineDocs/explanation/developer_utils/deprecation.rst
similarity index 100%
rename from doc/OnlineDocs/developer_reference/deprecation.rst
rename to doc/OnlineDocs/explanation/developer_utils/deprecation.rst
diff --git a/doc/OnlineDocs/explanation/developer_utils/index.rst b/doc/OnlineDocs/explanation/developer_utils/index.rst
new file mode 100644
index 00000000000..7b61e9a3ec1
--- /dev/null
+++ b/doc/OnlineDocs/explanation/developer_utils/index.rst
@@ -0,0 +1,8 @@
+Developer Utilities
+===================
+
+.. toctree::
+ :maxdepth: 2
+
+ config
+ deprecation
diff --git a/doc/OnlineDocs/explanation/experimental/index.rst b/doc/OnlineDocs/explanation/experimental/index.rst
new file mode 100644
index 00000000000..0fe881d5011
--- /dev/null
+++ b/doc/OnlineDocs/explanation/experimental/index.rst
@@ -0,0 +1,8 @@
+Experimental features
+=====================
+
+.. toctree::
+ :maxdepth: 2
+
+ kernel/index
+ solvers
diff --git a/doc/OnlineDocs/library_reference/kernel/index.rst b/doc/OnlineDocs/explanation/experimental/kernel/index.rst
similarity index 89%
rename from doc/OnlineDocs/library_reference/kernel/index.rst
rename to doc/OnlineDocs/explanation/experimental/kernel/index.rst
index 70c3cc715a9..bf48e865d02 100644
--- a/doc/OnlineDocs/library_reference/kernel/index.rst
+++ b/doc/OnlineDocs/explanation/experimental/kernel/index.rst
@@ -21,7 +21,7 @@ The :python:`pyomo.kernel` library is an experimental modeling interface designe
Models built from :python:`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.
-.. literalinclude:: examples/kernel_solving.py
+.. literalinclude:: /src/kernel/examples/kernel_solving.py
:language: python
Notable Improvements
@@ -32,7 +32,7 @@ More Control of Model Structure
Containers in :python:`pyomo.kernel` are analogous to indexed components in :python:`pyomo.environ`. However, :python:`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 :python:`pyomo.kernel.variable` containers.
-.. literalinclude:: examples/kernel_containers_all.spy
+.. literalinclude:: /src/kernel/examples/kernel_containers_all.spy
:language: python
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.
@@ -58,21 +58,21 @@ The next series of examples goes into more detail on how to implement derived co
The following code block shows a class definition for a non-negative variable, starting from :python:`pyomo.kernel.variable` as a base class.
-.. literalinclude:: examples/kernel_subclassing_Nonnegative.spy
+.. literalinclude:: /src/kernel/examples/kernel_subclassing_Nonnegative.spy
:language: python
The :python:`NonNegativeVariable` class prevents negative values from being stored into its lower bound during initialization or later on through assignment statements (e.g, :python:`x.lb = -1` fails). Note that the :python:`__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 :python:`Point` that represents a 3-dimensional point in Cartesian space. The new type derives from the :python:`pyomo.kernel.variable_tuple` container and uses the :python:`NonNegativeVariable` type we defined previously in the `z` coordinate.
-.. literalinclude:: examples/kernel_subclassing_Point.spy
+.. literalinclude:: /src/kernel/examples/kernel_subclassing_Point.spy
:language: python
The :python:`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 :python:`Point` object. It derives from the :python:`pyomo.kernel.constraint` class, overriding the constructor to build the constraint expression and utilizing the property methods on the point class to increase readability.
-.. literalinclude:: examples/kernel_subclassing_SOC.spy
+.. literalinclude:: /src/kernel/examples/kernel_subclassing_SOC.spy
:language: python
@@ -81,12 +81,12 @@ Reduced Memory Usage
The :python:`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 :python:`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.
-.. literalinclude:: examples/transformer_kernel.spy
+.. literalinclude:: /src/kernel/examples/transformer_kernel.spy
:language: python
A simplified version of this using :python:`pyomo.environ` components might look like what is below.
-.. literalinclude:: examples/transformer_aml.spy
+.. literalinclude:: /src/kernel/examples/transformer_aml.spy
:language: python
The transformer expressed using :python:`pyomo.kernel` components requires roughly 2 KB of memory, whereas the :python:`pyomo.environ` version requires roughly 8.4 KB of memory (an increase of more than 4x). Additionally, the :python:`pyomo.kernel` transformer is fully compatible with all existing :python:`pyomo.kernel` block containers.
@@ -142,7 +142,7 @@ instantiation. The first method is to directly instantiate a
conic constraint object, providing all necessary input
variables:
-.. literalinclude:: examples/conic_Class.spy
+.. literalinclude:: /src/kernel/examples/conic_Class.spy
:language: python
This method may be limiting if utilizing the Mosek solver as
@@ -164,47 +164,5 @@ constraint, as well as auxiliary constraints that link the
inputs (that are not :python:`None`) to the auxiliary
variables. Example:
-.. literalinclude:: examples/conic_Domain.spy
+.. literalinclude:: /src/kernel/examples/conic_Domain.spy
:language: python
-
-Reference
----------
-
-.. _kernel_modeling_components:
-
-Modeling Components:
-^^^^^^^^^^^^^^^^^^^^
-
-.. toctree::
- :maxdepth: 1
-
- block.rst
- variable.rst
- constraint.rst
- parameter.rst
- objective.rst
- expression.rst
- sos.rst
- suffix.rst
- piecewise/index.rst
- conic.rst
-
-Base API:
-^^^^^^^^^
-
-.. toctree::
- :maxdepth: 1
-
- base.rst
- homogeneous_container.rst
- heterogeneous_container.rst
-
-Containers:
-^^^^^^^^^^^
-
-.. toctree::
- :maxdepth: 1
-
- tuple_container.rst
- list_container.rst
- dict_container.rst
diff --git a/doc/OnlineDocs/explanation/experimental/kernel/syntax_comparison.rst b/doc/OnlineDocs/explanation/experimental/kernel/syntax_comparison.rst
new file mode 100644
index 00000000000..c0d60ad86b1
--- /dev/null
+++ b/doc/OnlineDocs/explanation/experimental/kernel/syntax_comparison.rst
@@ -0,0 +1,133 @@
+.. _kernel_syntax_comparison:
+
+Syntax Comparison Table (pyomo.kernel vs pyomo.environ)
+=======================================================
+
+.. list-table::
+ :header-rows: 1
+ :align: center
+
+ * -
+ - **pyomo.kernel**
+ - **pyomo.environ**
+
+ * - **Import**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Import_Syntax.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Import_Syntax.spy
+ :language: python
+ * - **Model** [#models_fn]_
+ - .. literalinclude:: /src/kernel/examples/kernel_example_AbstractModels.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_ConcreteModels.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_AbstractModels.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_ConcreteModels.spy
+ :language: python
+ * - **Set** [#sets_fn]_
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Sets_1.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Sets_2.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Sets_1.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Sets_2.spy
+ :language: python
+ * - **Parameter** [#parameters_fn]_
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Parameters_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Parameters_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Parameters_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Parameters_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Parameters_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Parameters_list.spy
+ :language: python
+ * - **Variable**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Variables_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Variables_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Variables_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Variables_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Variables_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Variables_list.spy
+ :language: python
+ * - **Constraint**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Constraints_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Constraints_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Constraints_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Constraints_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Constraints_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Constraints_list.spy
+ :language: python
+ * - **Expression**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Expressions_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Expressions_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Expressions_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Expressions_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Expressions_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Expressions_list.spy
+ :language: python
+ * - **Objective**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Objectives_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Objectives_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Objectives_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Objectives_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Objectives_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Objectives_list.spy
+ :language: python
+ * - **SOS** [#sos_fn]_
+ - .. literalinclude:: /src/kernel/examples/kernel_example_SOS_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_SOS_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_SOS_list.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_SOS_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_SOS_dict.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_SOS_list.spy
+ :language: python
+ * - **Suffix**
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Suffix_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/kernel_example_Suffix_dict.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Suffix_single.spy
+ :language: python
+ .. literalinclude:: /src/kernel/examples/aml_example_Suffix_dict.spy
+ :language: python
+ * - **Piecewise** [#pw_fn]_
+ - .. literalinclude:: /src/kernel/examples/kernel_example_Piecewise_1d.spy
+ :language: python
+ - .. literalinclude:: /src/kernel/examples/aml_example_Piecewise_1d.spy
+ :language: python
+.. [#models_fn] :python:`pyomo.kernel` does not include an alternative to the :python:`AbstractModel` component from :python:`pyomo.environ`. All data necessary to build a model must be imported by the user.
+.. [#sets_fn] :python:`pyomo.kernel` does not include an alternative to the Pyomo :python:`Set` component from :python:`pyomo.environ`.
+.. [#parameters_fn] :python:`pyomo.kernel.parameter` objects are always mutable.
+.. [#sos_fn] Special Ordered Sets
+.. [#pw_fn] Both :python:`pyomo.kernel.piecewise` and :python:`pyomo.kernel.piecewise_nd` create objects that are sub-classes of :python:`pyomo.kernel.block`. Thus, these objects can be stored in containers such as :python:`pyomo.kernel.block_dict` and :python:`pyomo.kernel.block_list`.
diff --git a/doc/OnlineDocs/explanation/experimental/solvers.rst b/doc/OnlineDocs/explanation/experimental/solvers.rst
new file mode 100644
index 00000000000..478749351eb
--- /dev/null
+++ b/doc/OnlineDocs/explanation/experimental/solvers.rst
@@ -0,0 +1,494 @@
+Future Solver Interface Changes
+===============================
+
+.. note::
+
+ The new solver interfaces are still under active development. They
+ are included in the releases as development previews. Please be
+ aware that APIs and functionality may change with no notice.
+
+ We welcome any feedback and ideas as we develop this capability.
+ Please post feedback on
+ `Issue 1030 `_.
+
+Pyomo offers interfaces into multiple solvers, both commercial and open
+source. To support better capabilities for solver interfaces, the Pyomo
+team is actively redesigning the existing interfaces to make them more
+maintainable and intuitive for use. A preview of the redesigned
+interfaces can be found in ``pyomo.contrib.solver``.
+
+.. currentmodule:: pyomo.contrib.solver
+
+
+New Interface Usage
+-------------------
+
+The new interfaces are not completely backwards compatible with the
+existing Pyomo solver interfaces. However, to aid in testing and
+evaluation, we are distributing versions of the new solver interfaces
+that are compatible with the existing ("legacy") solver interface.
+These "legacy" interfaces are registered with the current
+``SolverFactory`` using slightly different names (to avoid conflicts
+with existing interfaces).
+
+.. |br| raw:: html
+
+
+
+.. list-table:: Available Redesigned Solvers and Names Registered
+ in the SolverFactories
+ :header-rows: 1
+
+ * - Solver
+ - Name registered in the |br| ``pyomo.contrib.solver.common.factory.SolverFactory``
+ - Name registered in the |br| ``pyomo.opt.base.solvers.LegacySolverFactory``
+ * - Ipopt
+ - ``ipopt``
+ - ``ipopt_v2``
+ * - Gurobi (persistent)
+ - ``gurobi_persistent``
+ - ``gurobi_persistent_v2``
+ * - Gurobi (direct)
+ - ``gurobi_direct``
+ - ``gurobi_direct_v2``
+ * - HiGHS
+ - ``highs``
+ - ``highs``
+
+Using the new interfaces through the legacy interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here we use the new interface as exposed through the existing (legacy)
+solver factory and solver interface wrapper. This provides an API that
+is compatible with the existing (legacy) Pyomo solver interface and can
+be used with other Pyomo tools / capabilities.
+
+.. testcode::
+ :skipif: not ipopt_available
+
+ import pyomo.environ as pyo
+
+ model = pyo.ConcreteModel()
+ model.x = pyo.Var(initialize=1.5)
+ model.y = pyo.Var(initialize=1.5)
+
+ def rosenbrock(model):
+ return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
+
+ model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
+
+ status = pyo.SolverFactory('ipopt_v2').solve(model)
+ pyo.assert_optimal_termination(status)
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ 2 Var Declarations
+ ...
+ 3 Declarations: x y obj
+
+In keeping with our commitment to backwards compatibility, both the legacy and
+future methods of specifying solver options are supported:
+
+.. testcode::
+ :skipif: not ipopt_available
+
+ import pyomo.environ as pyo
+
+ model = pyo.ConcreteModel()
+ model.x = pyo.Var(initialize=1.5)
+ model.y = pyo.Var(initialize=1.5)
+
+ def rosenbrock(model):
+ return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
+
+ model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
+
+ # Backwards compatible
+ status = pyo.SolverFactory('ipopt_v2').solve(model, options={'max_iter' : 6})
+ # Forwards compatible
+ status = pyo.SolverFactory('ipopt_v2').solve(model, solver_options={'max_iter' : 6})
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ 2 Var Declarations
+ ...
+ 3 Declarations: x y obj
+
+Using the new interfaces directly
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here we use the new interface by importing it directly:
+
+.. testcode::
+ :skipif: not ipopt_available
+
+ # Direct import
+ import pyomo.environ as pyo
+ from pyomo.contrib.solver.solvers.ipopt import Ipopt
+
+ model = pyo.ConcreteModel()
+ model.x = pyo.Var(initialize=1.5)
+ model.y = pyo.Var(initialize=1.5)
+
+ def rosenbrock(model):
+ return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
+
+ model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
+
+ opt = Ipopt()
+ status = opt.solve(model)
+ pyo.assert_optimal_termination(status)
+ # Displays important results information; only available through the new interfaces
+ status.display()
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ termination_condition: ...
+ ...
+ 3 Declarations: x y obj
+
+Using the new interfaces through the "new" SolverFactory
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Here we use the new interface by retrieving it from the new ``SolverFactory``:
+
+.. testcode::
+ :skipif: not ipopt_available
+
+ # Import through new SolverFactory
+ import pyomo.environ as pyo
+ from pyomo.contrib.solver.common.factory import SolverFactory
+
+ model = pyo.ConcreteModel()
+ model.x = pyo.Var(initialize=1.5)
+ model.y = pyo.Var(initialize=1.5)
+
+ def rosenbrock(model):
+ return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
+
+ model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
+
+ opt = SolverFactory('ipopt')
+ status = opt.solve(model)
+ pyo.assert_optimal_termination(status)
+ # Displays important results information; only available through the new interfaces
+ status.display()
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ termination_condition: ...
+ ...
+ 3 Declarations: x y obj
+
+Switching all of Pyomo to use the new interfaces
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We also provide a mechanism to get a "preview" of the future where we
+replace the existing (legacy) SolverFactory and utilities with the new
+(development) version (see :doc:`/reference/future`):
+
+.. testcode::
+ :skipif: not ipopt_available
+
+ # Change default SolverFactory version
+ import pyomo.environ as pyo
+ from pyomo.__future__ import solver_factory_v3
+
+ model = pyo.ConcreteModel()
+ model.x = pyo.Var(initialize=1.5)
+ model.y = pyo.Var(initialize=1.5)
+
+ def rosenbrock(model):
+ return (1.0 - model.x) ** 2 + 100.0 * (model.y - model.x**2) ** 2
+
+ model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
+
+ status = pyo.SolverFactory('ipopt').solve(model)
+ pyo.assert_optimal_termination(status)
+ # Displays important results information; only available through the new interfaces
+ status.display()
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ termination_condition: ...
+ ...
+ 3 Declarations: x y obj
+
+.. testcode::
+ :skipif: not ipopt_available
+ :hide:
+
+ from pyomo.__future__ import solver_factory_v1
+
+Linear Presolve and Scaling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The new interface allows access to new capabilities in the various
+problem writers, including the linear presolve and scaling options
+recently incorporated into the redesigned NL writer. For example, you
+can control the NL writer in the new ``ipopt`` interface through the
+solver's ``writer_config`` configuration option:
+
+.. autoclass:: pyomo.contrib.solver.solvers.ipopt.Ipopt
+ :noindex:
+ :members: solve
+
+.. testcode::
+
+ from pyomo.contrib.solver.solvers.ipopt import Ipopt
+ opt = Ipopt()
+ opt.config.writer_config.display()
+
+.. testoutput::
+
+ show_section_timing: false
+ skip_trivial_constraints: true
+ file_determinism: FileDeterminism.ORDERED
+ symbolic_solver_labels: false
+ scale_model: true
+ export_nonlinear_variables: None
+ row_order: None
+ column_order: None
+ export_defined_variables: true
+ linear_presolve: true
+
+Note that, by default, both ``linear_presolve`` and ``scale_model`` are enabled.
+Users can manipulate ``linear_presolve`` and ``scale_model`` to their preferred
+states by changing their values.
+
+.. code-block:: python
+
+ >>> opt.config.writer_config.linear_presolve = False
+
+
+Interface Implementation
+------------------------
+
+All new interfaces should be built upon one of two classes (currently):
+:class:`SolverBase` or
+:class:`PersistentSolverBase`.
+
+All solvers should have the following:
+
+.. autoclass:: pyomo.contrib.solver.common.base.SolverBase
+ :noindex:
+ :members:
+
+Persistent solvers include additional members as well as other configuration options:
+
+.. autoclass:: pyomo.contrib.solver.common.base.PersistentSolverBase
+ :noindex:
+ :show-inheritance:
+ :members:
+
+Results
+-------
+
+Every solver, at the end of a
+:meth:`solve` call, will
+return a :class:`Results`
+object. This object is a :py:class:`pyomo.common.config.ConfigDict`,
+which can be manipulated similar to a standard ``dict`` in Python.
+
+.. autoclass:: pyomo.contrib.solver.common.results.Results
+ :noindex:
+ :show-inheritance:
+ :members:
+ :undoc-members:
+
+The new interface has condensed :py:class:`~pyomo.opt.results.solver.SolverStatus`,
+:py:class:`~pyomo.opt.results.solver.TerminationCondition`,
+and :py:class:`~pyomo.opt.results.solution.SolutionStatus` into
+:py:class:`~pyomo.contrib.solver.common.results.TerminationCondition`
+and :py:class:`~pyomo.contrib.solver.common.results.SolutionStatus` to
+reduce complexity. As a result, several legacy
+:py:class:`~pyomo.opt.results.solver.SolutionStatus` values are
+no longer achievable. These are detailed in the table below.
+
+.. list-table:: Mapping from unachievable :py:class:`~pyomo.opt.results.solver.SolutionStatus`
+ to future statuses
+ :header-rows: 1
+
+ * - Legacy :py:class:`~pyomo.opt.results.solver.SolutionStatus`
+ - :py:class:`~pyomo.contrib.solver.common.results.TerminationCondition`
+ - :py:class:`~pyomo.contrib.solver.common.results.SolutionStatus`
+ * - other
+ - unknown
+ - noSolution
+ * - unsure
+ - unknown
+ - noSolution
+ * - locallyOptimal
+ - convergenceCriteriaSatisfied
+ - optimal
+ * - globallyOptimal
+ - convergenceCriteriaSatisfied
+ - optimal
+ * - bestSoFar
+ - convergenceCriteriaSatisfied
+ - feasible
+
+Termination Conditions
+^^^^^^^^^^^^^^^^^^^^^^
+
+Pyomo offers a standard set of termination conditions to map to solver
+returns. The intent of
+:class:`TerminationCondition`
+is to notify the user of why the solver exited. The user is expected
+to inspect the :class:`Results`
+object or any returned solver messages or logs for more information.
+
+.. autoclass:: pyomo.contrib.solver.common.results.TerminationCondition
+ :noindex:
+ :show-inheritance:
+
+
+Solution Status
+^^^^^^^^^^^^^^^
+
+Pyomo offers a standard set of solution statuses to map to solver
+output. The intent of
+:class:`SolutionStatus`
+is to notify the user of what the solver returned at a high level. The
+user is expected to inspect the
+:class:`Results` object or any
+returned solver messages or logs for more information.
+
+.. autoclass:: pyomo.contrib.solver.common.results.SolutionStatus
+ :noindex:
+ :show-inheritance:
+
+
+Solution
+--------
+
+Solutions can be loaded back into a model using a ``SolutionLoader``. A specific
+loader should be written for each unique case. Several have already been
+implemented. For example, for ``ipopt``:
+
+.. autoclass:: pyomo.contrib.solver.solvers.ipopt.IpoptSolutionLoader
+ :noindex:
+ :members:
+ :show-inheritance:
+ :inherited-members:
+
+
+Dual Sign Convention
+--------------------
+For all future solver interfaces, Pyomo adopts the following sign convention. Given the problem
+
+.. math::
+
+ \begin{aligned}
+ \min\quad & f(x) \\
+ \text{s.t.}\quad & c_i(x) = 0 \quad \forall i \in \mathcal{E} \\
+ & g_i(x) \le 0 \quad \forall i \in \mathcal{U} \\
+ & h_i(x) \ge 0 \quad \forall i \in \mathcal{L}
+ \end{aligned}
+
+We define the Lagrangian as
+
+.. math::
+
+ \begin{aligned}
+ L(x, \lambda, \nu, \delta)
+ &= f(x)
+ - \sum_{i \in \mathcal{E}} \lambda_i\,c_i(x)
+ - \sum_{i \in \mathcal{U}} \nu_i\,g_i(x)
+ - \sum_{i \in \mathcal{L}} \delta_i\,h_i(x)
+ \end{aligned}
+
+Then, the KKT conditions are [NW99]_
+
+.. math::
+
+ \begin{aligned}
+ \nabla_x L(x, \lambda, \nu, \delta) &= 0 \\
+ c(x) &= 0 \\
+ g(x) &\le 0 \\
+ h(x) &\ge 0 \\
+ \nu &\le 0 \\
+ \delta &\ge 0 \\
+ \nu_i\,g_i(x) &= 0 \\
+ \delta_i\,h_i(x) &= 0
+ \end{aligned}
+
+Note that this sign convention is based on the ``(lower, body, upper)``
+representation of constraints rather than the expression provided by a
+user. Users can specify constraints with variables on both the left- and
+right-hand sides of equalities and inequalities. However, the
+``(lower, body, upper)`` representation ensures that all variables
+appear in the ``body``, matching the form of the problem above.
+
+For maximization problems of the form
+
+.. math::
+
+ \begin{aligned}
+ \max\quad & f(x) \\
+ \text{s.t.}\quad & c_i(x) = 0 \quad \forall i \in \mathcal{E} \\
+ & g_i(x) \le 0 \quad \forall i \in \mathcal{U} \\
+ & h_i(x) \ge 0 \quad \forall i \in \mathcal{L}
+ \end{aligned}
+
+we define the Lagrangian to be the same as above:
+
+.. math::
+
+ \begin{aligned}
+ L(x, \lambda, \nu, \delta)
+ &= f(x)
+ - \sum_{i \in \mathcal{E}} \lambda_i\,c_i(x)
+ - \sum_{i \in \mathcal{U}} \nu_i\,g_i(x)
+ - \sum_{i \in \mathcal{L}} \delta_i\,h_i(x)
+ \end{aligned}
+
+As a result, the signs of the duals change. The KKT conditions are
+
+.. math::
+
+ \begin{aligned}
+ \nabla_x L(x, \lambda, \nu, \delta) &= 0 \\
+ c(x) &= 0 \\
+ g(x) &\le 0 \\
+ h(x) &\ge 0 \\
+ \nu &\ge 0 \\
+ \delta &\le 0 \\
+ \nu_i\,g_i(x) &= 0 \\
+ \delta_i\,h_i(x) &= 0
+ \end{aligned}
+
+
+Pyomo also supports "range constraints" which are inequalities with both upper
+and lower bounds, where the bounds are not equal. For example,
+
+.. math::
+
+ -1 \leq x + y \leq 1
+
+These are handled very similarly to variable bounds in terms of dual sign
+conventions. For these, at most one "side" of the inequality can be active
+at a time. If neither side is active, then the dual will be zero. If the dual
+is nonzero, then the dual corresponds to the side of the constraint that is
+active. The dual for the other side will be implicitly zero. When accessing
+duals, the keys are the constraints. As a result, there is only one key for
+a range constraint, even though it is really two constraints. Therefore, the
+dual for the inactive side will not be reported explicitly. Again, the sign
+convention is based on the ``(lower, body, upper)`` representation of the
+constraint. Therefore, the left side of this inequality belongs to
+:math:`\mathcal{L}` and the right side belongs to :math:`\mathcal{U}`.
diff --git a/doc/OnlineDocs/explanation/index.rst b/doc/OnlineDocs/explanation/index.rst
new file mode 100644
index 00000000000..0121debcd32
--- /dev/null
+++ b/doc/OnlineDocs/explanation/index.rst
@@ -0,0 +1,55 @@
+Explanations
+============
+
+.. toctree::
+ :maxdepth: 3
+
+ philosophy/index
+ modeling/index
+ solvers/index
+ analysis/index
+ modeling_utils/index
+ developer_utils/index
+ experimental/index
+
+
+
+..
+ Reorganization notes:
+
+ `Pyomo Philosophy`
+ `Concrete and Abstract Models`
+ `Component Hierarchy`
+ `Expression System`
+ `Transformations`
+ `Modeling in Pyomo`
+ `Math Programming`
+ `GDP`
+ `DAE`
+ `Network`
+ `Piecewise Linear`
+ `Constraint Programming`
+ `Units of Measure`
+ `Solvers`
+ `PyROS`
+ `MindtPy`
+ `Trust Region`
+ `Pynumero`
+ `Analysis in Pyomo`
+ `IIS`
+ `FBBT`
+ `Incidence Analysis`
+ `Parameter Estimation`
+ `Design of Experiments`
+ `MPC`
+ `AOS`
+ `Modeling Utilities`
+ `Latex Printer`
+ `FME`
+ `Model Viewer`
+ `Model Flattening`
+ `Developer Utilities`
+ `Configuration System`
+ `Deprecation System`
+ `Experimental`
+ `Kernel`
diff --git a/doc/OnlineDocs/modeling_extensions/dae.rst b/doc/OnlineDocs/explanation/modeling/dae.rst
similarity index 86%
rename from doc/OnlineDocs/modeling_extensions/dae.rst
rename to doc/OnlineDocs/explanation/modeling/dae.rst
index 703e83f4f14..ac43ed35005 100644
--- a/doc/OnlineDocs/modeling_extensions/dae.rst
+++ b/doc/OnlineDocs/explanation/modeling/dae.rst
@@ -5,7 +5,8 @@ Dynamic Optimization with pyomo.DAE
:scale: 35%
:align: right
-The pyomo.DAE modeling extension [PyomoDAE]_ allows users to incorporate systems of
+The pyomo.DAE modeling extension [PyomoDAE-paper]_ allows users to
+incorporate systems of
differential algebraic equations (DAE)s in a Pyomo model. The modeling
components in this extension are able to represent ordinary or partial
differential equations. The differential equations do not have to be
@@ -34,19 +35,19 @@ Pyomo.DAE introduces three new modeling components to Pyomo:
As will be shown later, differential equations can be declared using
using these new modeling components along with the standard Pyomo
-:py:class:`Var ` and
-:py:class:`Constraint ` components.
+:py:class:`.Var` and
+:py:class:`.Constraint` components.
ContinuousSet
*************
This component is used to define continuous bounded domains (for example
'spatial' or 'time' domains). It is similar to a Pyomo
-:py:class:`Set ` component and can be used to index things
+:py:class:`.Set` component and can be used to index things
like variables and constraints. Any number of
:py:class:`ContinuousSets ` can be used to index a
component and components can be indexed by both
-:py:class:`Sets ` and
+:py:class:`Sets <.Set>` and
:py:class:`ContinuousSets ` in arbitrary order.
In the current implementation, models with
@@ -58,7 +59,8 @@ bounds of the continuous domain. A user may also specify additional points in
the domain to be used as finite element points in the discretization.
.. autoclass:: pyomo.dae.ContinuousSet
- :members:
+ :noindex:
+ :members:
The following code snippet shows examples of declaring a
:py:class:`ContinuousSet ` component on a
@@ -67,10 +69,10 @@ concrete Pyomo model:
.. doctest::
Required imports
- >>> from pyomo.environ import *
- >>> from pyomo.dae import *
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.dae import ContinuousSet
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
Declaration by providing bounds
>>> model.t = ContinuousSet(bounds=(0,5))
@@ -94,10 +96,10 @@ abstract Pyomo model using the example data file.
.. doctest::
Required imports
- >>> from pyomo.environ import *
- >>> from pyomo.dae import *
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.dae import ContinuousSet
- >>> model = AbstractModel()
+ >>> model = pyo.AbstractModel()
The ContinuousSet below will be initialized using the points
in the data file when a model instance is created.
@@ -110,9 +112,9 @@ abstract Pyomo model using the example data file.
.. note::
Most valid ways to declare and initialize a
- :py:class:`Set ` can be used to
+ :py:class:`.Set` can be used to
declare and initialize a :py:class:`ContinuousSet`.
- See the documentation for :py:class:`Set ` for additional
+ See the documentation for :py:class:`.Set` for additional
options.
.. warning::
@@ -127,7 +129,7 @@ abstract Pyomo model using the example data file.
.. note::
:py:class:`ContinuousSet ` components are
always ordered (sorted) therefore the ``first()`` and ``last()``
- :py:class:`Set ` methods can be used to access the lower
+ :py:class:`.Set` methods can be used to access the lower
and upper boundaries of the
:py:class:`ContinuousSet ` respectively
@@ -135,7 +137,8 @@ DerivativeVar
*************
.. autoclass:: pyomo.dae.DerivativeVar
- :members:
+ :noindex:
+ :members:
The code snippet below shows examples of declaring
:py:class:`DerivativeVar ` components on a
@@ -143,22 +146,22 @@ Pyomo model. In each case, the variable being differentiated is supplied
as the only positional argument and the type of derivative is specified
using the 'wrt' (or the more verbose 'withrespectto') keyword
argument. Any keyword argument that is valid for a Pyomo
-:py:class:`Var ` component may also be specified.
+:py:class:`.Var` component may also be specified.
.. doctest::
Required imports
- >>> from pyomo.environ import *
- >>> from pyomo.dae import *
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.dae import ContinuousSet, DerivativeVar
- >>> model = ConcreteModel()
- >>> model.s = Set(initialize=['a','b'])
+ >>> model = pyo.ConcreteModel()
+ >>> model.s = pyo.Set(initialize=['a','b'])
>>> model.t = ContinuousSet(bounds=(0,5))
>>> model.l = ContinuousSet(bounds=(-10,10))
- >>> model.x = Var(model.t)
- >>> model.y = Var(model.s,model.t)
- >>> model.z = Var(model.t,model.l)
+ >>> model.x = pyo.Var(model.t)
+ >>> model.y = pyo.Var(model.s,model.t)
+ >>> model.z = pyo.Var(model.t,model.l)
Declare the first derivative of model.x with respect to model.t
>>> model.dxdt = DerivativeVar(model.x, withrespectto=model.t)
@@ -179,32 +182,32 @@ argument. Any keyword argument that is valid for a Pyomo
The 'initialize' keyword argument will initialize the value of a
derivative and is **not** the same as specifying an initial
condition. Initial or boundary conditions should be specified using a
- :py:class:`Constraint` or
- :py:class:`ConstraintList` or
- by fixing the value of a :py:class:`Var` at a boundary
+ :py:class:`.Constraint` or
+ :py:class:`.ConstraintList` or
+ by fixing the value of a :py:class:`.Var` at a boundary
point.
Declaring Differential Equations
--------------------------------
A differential equations is declared as a standard Pyomo
-:py:class:`Constraint` and is not required to have
+:py:class:`.Constraint` and is not required to have
any particular form. The following code snippet shows how one might declare
an ordinary or partial differential equation.
.. doctest::
Required imports
- >>> from pyomo.environ import *
- >>> from pyomo.dae import *
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.dae import ContinuousSet, DerivativeVar, Integral
- >>> model = ConcreteModel()
- >>> model.s = Set(initialize=['a', 'b'])
+ >>> model = pyo.ConcreteModel()
+ >>> model.s = pyo.Set(initialize=['a', 'b'])
>>> model.t = ContinuousSet(bounds=(0, 5))
>>> model.l = ContinuousSet(bounds=(-10, 10))
- >>> model.x = Var(model.s, model.t)
- >>> model.y = Var(model.t, model.l)
+ >>> model.x = pyo.Var(model.s, model.t)
+ >>> model.y = pyo.Var(model.t, model.l)
>>> model.dxdt = DerivativeVar(model.x, wrt=model.t)
>>> model.dydt = DerivativeVar(model.y, wrt=model.t)
>>> model.dydl2 = DerivativeVar(model.y, wrt=(model.l, model.l))
@@ -212,23 +215,23 @@ an ordinary or partial differential equation.
An ordinary differential equation
>>> def _ode_rule(m, s, t):
... if t == 0:
- ... return Constraint.Skip
+ ... return pyo.Constraint.Skip
... return m.dxdt[s, t] == m.x[s, t]**2
- >>> model.ode = Constraint(model.s, model.t, rule=_ode_rule)
+ >>> model.ode = pyo.Constraint(model.s, model.t, rule=_ode_rule)
A partial differential equation
>>> def _pde_rule(m, t, l):
... if t == 0 or l == m.l.first() or l == m.l.last():
- ... return Constraint.Skip
+ ... return pyo.Constraint.Skip
... return m.dydt[t, l] == m.dydl2[t, l]
- >>> model.pde = Constraint(model.t, model.l, rule=_pde_rule)
+ >>> model.pde = pyo.Constraint(model.t, model.l, rule=_pde_rule)
-By default, a :py:class:`Constraint` declared over a
+By default, a :py:class:`.Constraint` declared over a
:py:class:`ContinuousSet` will be applied at every
discretization point contained in the set. Often a modeler does not want to
enforce a differential equation at one or both boundaries of a continuous
domain. This may be addressed explicitly in the
-:py:class:`Constraint` declaration using
+:py:class:`.Constraint` declaration using
``Constraint.Skip`` as shown above. Alternatively, the desired constraints can
be deactivated just before the model is sent to a solver as shown below.
@@ -244,11 +247,11 @@ be deactivated just before the model is sent to a solver as shown below.
>>> def _ode_rule(m, s, t):
... return m.dxdt[s, t] == m.x[s, t]**2
- >>> model.ode = Constraint(model.s, model.t, rule=_ode_rule)
+ >>> model.ode = pyo.Constraint(model.s, model.t, rule=_ode_rule)
>>> def _pde_rule(m, t, l):
... return m.dydt[t, l] == m.dydl2[t, l]
- >>> model.pde = Constraint(model.t, model.l, rule=_pde_rule)
+ >>> model.pde = pyo.Constraint(model.t, model.l, rule=_pde_rule)
Declare other model components and apply a discretization transformation
...
@@ -287,18 +290,19 @@ Declaring Integrals
equations.
.. autoclass:: pyomo.dae.Integral
+ :noindex:
:members:
Declaring an :py:class:`Integral` component is similar to
-declaring an :py:class:`Expression` component. A
+declaring an :py:class:`.Expression` component. A
simple example is shown below:
.. doctest::
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.time = ContinuousSet(bounds=(0,10))
- >>> model.X = Var(model.time)
- >>> model.scale = Param(initialize=1E-3)
+ >>> model.X = pyo.Var(model.time)
+ >>> model.scale = pyo.Param(initialize=1E-3)
>>> def _intX(m,t):
... return m.X[t]
@@ -306,7 +310,7 @@ simple example is shown below:
>>> def _obj(m):
... return m.scale*m.intX
- >>> model.obj = Objective(rule=_obj)
+ >>> model.obj = pyo.Objective(rule=_obj)
Notice that the positional arguments supplied to the
:py:class:`Integral` declaration must include all indices
@@ -322,7 +326,7 @@ is being evaluated over. This is done using the 'wrt' keyword argument.
ensure consistency in the ordering and dimension of the indexing sets
After an :py:class:`Integral` has been declared, it can be
-used just like a Pyomo :py:class:`Expression`
+used just like a Pyomo :py:class:`.Expression`
component and can be included in constraints or the objective function as shown
above.
@@ -338,20 +342,20 @@ positional argument. This should become more clear with the following example
showing a double integral over the
:py:class:`ContinuousSet` components ``model.t1`` and
``model.t2``. In addition, the expression is also indexed by the
-:py:class:`Set` ``model.s``. The mathematical representation
+:py:class:`.Set` ``model.s``. The mathematical representation
and implementation in Pyomo are shown below:
.. math::
- \sum_{s} \int_{t_2} \int_{t_1} \! X(t_1, t_2, s) \, dt_1 \, dt_2
+ \sum_{s} \int_{t_2} \int_{t_1} \! X(t_1, t_2, s) \, dt_1 \, dt_2
.. doctest::
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.t1 = ContinuousSet(bounds=(0, 10))
>>> model.t2 = ContinuousSet(bounds=(-1, 1))
- >>> model.s = Set(initialize=['A', 'B', 'C'])
+ >>> model.s = pyo.Set(initialize=['A', 'B', 'C'])
- >>> model.X = Var(model.t1, model.t2, model.s)
+ >>> model.X = pyo.Var(model.t1, model.t2, model.s)
>>> def _intX1(m, t1, t2, s):
... return m.X[t1, t2, s]
@@ -364,7 +368,7 @@ and implementation in Pyomo are shown below:
>>> def _obj(m):
... return sum(m.intX2[k] for k in m.s)
- >>> model.obj = Objective(rule=_obj)
+ >>> model.obj = pyo.Objective(rule=_obj)
Discretization Transformations
------------------------------
@@ -399,18 +403,20 @@ called Implicit or Backward Euler) has been implemented. The
discretization equations for this method are shown below:
.. math::
- \begin{array}{l}
+ :nowrap:
+
+ \[\begin{array}{l}
\mathrm{Given: } \\
\frac{dx}{dt} = f(t, x) , \quad x(t_0) = x_{0} \\
\text{discretize $t$ and $x$ such that } \\
x(t_0 + kh) = x_{k} \\
x_{k + 1} = x_{k} + h * f(t_{k + 1}, x_{k + 1}) \\
t_{k + 1} = t_{k} + h
- \end{array}
+ \end{array}\]
where :math:`h` is the step size between discretization points or the size of
each finite element. These equations are generated automatically as
-:py:class:`Constraints` when the backward
+:py:class:`Constraints<.Constraint>` when the backward
difference method is applied to a Pyomo model.
There are several discretization options available to a
@@ -454,25 +460,25 @@ method. The code also shows how to add a constraint to a discretized model.
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.time = ContinuousSet(bounds=(0, 10))
- >>> model.x1 = Var(model.time, bounds=(-10, 10))
+ >>> model.x1 = pyo.Var(model.time, bounds=(-10, 10))
>>> model.dx1 = DerivativeVar(model.x1)
.. doctest::
:skipif: not ipopt_available
Discretize model using Backward Difference method
- >>> discretizer = TransformationFactory('dae.finite_difference')
+ >>> discretizer = pyo.TransformationFactory('dae.finite_difference')
>>> discretizer.apply_to(model,nfe=20,wrt=model.time,scheme='BACKWARD')
Add another constraint to discretized model
>>> def _sum_limit(m):
... return sum(m.x1[i] for i in m.time) <= 50
- >>> model.con_sum_limit = Constraint(rule=_sum_limit)
+ >>> model.con_sum_limit = pyo.Constraint(rule=_sum_limit)
Solve discretized model
- >>> solver = SolverFactory('ipopt')
+ >>> solver = pyo.SolverFactory('ipopt')
>>> results = solver.solve(model)
Collocation Transformation
@@ -522,26 +528,26 @@ function to a discretized model.
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.time = ContinuousSet(bounds=(0, 10))
- >>> model.x = Var(model.time, bounds=(-10, 10))
+ >>> model.x = pyo.Var(model.time, bounds=(-10, 10))
>>> model.dx = DerivativeVar(model.x)
- >>> model.x_ref = Param(initialize=5)
+ >>> model.x_ref = pyo.Param(initialize=5)
.. doctest::
:skipif: not ipopt_available
Discretize model using Radau Collocation
- >>> discretizer = TransformationFactory('dae.collocation')
+ >>> discretizer = pyo.TransformationFactory('dae.collocation')
>>> discretizer.apply_to(model,nfe=20,ncp=6,scheme='LAGRANGE-RADAU')
Add objective function after model has been discretized
>>> def obj_rule(m):
... return sum((m.x[i]-m.x_ref)**2 for i in m.time)
- >>> model.obj = Objective(rule=obj_rule)
+ >>> model.obj = pyo.Objective(rule=obj_rule)
Solve discretized model
- >>> solver = SolverFactory('ipopt')
+ >>> solver = pyo.SolverFactory('ipopt')
>>> results = solver.solve(model)
Restricting Optimal Control Profiles
@@ -556,23 +562,24 @@ transformation to reduce the number of free collocation points within a finite
element for a particular variable.
.. autoclass:: pyomo.dae.plugins.colloc.Collocation_Discretization_Transformation
- :members: reduce_collocation_points
+ :noindex:
+ :members: reduce_collocation_points
An example of using this function is shown below:
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.time = ContinuousSet(bounds=(0, 10))
- >>> model.x = Var(model.time, bounds=(-10, 10))
+ >>> model.x = pyo.Var(model.time, bounds=(-10, 10))
>>> model.dx = DerivativeVar(model.x)
- >>> model.x_ref = Param(initialize=5)
- >>> model.u = Var(model.time)
+ >>> model.x_ref = pyo.Param(initialize=5)
+ >>> model.u = pyo.Var(model.time)
.. doctest::
- >>> discretizer = TransformationFactory('dae.collocation')
+ >>> discretizer = pyo.TransformationFactory('dae.collocation')
>>> discretizer.apply_to(model, nfe=10, ncp=6)
>>> model = discretizer.reduce_collocation_points(model,
... var=model.u,
@@ -607,13 +614,13 @@ numerical method can be applied with different resolutions:
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.t1 = ContinuousSet(bounds=(0, 10))
>>> model.t2 = ContinuousSet(bounds=(-2, 2))
.. doctest::
- >>> discretizer = TransformationFactory('dae.finite_difference')
+ >>> discretizer = pyo.TransformationFactory('dae.finite_difference')
>>> discretizer.apply_to(model,wrt=model.t1,nfe=10)
>>> discretizer.apply_to(model,wrt=model.t2,nfe=100)
@@ -626,13 +633,13 @@ difference method to another
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.t1 = ContinuousSet(bounds=(0, 10))
>>> model.t2 = ContinuousSet(bounds=(-2, 2))
.. doctest::
- >>> discretizer = TransformationFactory('dae.finite_difference')
+ >>> discretizer = pyo.TransformationFactory('dae.finite_difference')
>>> discretizer.apply_to(model,wrt=model.t1,scheme='FORWARD')
>>> discretizer.apply_to(model,wrt=model.t2,scheme='CENTRAL')
@@ -642,15 +649,15 @@ discretizations. For example:
.. doctest::
:hide:
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
>>> model.t1 = ContinuousSet(bounds=(0, 10))
>>> model.t2 = ContinuousSet(bounds=(-2, 2))
.. doctest::
- >>> disc_fe = TransformationFactory('dae.finite_difference')
+ >>> disc_fe = pyo.TransformationFactory('dae.finite_difference')
>>> disc_fe.apply_to(model,wrt=model.t1,nfe=10)
- >>> disc_col = TransformationFactory('dae.collocation')
+ >>> disc_col = pyo.TransformationFactory('dae.collocation')
>>> disc_col.apply_to(model,wrt=model.t2,nfe=10,ncp=5)
If the user would like to apply the same discretization to all
@@ -722,7 +729,8 @@ packages.
order to use this class.
.. autoclass:: pyomo.dae.Simulator
- :members:
+ :noindex:
+ :members:
.. note::
Any keyword options supported by the integrator may be specified as
@@ -738,7 +746,7 @@ supported by CasADi. A list of available integrators for each package is
given below. Please refer to the `SciPy
`_
and `CasADi
-`_ documentation directly for the most up-to-date information about
+`_ documentation directly for the most up-to-date information about
these packages and for more information about the various integrators and
options.
@@ -766,24 +774,26 @@ Using the Simulator
We now show how to use the Simulator to simulate the following system of ODEs:
.. math::
- \begin{array}{l}
+ :nowrap:
+
+ \[\begin{array}{l}
\frac{d\theta}{dt} = \omega \\
\frac{d\omega}{dt} = -b*\omega -c*sin(\theta)
- \end{array}
+ \end{array}\]
We begin by formulating the model using pyomo.DAE
.. doctest::
- >>> m = ConcreteModel()
+ >>> m = pyo.ConcreteModel()
>>> m.t = ContinuousSet(bounds=(0.0, 10.0))
- >>> m.b = Param(initialize=0.25)
- >>> m.c = Param(initialize=5.0)
+ >>> m.b = pyo.Param(initialize=0.25)
+ >>> m.c = pyo.Param(initialize=5.0)
- >>> m.omega = Var(m.t)
- >>> m.theta = Var(m.t)
+ >>> m.omega = pyo.Var(m.t)
+ >>> m.theta = pyo.Var(m.t)
>>> m.domegadt = DerivativeVar(m.omega, wrt=m.t)
>>> m.dthetadt = DerivativeVar(m.theta, wrt=m.t)
@@ -793,12 +803,12 @@ We begin by formulating the model using pyomo.DAE
>>> m.theta[0].fix(3.14 - 0.1)
>>> def _diffeq1(m, t):
- ... return m.domegadt[t] == -m.b * m.omega[t] - m.c * sin(m.theta[t])
- >>> m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ ... return m.domegadt[t] == -m.b * m.omega[t] - m.c * pyo.sin(m.theta[t])
+ >>> m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
>>> def _diffeq2(m, t):
... return m.dthetadt[t] == m.omega[t]
- >>> m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ >>> m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
Notice that the initial conditions are set by `fixing` the values of
``m.omega`` and ``m.theta`` at t=0 instead of being specified as extra
@@ -856,16 +866,16 @@ example.
.. doctest::
- >>> m = ConcreteModel()
+ >>> m = pyo.ConcreteModel()
>>> m.t = ContinuousSet(bounds=(0.0, 20.0))
Time-varying inputs
- >>> m.b = Var(m.t)
- >>> m.c = Param(m.t, default=5.0)
+ >>> m.b = pyo.Var(m.t)
+ >>> m.c = pyo.Param(m.t, default=5.0)
- >>> m.omega = Var(m.t)
- >>> m.theta = Var(m.t)
+ >>> m.omega = pyo.Var(m.t)
+ >>> m.theta = pyo.Var(m.t)
>>> m.domegadt = DerivativeVar(m.omega, wrt=m.t)
>>> m.dthetadt = DerivativeVar(m.theta, wrt=m.t)
@@ -876,19 +886,19 @@ example.
>>> def _diffeq1(m, t):
... return m.domegadt[t] == -m.b[t] * m.omega[t] - \
- ... m.c[t] * sin(m.theta[t])
- >>> m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ ... m.c[t] * pyo.sin(m.theta[t])
+ >>> m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
>>> def _diffeq2(m, t):
... return m.dthetadt[t] == m.omega[t]
- >>> m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ >>> m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
Specifying the piecewise constant inputs
>>> b_profile = {0: 0.25, 15: 0.025}
>>> c_profile = {0: 5.0, 7: 50}
Declaring a Pyomo Suffix to pass the time-varying inputs to the Simulator
- >>> m.var_input = Suffix(direction=Suffix.LOCAL)
+ >>> m.var_input = pyo.Suffix(direction=pyo.Suffix.LOCAL)
>>> m.var_input[m.b] = b_profile
>>> m.var_input[m.c] = c_profile
@@ -923,7 +933,7 @@ returned from the simulator. An example using this function is shown below
... varying_inputs=m.var_input) # doctest: +SKIP
Discretize the model using Orthogonal Collocation
- >>> discretizer = TransformationFactory('dae.collocation')
+ >>> discretizer = pyo.TransformationFactory('dae.collocation')
>>> discretizer.apply_to(m, nfe=10, ncp=3)
Initialize the discretized model using the simulator profiles
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/concepts.rst b/doc/OnlineDocs/explanation/modeling/gdp/concepts.rst
similarity index 93%
rename from doc/OnlineDocs/modeling_extensions/gdp/concepts.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/concepts.rst
index 95629bc48fd..952be873767 100644
--- a/doc/OnlineDocs/modeling_extensions/gdp/concepts.rst
+++ b/doc/OnlineDocs/explanation/modeling/gdp/concepts.rst
@@ -11,21 +11,24 @@ Generalized Disjunctive Programming (GDP) provides a way to bridge high-level pr
The GDP standard form from the :ref:`index page ` is repeated below.
.. math::
+ :nowrap:
- \min\ obj = &\ f(x, z) \\
- \text{s.t.} \quad &\ Ax+Bz \leq d\\
- &\ g(x,z) \leq 0\\
- &\ \bigvee_{i\in D_k} \left[
+ \[\begin{array}{ll}
+ \min & f(x, z) \\
+ \mathrm{s.t.} \quad & Ax+Bz \leq d \\
+ & g(x,z) \leq 0 \\
+ & \bigvee_{i\in D_k} \left[
\begin{gathered}
Y_{ik} \\
M_{ik} x + N_{ik} z \leq e_{ik} \\
- r_{ik}(x,z)\leq 0\\
+ r_{ik}(x,z)\leq 0 \\
\end{gathered}
- \right] \quad k \in K\\
- &\ \Omega(Y) = True \\
- &\ x \in X \subseteq \mathbb{R}^n\\
- &\ Y \in \{True, False\}^{p}\\
- &\ z \in Z \subseteq \mathbb{Z}^m
+ \right] \quad k \in K \\
+ & \Omega(Y) = True \\
+ & x \in X \subseteq \mathbb{R}^n \\
+ & Y \in \{True, False\}^{p} \\
+ & z \in Z \subseteq \mathbb{Z}^m
+ \end{array}\]
Original support in Pyomo.GDP focused on the disjuncts and disjunctions, allowing the modelers to group relational expressions in disjuncts, with disjunctions describing logical-OR relationships between the groupings.
As a result, we implemented the ``Disjunct`` and ``Disjunction`` objects before ``BooleanVar`` and the rest of the logical expression system.
@@ -37,14 +40,16 @@ Disjuncts
Disjuncts represent groupings of relational expressions (e.g. algebraic constraints) summarized by a Boolean indicator variable :math:`Y` through implication:
.. math::
+ :nowrap:
+ \[
\left.
\begin{aligned}
& Y_{ik} \Rightarrow & M_{ik} x + N_{ik} z &\leq e_{ik}\\
& Y_{ik} \Rightarrow & r_{ik}(x,z) &\leq 0
\end{aligned}
\right.\qquad \forall i \in D_k, \forall k \in K
-
+ \]
Logically, this means that if :math:`Y_{ik} = True`, then the constraints :math:`M_{ik} x + N_{ik} z \leq e_{ik}` and :math:`r_{ik}(x,z) \leq 0` must be satisfied.
However, if :math:`Y_{ik} = False`, then the corresponding constraints are ignored.
@@ -59,7 +64,9 @@ Disjunctions describe a logical *OR* relationship between two or more Disjuncts.
The simplest and most common case is a 2-term disjunction:
.. math::
+ :nowrap:
+ \[
\left[\begin{gathered}
Y_1 \\
\exp(x_2) - 1 = x_1 \\
@@ -71,6 +78,7 @@ The simplest and most common case is a 2-term disjunction:
x_1 = x_2 = 0
\end{gathered}
\right]
+ \]
The disjunction above describes the selection between two units in a process network.
diff --git a/doc/OnlineDocs/explanation/modeling/gdp/index.rst b/doc/OnlineDocs/explanation/modeling/gdp/index.rst
new file mode 100644
index 00000000000..ee69f99668e
--- /dev/null
+++ b/doc/OnlineDocs/explanation/modeling/gdp/index.rst
@@ -0,0 +1,80 @@
+.. _gdp-main-page:
+
+***********************************
+Generalized Disjunctive Programming
+***********************************
+
+.. image:: /../logos/gdp/Pyomo-GDP-150.png
+ :scale: 35%
+ :align: right
+ :class: no-scaled-link
+
+The Pyomo.GDP modeling extension [PyomoGDP-proceedings]_
+[PyomoGDP-paper]_ provides support for Generalized Disjunctive
+Programming (GDP) [RG94]_, an extension of Disjunctive Programming
+[Bal85]_ from the operations research community to include nonlinear
+relationships. The classic form for a GDP is given by:
+
+.. math::
+ :nowrap:
+
+ \[\begin{array}{ll}
+ \min & f(x, z) \\
+ \mathrm{s.t.} \quad & Ax+Bz \leq d\\
+ & g(x,z) \leq 0\\
+ & \bigvee_{i\in D_k} \left[
+ \begin{gathered}
+ Y_{ik} \\
+ M_{ik} x + N_{ik} z \leq e_{ik} \\
+ r_{ik}(x,z)\leq 0\\
+ \end{gathered}
+ \right] \quad k \in K\\
+ & \Omega(Y) = True \\
+ & x \in X \subseteq \mathbb{R}^n\\
+ & Y \in \{True, False\}^{p}\\
+ & z \in Z \subseteq \mathbb{Z}^m
+ \end{array}\]
+
+Here, we have the minimization of an objective :math:`f(x, z)` subject to global linear constraints :math:`Ax+Bz \leq d` and nonlinear constraints :math:`g(x,z) \leq 0`, with conditional linear constraints :math:`M_{ik} x + N_{ik} z \leq e_{ik}` and nonlinear constraints :math:`r_{ik}(x,z)\leq 0`.
+These conditional constraints are collected into disjuncts :math:`D_k`, organized into disjunctions :math:`K`. Finally, there are logical propositions :math:`\Omega(Y) = True`.
+Decision/state variables can be continuous :math:`x`, Boolean :math:`Y`, and/or integer :math:`z`.
+
+GDP is useful to model discrete decisions that have implications on the
+system behavior [GT13]_. For example, in process design, a
+disjunction may model the choice between processes A and B. If A is
+selected, then its associated equations and inequalities will apply;
+otherwise, if B is selected, then its respective constraints should be
+enforced.
+
+Modelers often ask to model if-then-else relationships.
+These can be expressed as a disjunction as follows:
+
+.. math::
+ :nowrap:
+
+ \begin{gather*}
+ \left[\begin{gathered}
+ Y_1 \\
+ \text{constraints} \\
+ \text{for }\textit{then}
+ \end{gathered}\right]
+ \vee
+ \left[\begin{gathered}
+ Y_2 \\
+ \text{constraints} \\
+ \text{for }\textit{else}
+ \end{gathered}\right] \\
+ Y_1 \veebar Y_2
+ \end{gather*}
+
+Here, if the Boolean :math:`Y_1` is ``True``, then the constraints in the first disjunct are enforced; otherwise, the constraints in the second disjunct are enforced.
+The following sections describe the key concepts, modeling, and solution approaches available for Generalized Disjunctive Programming.
+
+.. toctree::
+ :caption: Pyomo.GDP Contents
+ :maxdepth: 2
+
+ concepts
+ modeling
+ solving
+
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/modeling.rst b/doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
similarity index 90%
rename from doc/OnlineDocs/modeling_extensions/gdp/modeling.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
index 996ebcb0366..6abb456c93a 100644
--- a/doc/OnlineDocs/modeling_extensions/gdp/modeling.rst
+++ b/doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
@@ -17,11 +17,6 @@ Modeling in Pyomo.GDP
from pyomo.gdp import Disjunct, Disjunction
from pyomo.core.plugins.transform.logical_to_linear import update_boolean_vars_from_binary
- # This is to make unicode comparison work in python 2.7.
- import sys
- if sys.version[0] == '2':
- reload(sys)
- sys.setdefaultencoding("utf-8")
Disjunctions
============
@@ -220,13 +215,36 @@ logical propositions.
Here, we demonstrate this capability with a toy example:
.. math::
-
- \min~&x\\
- \text{s.t.}~&\left[\begin{gathered}Y_1\\x \geq 2\end{gathered}\right] \vee \left[\begin{gathered}Y_2\\x \geq 3\end{gathered}\right]\\
- &\left[\begin{gathered}Y_3\\x \leq 8\end{gathered}\right] \vee \left[\begin{gathered}Y_4\\x = 2.5\end{gathered}\right] \\
- &Y_1 \veebar Y_2\\
- &Y_3 \veebar Y_4\\
- &Y_1 \Rightarrow Y_4
+ :nowrap:
+
+ \[\begin{array}{ll}
+ \min & x \\
+ \text{s.t.} & \left[
+ \begin{gathered}
+ Y_1\\
+ x \geq 2
+ \end{gathered}
+ \right] \vee \left[
+ \begin{gathered}
+ Y_2 \\
+ x \geq 3
+ \end{gathered}
+ \right]\\
+ & \left[
+ \begin{gathered}
+ Y_3 \\
+ x \leq 8
+ \end{gathered}
+ \right] \vee \left[
+ \begin{gathered}
+ Y_4 \\
+ x = 2.5
+ \end{gathered}
+ \right] \\
+ & Y_1 \veebar Y_2 \\
+ & Y_3 \veebar Y_4 \\
+ & Y_1 \Rightarrow Y_4
+ \end{array}\]
.. doctest::
:skipif: not glpk_available
@@ -302,9 +320,9 @@ Expressions within CP-type operators
Here, augmented variables may be automatically added to the model as follows:
.. math::
- \text{atleast}(3, &Y_1, Y_A, Y_B, Y_6)\\
- &Y_A \Leftrightarrow Y_2 \vee Y_3\\
- &Y_B \Leftrightarrow (Y_4 \Rightarrow Y_5)
+ \text{atleast}(3, Y_1, Y_A, Y_B, Y_6)\\
+ Y_A \Leftrightarrow Y_2 \vee Y_3\\
+ Y_B \Leftrightarrow (Y_4 \Rightarrow Y_5)
.. code::
@@ -366,22 +384,22 @@ The following models all work and are equivalent for :math:`\left[x = 0\right] \
Option 1: Rule-based construction
- >>> from pyomo.environ import *
- >>> from pyomo.gdp import *
- >>> model = ConcreteModel()
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.gdp import Disjunct, Disjunction
+ >>> model = pyo.ConcreteModel()
- >>> model.x = Var()
- >>> model.y = Var()
+ >>> model.x = pyo.Var()
+ >>> model.y = pyo.Var()
>>> # Two conditions
>>> def _d(disjunct, flag):
... model = disjunct.model()
... if flag:
... # x == 0
- ... disjunct.c = Constraint(expr=model.x == 0)
+ ... disjunct.c = pyo.Constraint(expr=model.x == 0)
... else:
... # y == 0
- ... disjunct.c = Constraint(expr=model.y == 0)
+ ... disjunct.c = pyo.Constraint(expr=model.y == 0)
>>> model.d = Disjunct([0,1], rule=_d)
>>> # Define the disjunction
@@ -391,29 +409,29 @@ The following models all work and are equivalent for :math:`\left[x = 0\right] \
Option 2: Explicit disjuncts
- >>> from pyomo.environ import *
- >>> from pyomo.gdp import *
- >>> model = ConcreteModel()
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.gdp import Disjunct, Disjunction
+ >>> model = pyo.ConcreteModel()
- >>> model.x = Var()
- >>> model.y = Var()
+ >>> model.x = pyo.Var()
+ >>> model.y = pyo.Var()
>>> model.fix_x = Disjunct()
- >>> model.fix_x.c = Constraint(expr=model.x == 0)
+ >>> model.fix_x.c = pyo.Constraint(expr=model.x == 0)
>>> model.fix_y = Disjunct()
- >>> model.fix_y.c = Constraint(expr=model.y == 0)
+ >>> model.fix_y.c = pyo.Constraint(expr=model.y == 0)
>>> model.c = Disjunction(expr=[model.fix_x, model.fix_y])
Option 3: Implicit disjuncts (disjunction rule returns a list of
expressions or a list of lists of expressions)
- >>> from pyomo.environ import *
- >>> from pyomo.gdp import *
- >>> model = ConcreteModel()
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.gdp import Disjunction
+ >>> model = pyo.ConcreteModel()
- >>> model.x = Var()
- >>> model.y = Var()
+ >>> model.x = pyo.Var()
+ >>> model.y = pyo.Var()
>>> model.c = Disjunction(expr=[model.x == 0, model.y == 0])
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/solving.rst b/doc/OnlineDocs/explanation/modeling/gdp/solving.rst
similarity index 69%
rename from doc/OnlineDocs/modeling_extensions/gdp/solving.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/solving.rst
index 9fea90ebf5f..eb8ecf38eda 100644
--- a/doc/OnlineDocs/modeling_extensions/gdp/solving.rst
+++ b/doc/OnlineDocs/explanation/modeling/gdp/solving.rst
@@ -70,6 +70,7 @@ also be created, as described in :ref:`gdp-advanced-examples`.
Following solution of the GDP model, values of the Boolean variables may be updated from their algebraic binary counterparts using the ``update_boolean_vars_from_binary()`` function.
.. autofunction:: pyomo.core.plugins.transform.logical_to_linear.update_boolean_vars_from_binary
+ :noindex:
Factorable Programming
^^^^^^^^^^^^^^^^^^^^^^
@@ -105,11 +106,16 @@ doing so are the (included) Big-M and Hull reformulations.
Big-M (BM) Reformulation
^^^^^^^^^^^^^^^^^^^^^^^^
-The Big-M reformulation\ [#gdp-bm]_ results in a smaller transformed model, avoiding the need to add extra variables; however, it yields a looser continuous relaxation.
-By default, the BM transformation will estimate reasonably tight M values for you if variables are bounded.
-For nonlinear models where finite expression bounds may be inferred from variable bounds, the BM transformation may also be able to automatically compute M values for you.
-For all other models, you will need to provide the M values through a "BigM" Suffix, or through the `bigM` argument to the transformation.
-We will raise a ``GDP_Error`` for missing M values.
+The Big-M reformulation\ [NW88]_ results in a smaller transformed
+model, avoiding the need to add extra variables; however, it yields a
+looser continuous relaxation. By default, the BM transformation will
+estimate reasonably tight M values for you if variables are bounded.
+For nonlinear models where finite expression bounds may be inferred from
+variable bounds, the BM transformation may also be able to automatically
+compute M values for you. For all other models, you will need to
+provide the M values through a "BigM" Suffix, or through the `bigM`
+argument to the transformation. We will raise a ``GDP_Error`` for
+missing M values.
To apply the BM reformulation within a python script, use:
@@ -122,9 +128,12 @@ From the Pyomo command line, include the ``--transform pyomo.gdp.bigm`` option.
Multiple Big-M (MBM) Reformulation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-We also implement the multiple-parameter Big-M (MBM) approach described in literature\ [#gdp-mbm]_.
-By default, the MBM transformation will solve continuous subproblems in order to calculate M values.
-This process can be time-consuming, so the transformation also provides a method to export the M values used as a dictionary and allows for M values to be provided through the `bigM` argument.
+We also implement the multiple-parameter Big-M (MBM) approach described
+in literature\ [TG15]_. By default, the MBM transformation will solve
+continuous subproblems in order to calculate M values. This process can
+be time-consuming, so the transformation also provides a method to
+export the M values used as a dictionary and allows for M values to be
+provided through the `bigM` argument.
For example, to apply the transformation and store the M values, use:
@@ -168,9 +177,12 @@ From the Pyomo command line, include the ``--transform pyomo.gdp.hull`` option.
Hybrid BM/HR Reformulation
^^^^^^^^^^^^^^^^^^^^^^^^^^
-An experimental (for now) implementation of the cutting plane approach described in literature\ [#gdp-cuttingplanes]_ is provided for linear GDP models.
-The transformation augments the BM reformulation by a set of cutting planes generated from the HR model by solving separation problems.
-This gives a model that is not as large as the HR, but with a stronger continuous relaxation than the BM.
+An experimental (for now) implementation of the cutting plane approach
+described in literature\ [SG03]_ is provided for linear GDP models.
+The transformation augments the BM reformulation by a set of cutting
+planes generated from the HR model by solving separation problems. This
+gives a model that is not as large as the HR, but with a stronger
+continuous relaxation than the BM.
This transformation is accessible via:
@@ -185,17 +197,4 @@ Pyomo includes the contributed GDPopt solver, which can directly solve
GDP models. Its usage is described within the :ref:`contributed
packages documentation `.
-References
-==========
-.. [#gdp-pse-paper] Chen, Q., Johnson, E. S., Siirola, J. D., & Grossmann, I. E. (2018). Pyomo.GDP: Disjunctive Models in Python. In M. R. Eden, M. G. Ierapetritou, & G. P. Towler (Eds.), *Proceedings of the 13th International Symposium on Process Systems Engineering* (pp. 889–894). San Diego: Elsevier B.V. https://doi.org/10.1016/B978-0-444-64241-7.50143-9
-
-.. [#gdp-main-paper] Chen, Q., Johnson, E. S., Bernal, D. E., Valentin, R., Kale, S., Bates, J., Siirola, J. D. and Grossmann, I. E. (2021). Pyomo.GDP: an ecosystem for logic based modeling and optimization development, *Optimization and Engineering* (pp. 1-36).https://doi.org/10.1007/s11081-021-09601-7
-
-.. [#gdp-review-2013] Grossmann, I. E., & Trespalacios, F. (2013). Systematic modeling of discrete-continuous optimization models through generalized disjunctive programming. *AIChE Journal*, 59(9), 3276–3295. https://doi.org/10.1002/aic.14088
-
-.. [#gdp-mbm] Trespalacios, F., & Grossmann, I. E. (2015). Improved Big-M reformulation for generalized disjunctive programs. *Computers and Chemical Engineering*, 76, 98–103. https://doi.org/10.1016/j.compchemeng.2015.02.013
-
-.. [#gdp-bm] Nemhauser, G. L., & Wolsey, L. A. (1988). *Integer and combinatorial optimization*. New York: Wiley.
-
-.. [#gdp-cuttingplanes] Sawaya, N. W., & Grossmann, I. E. (2003). A cutting plane method for solving linear generalized disjunctive programming problems. *Computer Aided Chemical Engineering*, 15(C), 1032–1037. https://doi.org/10.1016/S1570-7946(03)80444-3
diff --git a/doc/OnlineDocs/explanation/modeling/index.rst b/doc/OnlineDocs/explanation/modeling/index.rst
new file mode 100644
index 00000000000..f23f5421322
--- /dev/null
+++ b/doc/OnlineDocs/explanation/modeling/index.rst
@@ -0,0 +1,25 @@
+Modeling in Pyomo
+=================
+
+.. toctree::
+ :maxdepth: 1
+
+ math_programming/index
+ dae
+ gdp/index
+ mpec
+ network
+ units
+
+
+..
+ Reorganization notes:
+
+ `Modeling in Pyomo`
+ `Math Programming`
+ `GDP`
+ `DAE`
+ `Network`
+ `Piecewise Linear`
+ `Constraint Programming`
+ `Units of Measure`
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Constraints.rst b/doc/OnlineDocs/explanation/modeling/math_programming/constraints.rst
similarity index 84%
rename from doc/OnlineDocs/pyomo_modeling_components/Constraints.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/constraints.rst
index 0cc42cb2abe..fdda70fa28d 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Constraints.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/constraints.rst
@@ -6,7 +6,7 @@ that are created using a rule, which is a Python function. For example,
if the variable ``model.x`` has the indexes 'butter' and 'scones', then
this constraint limits the sum over these indexes to be exactly three:
-.. literalinclude:: ../src/scripting/spy4Constraints_Constraint_example.spy
+.. literalinclude:: /src/scripting/spy4Constraints_Constraint_example.spy
:language: python
Instead of expressions involving equality (==) or inequalities (`<=` or
@@ -16,7 +16,7 @@ lb `<=` expr `<=` ub. Variables can appear only in the middle expr. For
example, the following two constraint declarations have the same
meaning:
-.. literalinclude:: ../src/scripting/spy4Constraints_Inequality_constraints_2expressions.spy
+.. literalinclude:: /src/scripting/spy4Constraints_Inequality_constraints_2expressions.spy
:language: python
For this simple example, it would also be possible to declare
@@ -30,7 +30,7 @@ interpreted as placing a budget of :math:`i` on the
:math:`i^{\mbox{th}}` item to buy where the cost per item is given by
the parameter ``model.a``:
-.. literalinclude:: ../src/scripting/spy4Constraints_Passing_elements_crossproduct.spy
+.. literalinclude:: /src/scripting/spy4Constraints_Passing_elements_crossproduct.spy
:language: python
.. note::
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Expressions.rst b/doc/OnlineDocs/explanation/modeling/math_programming/expressions.rst
similarity index 90%
rename from doc/OnlineDocs/pyomo_modeling_components/Expressions.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/expressions.rst
index 16c206e2fe8..f272607718d 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Expressions.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/expressions.rst
@@ -20,7 +20,7 @@ possible to build up expressions. The following example illustrates
this, along with a reference to global Python data in the form of a
Python variable called ``switch``:
-.. literalinclude:: ../src/scripting/spy4Expressions_Buildup_expression_switch.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Buildup_expression_switch.spy
:language: python
In this example, the constraint that is generated depends on the value
@@ -33,7 +33,7 @@ otherwise, the ``model.d`` term is not present.
Because model elements result in expressions, not values, the
following does not work as expected in an abstract model!
- .. literalinclude:: ../src/scripting/spy4Expressions_Abstract_wrong_usage.spy
+ .. literalinclude:: /src/scripting/spy4Expressions_Abstract_wrong_usage.spy
:language: python
The trouble is that ``model.d >= 2`` results in an expression, not
@@ -54,11 +54,11 @@ Pyomo has facilities to add piecewise constraints of the form y=f(x) for
a variety of forms of the function f.
The piecewise types other than SOS2, BIGM_SOS1, BIGM_BIN are implement
-as described in the paper [Vielma_et_al]_.
+as described in the paper [VAN10]_.
There are two basic forms for the declaration of the constraint:
-.. literalinclude:: ../src/scripting/spy4Expressions_Declare_piecewise_constraints.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Declare_piecewise_constraints.spy
:language: python
where ``pwconst`` can be replaced by a name appropriate for the
@@ -124,7 +124,7 @@ Keywords:
indexing set is used or when all indices use an identical piecewise
function). Examples:
- .. literalinclude:: ../src/scripting/spy4Expressions_f_rule_Function_examples.spy
+ .. literalinclude:: /src/scripting/spy4Expressions_f_rule_Function_examples.spy
:language: python
* **force_pw=True/False**
@@ -163,7 +163,7 @@ Keywords:
Here is an example of an assignment to a Python dictionary variable that
has keywords for a picewise constraint:
-.. literalinclude:: ../src/scripting/spy4Expressions_Keyword_assignment_example.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Keyword_assignment_example.spy
:language: python
Here is a simple example based on the example given earlier in
@@ -175,10 +175,10 @@ whimsically just to make the example. The important thing to note is
that variables that are going to appear as the independent variable in a
piecewise constraint must have bounds.
-.. literalinclude:: ../src/scripting/abstract2piece.py
+.. literalinclude:: /src/scripting/abstract2piece.py
:language: python
-A more advanced example is provided in abstract2piecebuild.py in
+A more advanced example is provided in ``abstract2piecebuild.py`` in
:ref:`BuildAction`.
``Expression`` Objects
@@ -193,13 +193,13 @@ variable x times the index. Later in the model file, just to illustrate
how to do it, the expression is changed but just for the first index to
be x squared.
-.. literalinclude:: ../src/scripting/spy4Expressions_Expression_objects_illustration.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Expression_objects_illustration.spy
:language: python
An alternative is to create Python functions that, potentially,
manipulate model objects. E.g., if you define a function
-.. literalinclude:: ../src/scripting/spy4Expressions_Define_python_function.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Define_python_function.spy
:language: python
You can call this function with or without Pyomo modeling components as
@@ -211,7 +211,7 @@ expression is used to generate another expression (e.g., f(model.x, 3) +
5), the initial expression is always cloned so that the new generated
expression is independent of the old. For example:
-.. literalinclude:: ../src/scripting/spy4Expressions_Generate_new_expression.spy
+.. literalinclude:: /src/scripting/spy4Expressions_Generate_new_expression.spy
:language: python
If you want to create an expression that is shared between other
diff --git a/doc/OnlineDocs/explanation/modeling/math_programming/index.rst b/doc/OnlineDocs/explanation/modeling/math_programming/index.rst
new file mode 100644
index 00000000000..bc4e7c1803d
--- /dev/null
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/index.rst
@@ -0,0 +1,14 @@
+Math Programming
+================
+
+.. toctree::
+ :maxdepth: 1
+
+ sets
+ parameters
+ variables
+ objectives
+ constraints
+ expressions
+ sos_constraints
+ suffixes
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Objectives.rst b/doc/OnlineDocs/explanation/modeling/math_programming/objectives.rst
similarity index 100%
rename from doc/OnlineDocs/pyomo_modeling_components/Objectives.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/objectives.rst
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Parameters.rst b/doc/OnlineDocs/explanation/modeling/math_programming/parameters.rst
similarity index 100%
rename from doc/OnlineDocs/pyomo_modeling_components/Parameters.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/parameters.rst
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Sets.rst b/doc/OnlineDocs/explanation/modeling/math_programming/sets.rst
similarity index 97%
rename from doc/OnlineDocs/pyomo_modeling_components/Sets.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/sets.rst
index 73c3539d79d..3689ff8cc43 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Sets.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/sets.rst
@@ -277,12 +277,12 @@ Consider the following simple version of minimum cost flow problem:
.. math::
:nowrap:
- \begin{array}{lll}
- \mbox{minimize} & \sum_{a \in \mathcal{A}} c_{a}x_{a} \\
- \mbox{subject to:} & S_{n} + \sum_{(i,n) \in \mathcal{A}}x_{(i,n)} & \\
- & -D_{n} - \sum_{(n,j) \in \mathcal{A}}x_{(n,j)} & n \in \mathcal{N} \\
- & x_{a} \geq 0, & a \in \mathcal{A}
- \end{array}
+ \[\begin{array}{lll}
+ \mbox{minimize} & \sum_{a \in \mathcal{A}} c_{a}x_{a} \\
+ \mbox{subject to:} & S_{n} + \sum_{(i,n) \in \mathcal{A}}x_{(i,n)} & \\
+ & -D_{n} - \sum_{(n,j) \in \mathcal{A}}x_{(n,j)} & n \in \mathcal{N} \\
+ & x_{a} \geq 0, & a \in \mathcal{A}
+ \end{array}\]
where
@@ -443,7 +443,7 @@ model is:
for this model, a toy data file (in AMPL "``.dat``" format) would be:
-.. literalinclude:: ../src/scripting/Isinglecomm.dat
+.. literalinclude:: /src/scripting/Isinglecomm.dat
:language: text
.. doctest::
diff --git a/doc/OnlineDocs/advanced_topics/sos_constraints.rst b/doc/OnlineDocs/explanation/modeling/math_programming/sos_constraints.rst
similarity index 100%
rename from doc/OnlineDocs/advanced_topics/sos_constraints.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/sos_constraints.rst
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Suffixes.rst b/doc/OnlineDocs/explanation/modeling/math_programming/suffixes.rst
similarity index 99%
rename from doc/OnlineDocs/pyomo_modeling_components/Suffixes.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/suffixes.rst
index e45fe2d74b7..e410374b274 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Suffixes.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/suffixes.rst
@@ -23,7 +23,7 @@ Suffix Notation and the Pyomo NL File Interface
-----------------------------------------------
The Suffix component used in Pyomo has been adapted from the suffix
-notation used in the modeling language AMPL [AMPL]_. Therefore, it
+notation used in the modeling language AMPL [FGK02]_. Therefore, it
follows naturally that AMPL style suffix functionality is fully
available using Pyomo's NL file interface. For information on AMPL style
suffixes the reader is referred to the AMPL website:
diff --git a/doc/OnlineDocs/pyomo_modeling_components/Variables.rst b/doc/OnlineDocs/explanation/modeling/math_programming/variables.rst
similarity index 88%
rename from doc/OnlineDocs/pyomo_modeling_components/Variables.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/variables.rst
index 7f7ee74af5f..58ccacc17da 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Variables.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/variables.rst
@@ -20,13 +20,13 @@ declaring a *singleton* (i.e. unindexed) variable named
``model.LumberJack`` that will take on real values between zero and 6
and it initialized to be 1.5:
-.. literalinclude:: ../src/scripting/spy4Variables_Declare_singleton_variable.spy
+.. literalinclude:: /src/scripting/spy4Variables_Declare_singleton_variable.spy
:language: python
Instead of the ``initialize`` option, initialization is sometimes done
with a Python assignment statement as in
-.. literalinclude:: ../src/scripting/spy4Variables_Assign_value.spy
+.. literalinclude:: /src/scripting/spy4Variables_Assign_value.spy
:language: python
For indexed variables, bounds and initial values are often specified by
@@ -36,7 +36,7 @@ followed by the indexes. This is illustrated in the following code
snippet that makes use of Python dictionaries declared as lb and ub that
are used by a function to provide bounds:
-.. literalinclude:: ../src/scripting/spy4Variables_Declare_bounds.spy
+.. literalinclude:: /src/scripting/spy4Variables_Declare_bounds.spy
:language: python
.. note::
diff --git a/doc/OnlineDocs/modeling_extensions/mpec.rst b/doc/OnlineDocs/explanation/modeling/mpec.rst
similarity index 100%
rename from doc/OnlineDocs/modeling_extensions/mpec.rst
rename to doc/OnlineDocs/explanation/modeling/mpec.rst
diff --git a/doc/OnlineDocs/modeling_extensions/network.rst b/doc/OnlineDocs/explanation/modeling/network.rst
similarity index 91%
rename from doc/OnlineDocs/modeling_extensions/network.rst
rename to doc/OnlineDocs/explanation/modeling/network.rst
index 3fce9448997..2c640eabe0a 100644
--- a/doc/OnlineDocs/modeling_extensions/network.rst
+++ b/doc/OnlineDocs/explanation/modeling/network.rst
@@ -29,10 +29,12 @@ Port
****
.. autoclass:: pyomo.network.Port
+ :noindex:
:members:
:exclude-members: construct, display
.. autoclass:: pyomo.network.port._PortData
+ :noindex:
:members:
:special-members: __getattr__
:exclude-members: set_value
@@ -43,14 +45,14 @@ concrete Pyomo model:
.. doctest::
- >>> from pyomo.environ import *
- >>> from pyomo.network import *
- >>> m = ConcreteModel()
- >>> m.x = Var()
- >>> m.y = Var(['a', 'b']) # can be indexed
- >>> m.z = Var()
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.network import Port
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var(['a', 'b']) # can be indexed
+ >>> m.z = pyo.Var()
>>> m.e = 5 * m.z # you can add Pyomo expressions too
- >>> m.w = Var()
+ >>> m.w = pyo.Var()
>>> m.p = Port()
>>> m.p.add(m.x) # implicitly name the port member "x"
@@ -62,10 +64,12 @@ Arc
***
.. autoclass:: pyomo.network.Arc
+ :noindex:
:members:
:exclude-members: construct
.. autoclass:: pyomo.network.arc._ArcData
+ :noindex:
:members:
:special-members: __getattr__
@@ -75,15 +79,15 @@ concrete Pyomo model:
.. doctest::
- >>> from pyomo.environ import *
- >>> from pyomo.network import *
- >>> m = ConcreteModel()
- >>> m.x = Var()
- >>> m.y = Var(['a', 'b'])
- >>> m.u = Var()
- >>> m.v = Var(['a', 'b'])
- >>> m.w = Var()
- >>> m.z = Var(['a', 'b']) # indexes need to match
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.network import Port, Arc
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var(['a', 'b'])
+ >>> m.u = pyo.Var()
+ >>> m.v = pyo.Var(['a', 'b'])
+ >>> m.w = pyo.Var()
+ >>> m.z = pyo.Var(['a', 'b']) # indexes need to match
>>> m.p = Port(initialize=[m.x, m.y])
>>> m.q = Port(initialize={"x": m.u, "y": m.v})
@@ -135,19 +139,19 @@ the arcs on a model:
.. doctest::
- >>> from pyomo.environ import *
- >>> from pyomo.network import *
- >>> m = ConcreteModel()
- >>> m.x = Var()
- >>> m.y = Var(['a', 'b'])
- >>> m.u = Var()
- >>> m.v = Var(['a', 'b'])
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.network import Port, Arc
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var(['a', 'b'])
+ >>> m.u = pyo.Var()
+ >>> m.v = pyo.Var(['a', 'b'])
>>> m.p = Port(initialize=[m.x, (m.y, Port.Extensive)]) # rules must match
>>> m.q = Port(initialize={"x": m.u, "y": (m.v, Port.Extensive)})
>>> m.a = Arc(source=m.p, destination=m.q)
- >>> TransformationFactory("network.expand_arcs").apply_to(m)
+ >>> pyo.TransformationFactory("network.expand_arcs").apply_to(m)
Sequential Decomposition
------------------------
@@ -297,19 +301,19 @@ class:
.. doctest::
:skipif: not __import__("pyomo.network").network.decomposition.imports_available
- >>> from pyomo.environ import *
- >>> from pyomo.network import *
- >>> m = ConcreteModel()
- >>> m.unit1 = Block()
- >>> m.unit1.x = Var()
- >>> m.unit1.y = Var(['a', 'b'])
- >>> m.unit2 = Block()
- >>> m.unit2.x = Var()
- >>> m.unit2.y = Var(['a', 'b'])
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.network import Port, Arc, SequentialDecomposition
+ >>> m = pyo.ConcreteModel()
+ >>> m.unit1 = pyo.Block()
+ >>> m.unit1.x = pyo.Var()
+ >>> m.unit1.y = pyo.Var(['a', 'b'])
+ >>> m.unit2 = pyo.Block()
+ >>> m.unit2.x = pyo.Var()
+ >>> m.unit2.y = pyo.Var(['a', 'b'])
>>> m.unit1.port = Port(initialize=[m.unit1.x, (m.unit1.y, Port.Extensive)])
>>> m.unit2.port = Port(initialize=[m.unit2.x, (m.unit2.y, Port.Extensive)])
>>> m.a = Arc(source=m.unit1.port, destination=m.unit2.port)
- >>> TransformationFactory("network.expand_arcs").apply_to(m)
+ >>> pyo.TransformationFactory("network.expand_arcs").apply_to(m)
>>> m.unit1.x.fix(10)
>>> m.unit1.y['a'].fix(15)
@@ -326,6 +330,7 @@ class:
>>> seq.run(m, initialize)
.. autoclass:: pyomo.network.SequentialDecomposition
+ :noindex:
:members: set_guesses_for, set_tear_set, tear_set_arcs, indexes_to_arcs,
run, create_graph, select_tear_mip, select_tear_mip_model,
select_tear_heuristic, calculation_order, tree_order
diff --git a/doc/OnlineDocs/modeling_extensions/reduce_points_demo.png b/doc/OnlineDocs/explanation/modeling/reduce_points_demo.png
similarity index 100%
rename from doc/OnlineDocs/modeling_extensions/reduce_points_demo.png
rename to doc/OnlineDocs/explanation/modeling/reduce_points_demo.png
diff --git a/doc/OnlineDocs/explanation/modeling/units.rst b/doc/OnlineDocs/explanation/modeling/units.rst
new file mode 100644
index 00000000000..6e4c1ae3f15
--- /dev/null
+++ b/doc/OnlineDocs/explanation/modeling/units.rst
@@ -0,0 +1,12 @@
+Units Handling in Pyomo
+=======================
+
+.. automodule:: pyomo.core.base.units_container
+ :noindex:
+
+.. autosummary::
+
+ PyomoUnitsContainer
+ UnitsError
+ InconsistentUnitsError
+
diff --git a/doc/OnlineDocs/advanced_topics/flattener/index.rst b/doc/OnlineDocs/explanation/modeling_utils/flattener/index.rst
similarity index 100%
rename from doc/OnlineDocs/advanced_topics/flattener/index.rst
rename to doc/OnlineDocs/explanation/modeling_utils/flattener/index.rst
diff --git a/doc/OnlineDocs/advanced_topics/flattener/motivation.rst b/doc/OnlineDocs/explanation/modeling_utils/flattener/motivation.rst
similarity index 100%
rename from doc/OnlineDocs/advanced_topics/flattener/motivation.rst
rename to doc/OnlineDocs/explanation/modeling_utils/flattener/motivation.rst
diff --git a/doc/OnlineDocs/advanced_topics/flattener/reference.rst b/doc/OnlineDocs/explanation/modeling_utils/flattener/reference.rst
similarity index 90%
rename from doc/OnlineDocs/advanced_topics/flattener/reference.rst
rename to doc/OnlineDocs/explanation/modeling_utils/flattener/reference.rst
index 22c7b67e1f6..b30559ef1a6 100644
--- a/doc/OnlineDocs/advanced_topics/flattener/reference.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/flattener/reference.rst
@@ -8,7 +8,10 @@ API reference
pyomo.dae.flatten.flatten_dae_components
.. autofunction:: pyomo.dae.flatten.slice_component_along_sets
+ :noindex:
.. autofunction:: pyomo.dae.flatten.flatten_components_along_sets
+ :noindex:
.. autofunction:: pyomo.dae.flatten.flatten_dae_components
+ :noindex:
diff --git a/doc/OnlineDocs/explanation/modeling_utils/index.rst b/doc/OnlineDocs/explanation/modeling_utils/index.rst
new file mode 100644
index 00000000000..16560899ebd
--- /dev/null
+++ b/doc/OnlineDocs/explanation/modeling_utils/index.rst
@@ -0,0 +1,24 @@
+Modeling Utilities
+==================
+
+.. toctree::
+ :maxdepth: 2
+
+ flattener/index
+ latex_printer
+ preprocessing
+ scaling
+
+
+
+..
+ Reorganization notes:
+
+ `Latex Printer`
+ `FME`
+ `Model Viewer`
+ `Model Flattening`
+
+ Still missing:
+ - fme
+ - viewer
diff --git a/doc/OnlineDocs/contributed_packages/latex_printer.rst b/doc/OnlineDocs/explanation/modeling_utils/latex_printer.rst
similarity index 99%
rename from doc/OnlineDocs/contributed_packages/latex_printer.rst
rename to doc/OnlineDocs/explanation/modeling_utils/latex_printer.rst
index ff3f628c0c8..c03eebe2f91 100644
--- a/doc/OnlineDocs/contributed_packages/latex_printer.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/latex_printer.rst
@@ -4,6 +4,7 @@ Latex Printing
Pyomo models can be printed to a LaTeX compatible format using the ``pyomo.contrib.latex_printer.latex_printer`` function:
.. autofunction:: pyomo.contrib.latex_printer.latex_printer.latex_printer
+ :noindex:
.. note::
diff --git a/doc/OnlineDocs/contributed_packages/preprocessing.rst b/doc/OnlineDocs/explanation/modeling_utils/preprocessing.rst
similarity index 78%
rename from doc/OnlineDocs/contributed_packages/preprocessing.rst
rename to doc/OnlineDocs/explanation/modeling_utils/preprocessing.rst
index fd26f2bf6db..accc2bf935c 100644
--- a/doc/OnlineDocs/contributed_packages/preprocessing.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/preprocessing.rst
@@ -40,16 +40,16 @@ transformation on a concrete Pyomo model:
.. doctest::
- >>> from pyomo.environ import *
- >>> m = ConcreteModel()
- >>> m.v1 = Var(initialize=1, bounds=(1, 8))
- >>> m.v2 = Var(initialize=2, bounds=(0, 3))
- >>> m.v3 = Var(initialize=3, bounds=(-7, 4))
- >>> m.v4 = Var(initialize=4, bounds=(2, 6))
- >>> m.c1 = Constraint(expr=m.v1 == m.v2)
- >>> m.c2 = Constraint(expr=m.v2 == m.v3)
- >>> m.c3 = Constraint(expr=m.v3 == m.v4)
- >>> TransformationFactory('contrib.aggregate_vars').apply_to(m)
+ >>> import pyomo.environ as pyo
+ >>> m = pyo.ConcreteModel()
+ >>> m.v1 = pyo.Var(initialize=1, bounds=(1, 8))
+ >>> m.v2 = pyo.Var(initialize=2, bounds=(0, 3))
+ >>> m.v3 = pyo.Var(initialize=3, bounds=(-7, 4))
+ >>> m.v4 = pyo.Var(initialize=4, bounds=(2, 6))
+ >>> m.c1 = pyo.Constraint(expr=m.v1 == m.v2)
+ >>> m.c2 = pyo.Constraint(expr=m.v2 == m.v3)
+ >>> m.c3 = pyo.Constraint(expr=m.v3 == m.v4)
+ >>> pyo.TransformationFactory('contrib.aggregate_vars').apply_to(m)
To see the results of the transformation, you could then use the command
@@ -58,6 +58,7 @@ To see the results of the transformation, you could then use the command
>>> m.pprint()
.. autoclass:: pyomo.contrib.preprocessing.plugins.var_aggregator.VariableAggregator
+ :noindex:
:members: apply_to, create_using, update_variables
@@ -66,17 +67,18 @@ Explicit Constraints to Variable Bounds
.. doctest::
- >>> from pyomo.environ import *
- >>> m = ConcreteModel()
- >>> m.v1 = Var(initialize=1)
- >>> m.v2 = Var(initialize=2)
- >>> m.v3 = Var(initialize=3)
- >>> m.c1 = Constraint(expr=m.v1 == 2)
- >>> m.c2 = Constraint(expr=m.v2 >= -2)
- >>> m.c3 = Constraint(expr=m.v3 <= 5)
- >>> TransformationFactory('contrib.constraints_to_var_bounds').apply_to(m)
+ >>> import pyomo.environ as pyo
+ >>> m = pyo.ConcreteModel()
+ >>> m.v1 = pyo.Var(initialize=1)
+ >>> m.v2 = pyo.Var(initialize=2)
+ >>> m.v3 = pyo.Var(initialize=3)
+ >>> m.c1 = pyo.Constraint(expr=m.v1 == 2)
+ >>> m.c2 = pyo.Constraint(expr=m.v2 >= -2)
+ >>> m.c3 = pyo.Constraint(expr=m.v3 <= 5)
+ >>> pyo.TransformationFactory('contrib.constraints_to_var_bounds').apply_to(m)
.. autoclass:: pyomo.contrib.preprocessing.plugins.bounds_to_vars.ConstraintToVarBoundTransform
+ :noindex:
:members: apply_to, create_using
@@ -84,6 +86,7 @@ Induced Linearity Reformulation
-------------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.induced_linearity.InducedLinearity
+ :noindex:
:members: apply_to, create_using
@@ -94,58 +97,68 @@ This transformation was developed by `Sunjeev Kale
`_ at Carnegie Mellon University.
.. autoclass:: pyomo.contrib.preprocessing.plugins.constraint_tightener.TightenConstraintFromVars
+ :noindex:
:members: apply_to, create_using
Trivial Constraint Deactivation
-------------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.deactivate_trivial_constraints.TrivialConstraintDeactivator
+ :noindex:
:members: apply_to, create_using, revert
Fixed Variable Detection
------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.detect_fixed_vars.FixedVarDetector
+ :noindex:
:members: apply_to, create_using, revert
Fixed Variable Equality Propagator
----------------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.equality_propagate.FixedVarPropagator
+ :noindex:
:members: apply_to, create_using, revert
Variable Bound Equality Propagator
----------------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.equality_propagate.VarBoundPropagator
+ :noindex:
:members: apply_to, create_using, revert
Variable Midpoint Initializer
-----------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.init_vars.InitMidpoint
+ :noindex:
:members: apply_to, create_using
Variable Zero Initializer
-------------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.init_vars.InitZero
+ :noindex:
:members: apply_to, create_using
Zero Term Remover
-----------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.remove_zero_terms.RemoveZeroTerms
+ :noindex:
:members: apply_to, create_using
Variable Bound Remover
----------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.strip_bounds.VariableBoundStripper
+ :noindex:
:members: apply_to, create_using, revert
Zero Sum Propagator
-------------------
.. autoclass:: pyomo.contrib.preprocessing.plugins.zero_sum_propagator.ZeroSumPropagator
+ :noindex:
:members: apply_to, create_using
diff --git a/doc/OnlineDocs/model_transformations/scaling.rst b/doc/OnlineDocs/explanation/modeling_utils/scaling.rst
similarity index 97%
rename from doc/OnlineDocs/model_transformations/scaling.rst
rename to doc/OnlineDocs/explanation/modeling_utils/scaling.rst
index 180f1e0205b..7761e275176 100644
--- a/doc/OnlineDocs/model_transformations/scaling.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/scaling.rst
@@ -3,8 +3,10 @@ Model Scaling Transformation
Good scaling of models can greatly improve the numerical properties of a problem and thus increase reliability and convergence. The ``core.scale_model`` transformation allows users to separate scaling of a model from the declaration of the model variables and constraints which allows for models to be written in more natural forms and to be scaled and rescaled as required without having to rewrite the model code.
-.. autoclass:: pyomo.core.plugins.transform.scaling.ScaleModel
- :members:
+.. autosummary::
+
+ pyomo.core.plugins.transform.scaling.ScaleModel
+
Setting Scaling Factors
-----------------------
diff --git a/doc/OnlineDocs/explanation/philosophy/abstract_modeling.rst b/doc/OnlineDocs/explanation/philosophy/abstract_modeling.rst
new file mode 100644
index 00000000000..6832cfe04ac
--- /dev/null
+++ b/doc/OnlineDocs/explanation/philosophy/abstract_modeling.rst
@@ -0,0 +1,64 @@
+Abstract Models
+---------------
+
+.. note::
+
+ TODO: this is a copy of "Abstract vs Concrete" from Getting Started.
+ This should be expanded here.
+
+
+A mathematical model can be defined using symbols that represent data
+values. For example, the following equations represent a linear program
+(LP) to find optimal values for the vector :math:`x` with parameters
+:math:`n` and :math:`b`, and parameter vectors :math:`a` and :math:`c`:
+
+.. math::
+ :nowrap:
+
+ \[
+ \begin{array}{lll}
+ \min & \sum_{j=1}^n c_j x_j &\\
+ \mathrm{s.t.} & \sum_{j=1}^n a_{ij} x_j \geq b_i & \forall i = 1 \ldots m\\
+ & x_j \geq 0 & \forall j = 1 \ldots n
+ \end{array}
+ \]
+
+.. note::
+
+ As a convenience, we use the symbol :math:`\forall` to mean "for all"
+ or "for each."
+
+We call this an *abstract* or *symbolic* mathematical model since it
+relies on unspecified parameter values. Data values can be used to
+specify a *model instance*. The ``AbstractModel`` class provides a
+context for defining and initializing abstract optimization models in
+Pyomo when the data values will be supplied at the time a solution is to
+be obtained.
+
+In many contexts, a mathematical model can and should be directly
+defined with the data values supplied at the time of the model
+definition. We call these *concrete* mathematical models. For example,
+the following LP model is a concrete instance of the previous abstract
+model:
+
+.. math::
+ :nowrap:
+
+ \[
+ \begin{array}{ll}
+ \min & 2 x_1 + 3 x_2\\
+ \mathrm{s.t.} & 3 x_1 + 4 x_2 \geq 1\\
+ & x_1, x_2 \geq 0
+ \end{array}
+ \]
+
+The ``ConcreteModel`` class is used to define concrete optimization
+models in Pyomo.
+
+.. note::
+
+ Python programmers will probably prefer to write concrete models,
+ while users of some other algebraic modeling languages may tend to
+ prefer to write abstract models. The choice is largely a matter of
+ taste; some applications may be a little more straightforward using
+ one or the other.
diff --git a/doc/OnlineDocs/explanation/philosophy/component_design.rst b/doc/OnlineDocs/explanation/philosophy/component_design.rst
new file mode 100644
index 00000000000..e4c526698d1
--- /dev/null
+++ b/doc/OnlineDocs/explanation/philosophy/component_design.rst
@@ -0,0 +1,4 @@
+Pyomo Component Design
+======================
+
+TODO
diff --git a/doc/OnlineDocs/developer_reference/expressions/design.rst b/doc/OnlineDocs/explanation/philosophy/expressions/design.rst
similarity index 98%
rename from doc/OnlineDocs/developer_reference/expressions/design.rst
rename to doc/OnlineDocs/explanation/philosophy/expressions/design.rst
index ddecb39ad0c..d12fe745672 100644
--- a/doc/OnlineDocs/developer_reference/expressions/design.rst
+++ b/doc/OnlineDocs/explanation/philosophy/expressions/design.rst
@@ -73,7 +73,7 @@ Expression trees can be categorized in four different ways:
These three categories are illustrated with the following example:
-.. literalinclude:: ../../src/expr/design_categories.spy
+.. literalinclude:: /src/expr/design_categories.spy
The following table describes four different simple expressions
that consist of a single model component, and it shows how they
@@ -107,7 +107,7 @@ Named expressions allow for changes to an expression after it has
been constructed. For example, consider the expression ``f`` defined
with the :class:`Expression ` component:
-.. literalinclude:: ../../src/expr/design_named_expression.spy
+.. literalinclude:: /src/expr/design_named_expression.spy
Although ``f`` is an immutable expression, whose definition is
fixed, a sub-expressions is the named expression ``M.e``. Named
@@ -227,7 +227,7 @@ The :data:`linear_expression `
object is a context manager that can be used to declare a linear sum. For
example, consider the following two loops:
-.. literalinclude:: ../../src/expr/design_cm1.spy
+.. literalinclude:: /src/expr/design_cm1.spy
The first apparent difference in these loops is that the value of
``s`` is explicitly initialized while ``e`` is initialized when the
@@ -250,7 +250,7 @@ construct different expressions with different context declarations.
Finally, note that these context managers can be passed into the :attr:`start`
method for the :func:`quicksum ` function. For example:
-.. literalinclude:: ../../src/expr/design_cm2.spy
+.. literalinclude:: /src/expr/design_cm2.spy
This sum contains terms for ``M.x[i]`` and ``M.y[i]``. The syntax
in this example is not intuitive because the sum is being stored
diff --git a/doc/OnlineDocs/developer_reference/expressions/index.rst b/doc/OnlineDocs/explanation/philosophy/expressions/index.rst
similarity index 96%
rename from doc/OnlineDocs/developer_reference/expressions/index.rst
rename to doc/OnlineDocs/explanation/philosophy/expressions/index.rst
index 685fde25173..e7dcf5831a1 100644
--- a/doc/OnlineDocs/developer_reference/expressions/index.rst
+++ b/doc/OnlineDocs/explanation/philosophy/expressions/index.rst
@@ -21,7 +21,7 @@ nodes contain operators. Pyomo relies on so-called magic methods
to automate the construction of symbolic expressions. For example,
consider an expression ``e`` declared as follows:
-.. literalinclude:: ../../src/expr/index_simple.spy
+.. literalinclude:: /src/expr/index_simple.spy
Python determines that the magic method ``__mul__`` is called on
the ``M.v`` object, with the argument ``2``. This method returns
diff --git a/doc/OnlineDocs/developer_reference/expressions/managing.rst b/doc/OnlineDocs/explanation/philosophy/expressions/managing.rst
similarity index 81%
rename from doc/OnlineDocs/developer_reference/expressions/managing.rst
rename to doc/OnlineDocs/explanation/philosophy/expressions/managing.rst
index a4dd2a51436..ded3a5f8f9f 100644
--- a/doc/OnlineDocs/developer_reference/expressions/managing.rst
+++ b/doc/OnlineDocs/explanation/philosophy/expressions/managing.rst
@@ -23,7 +23,7 @@ mimics the Python operations used to construct an expression. The
:data:`verbose` flag can be set to :const:`True` to generate a
string representation that is a nested functional form. For example:
-.. literalinclude:: ../../src/expr/managing_ex1.spy
+.. literalinclude:: /src/expr/managing_ex1.spy
Labeler and Symbol Map
~~~~~~~~~~~~~~~~~~~~~~
@@ -37,7 +37,7 @@ the :class:`NumericLabeler` defines a functor that can be used to
sequentially generate simple labels with a prefix followed by the
variable count:
-.. literalinclude:: ../../src/expr/managing_ex2.spy
+.. literalinclude:: /src/expr/managing_ex2.spy
The :data:`smap` option is used to specify a symbol map object
(:class:`SymbolMap `), which
@@ -72,19 +72,19 @@ the expression have a value. The :func:`value `
function can be used to walk the expression tree and compute the
value of an expression. For example:
-.. literalinclude:: ../../src/expr/managing_ex5.spy
+.. literalinclude:: /src/expr/managing_ex5.spy
Additionally, expressions define the :func:`__call__` method, so the
following is another way to compute the value of an expression:
-.. literalinclude:: ../../src/expr/managing_ex6.spy
+.. literalinclude:: /src/expr/managing_ex6.spy
If a parameter or variable is undefined, then the :func:`value
` function and :func:`__call__` method will
raise an exception. This exception can be suppressed using the
:attr:`exception` option. For example:
-.. literalinclude:: ../../src/expr/managing_ex7.spy
+.. literalinclude:: /src/expr/managing_ex7.spy
This option is useful in contexts where adding a try block is inconvenient
in your modeling script.
@@ -108,7 +108,7 @@ functions that support this functionality. First, the
function is a generator function that walks the expression tree and yields all
nodes whose type is in a specified set of node types. For example:
-.. literalinclude:: ../../src/expr/managing_ex8.spy
+.. literalinclude:: /src/expr/managing_ex8.spy
The :func:`identify_variables `
function is a generator function that yields all nodes that are
@@ -117,7 +117,7 @@ but this set of variable types does not need to be specified by the user.
However, the :attr:`include_fixed` flag can be specified to omit fixed
variables. For example:
-.. literalinclude:: ../../src/expr/managing_ex9.spy
+.. literalinclude:: /src/expr/managing_ex9.spy
Walking an Expression Tree with a Visitor Class
-----------------------------------------------
@@ -140,10 +140,6 @@ tree:
seven event callbacks that users can hook into, providing very
fine-grained control over the expression walker.
-:class:`SimpleExpressionVisitor `
- A :func:`visitor` method is called for each node in the tree,
- and the visitor class collects information about the tree.
-
:class:`ExpressionValueVisitor `
When the :func:`visitor` method is called on each node in the
tree, the *values* of its children have been computed. The
@@ -166,12 +162,6 @@ These classes define a variety of suitable tree search methods:
* ``walk_expression``: depth-first traversal of the expression tree.
-* :class:`SimpleExpressionVisitor `
-
- * ``xbfs``: breadth-first search where leaf nodes are immediately visited
- * ``xbfs_yield_leaves``: breadth-first search where leaf nodes are
- immediately visited, and the visit method yields a value
-
* :class:`ExpressionValueVisitor `
* ``dfs_postorder_stack``: postorder depth-first search using a
@@ -179,12 +169,11 @@ These classes define a variety of suitable tree search methods:
To implement a visitor object, a user needs to provide specializations
-for specific events. For legacy visitors based on the PyUtilib
-visitor pattern (e.g., :class:`SimpleExpressionVisitor` and
-:class:`ExpressionValueVisitor`), one must create a subclass of one of these
-classes and override at least one of the following:
+for specific events. For legacy visitors based on the PyUtilib visitor
+pattern (e.g., :class:`ExpressionValueVisitor`), one must create a
+subclass and override at least one of the following:
-:func:`visitor`
+:func:`visit`
Defines the operation that is performed when a node is visited. In
the :class:`ExpressionValueVisitor
` and
@@ -196,10 +185,7 @@ classes and override at least one of the following:
Checks if the search should terminate with this node. If no,
then this method returns the tuple ``(False, None)``. If yes,
then this method returns ``(False, value)``, where *value* is
- computed by this method. This method is not used in the
- :class:`SimpleExpressionVisitor
- ` visitor
- class.
+ computed by this method.
:func:`finalize`
This method defines the final value that is returned from the
@@ -216,21 +202,22 @@ callbacks, which are documented in the class documentation.
Detailed documentation of the APIs for these methods is provided
with the class documentation for these visitors.
-SimpleExpressionVisitor Example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+StreamBasedExpressionVisitor Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this example, we describe an visitor class that counts the number
of nodes in an expression (including leaf nodes). Consider the following
class:
-.. literalinclude:: ../../src/expr/managing_visitor1.spy
+.. literalinclude:: /src/expr/managing_visitor1.spy
-The class constructor creates a counter, and the :func:`visit` method
-increments this counter for every node that is visited. The :func:`finalize`
-method returns the value of this counter after the tree has been walked. The
-following function illustrates this use of this visitor class:
+The :func:`initializeWalker` method creates a counter, and the
+:func:`exitNode` method increments this counter for every node that is
+visited. The :func:`finalizeResult` method returns the value of this
+counter after the tree has been walked. The following function
+illustrates this use of this visitor class:
-.. literalinclude:: ../../src/expr/managing_visitor2.spy
+.. literalinclude:: /src/expr/managing_visitor2.spy
ExpressionValueVisitor Example
@@ -240,14 +227,14 @@ In this example, we describe an visitor class that clones the
expression tree (including leaf nodes). Consider the following
class:
-.. literalinclude:: ../../src/expr/managing_visitor3.spy
+.. literalinclude:: /src/expr/managing_visitor3.spy
The :func:`visit` method creates a new expression node with children
specified by :attr:`values`. The :func:`visiting_potential_leaf`
method performs a :func:`deepcopy` on leaf nodes, which are native
Python types or non-expression objects.
-.. literalinclude:: ../../src/expr/managing_visitor4.spy
+.. literalinclude:: /src/expr/managing_visitor4.spy
ExpressionReplacementVisitor Example
@@ -258,15 +245,15 @@ variables with scaled variables, using a mutable parameter that
can be modified later. the following
class:
-.. literalinclude:: ../../src/expr/managing_visitor5.spy
+.. literalinclude:: /src/expr/managing_visitor5.spy
No other method need to be defined. The
:func:`beforeChild` method identifies variable nodes
and returns a product expression that contains a mutable parameter.
-.. literalinclude:: ../../src/expr/managing_visitor6.spy
+.. literalinclude:: /src/expr/managing_visitor6.spy
The :func:`scale_expression` function is called with an expression and
a dictionary, :attr:`scale`, that maps variable ID to model parameter. For example:
-.. literalinclude:: ../../src/expr/managing_visitor7.spy
+.. literalinclude:: /src/expr/managing_visitor7.spy
diff --git a/doc/OnlineDocs/developer_reference/expressions/overview.rst b/doc/OnlineDocs/explanation/philosophy/expressions/overview.rst
similarity index 95%
rename from doc/OnlineDocs/developer_reference/expressions/overview.rst
rename to doc/OnlineDocs/explanation/philosophy/expressions/overview.rst
index c1962edec22..c89e3e6b4b7 100644
--- a/doc/OnlineDocs/developer_reference/expressions/overview.rst
+++ b/doc/OnlineDocs/explanation/philosophy/expressions/overview.rst
@@ -50,13 +50,13 @@ are:
example, the following two loops had dramatically different
runtime:
- .. literalinclude:: ../../src/expr/overview_example1.spy
+ .. literalinclude:: /src/expr/overview_example1.spy
* Coopr3 eliminates side effects by automatically cloning sub-expressions.
Unfortunately, this can easily lead to unexpected cloning in models, which
can dramatically slow down Pyomo model generation. For example:
- .. literalinclude:: ../../src/expr/overview_example2.spy
+ .. literalinclude:: /src/expr/overview_example2.spy
* Coopr3 leverages recursion in many operations, including expression
cloning. Even simple non-linear expressions can result in deep
@@ -82,7 +82,7 @@ control for how expressions are managed in Python. For example:
* Python variables can point to the same expression tree
- .. literalinclude:: ../../src/expr/overview_tree1.spy
+ .. literalinclude:: /src/expr/overview_tree1.spy
This is illustrated as follows:
@@ -102,7 +102,7 @@ control for how expressions are managed in Python. For example:
* A variable can point to a sub-tree that another variable points to
- .. literalinclude:: ../../src/expr/overview_tree2.spy
+ .. literalinclude:: /src/expr/overview_tree2.spy
This is illustrated as follows:
@@ -124,7 +124,7 @@ control for how expressions are managed in Python. For example:
* Two expression trees can point to the same sub-tree
- .. literalinclude:: ../../src/expr/overview_tree3.spy
+ .. literalinclude:: /src/expr/overview_tree3.spy
This is illustrated as follows:
@@ -169,7 +169,7 @@ between expressions, we do not consider those expressions entangled.
Expression entanglement is problematic because shared expressions complicate
the expected behavior when sub-expressions are changed. Consider the following example:
-.. literalinclude:: ../../src/expr/overview_tree4.spy
+.. literalinclude:: /src/expr/overview_tree4.spy
What is the value of ``e`` after ``M.w`` is added to it? What is the
value of ``f``? The answers to these questions are not immediately
@@ -244,7 +244,7 @@ There is one important exception to the entanglement property
described above. The ``Expression`` component is treated as a
mutable expression when shared between expressions. For example:
-.. literalinclude:: ../../src/expr/overview_tree5.spy
+.. literalinclude:: /src/expr/overview_tree5.spy
Here, the expression ``M.e`` is a so-called *named expression* that
the user has declared. Named expressions are explicitly intended
diff --git a/doc/OnlineDocs/developer_reference/expressions/performance.rst b/doc/OnlineDocs/explanation/philosophy/expressions/performance.rst
similarity index 91%
rename from doc/OnlineDocs/developer_reference/expressions/performance.rst
rename to doc/OnlineDocs/explanation/philosophy/expressions/performance.rst
index 8e344e50982..c7b68377098 100644
--- a/doc/OnlineDocs/developer_reference/expressions/performance.rst
+++ b/doc/OnlineDocs/explanation/philosophy/expressions/performance.rst
@@ -11,14 +11,14 @@ Expression Generation
Pyomo expressions can be constructed using native binary operators
in Python. For example, a sum can be created in a simple loop:
-.. literalinclude:: ../../src/expr/performance_loop1.spy
+.. literalinclude:: /src/expr/performance_loop1.spy
Additionally, Pyomo expressions can be constructed using functions
that iteratively apply Python binary operators. For example, the
Python :func:`sum` function can be used to replace the previous
loop:
-.. literalinclude:: ../../src/expr/performance_loop2.spy
+.. literalinclude:: /src/expr/performance_loop2.spy
The :func:`sum` function is both more compact and more efficient.
Using :func:`sum` avoids the creation of temporary variables, and
@@ -47,7 +47,7 @@ expressions.
For example, consider the following quadratic polynomial:
-.. literalinclude:: ../../src/expr/performance_loop3.spy
+.. literalinclude:: /src/expr/performance_loop3.spy
This quadratic polynomial is treated as a nonlinear expression
unless the expression is explicitly processed to identify quadratic
@@ -78,7 +78,7 @@ The :func:`prod ` function is analogous to the builtin
argument list, :attr:`args`, which represents expressions that are multiplied
together. For example:
-.. literalinclude:: ../../src/expr/performance_prod.spy
+.. literalinclude:: /src/expr/performance_prod.spy
quicksum
~~~~~~~~
@@ -89,7 +89,7 @@ generates a more compact Pyomo expression. Its main argument is a
variable length argument list, :attr:`args`, which represents
expressions that are summed together. For example:
-.. literalinclude:: ../../src/expr/performance_quicksum.spy
+.. literalinclude:: /src/expr/performance_quicksum.spy
The summation is customized based on the :attr:`start` and
:attr:`linear` arguments. The :attr:`start` defines the initial
@@ -111,13 +111,13 @@ more quickly.
Consider the following example:
-.. literalinclude:: ../../src/expr/quicksum_runtime.spy
+.. literalinclude:: /src/expr/quicksum_runtime.spy
The sum consists of linear terms because the exponents are one.
The following output illustrates that quicksum can identify this
linear structure to generate expressions more quickly:
-.. literalinclude:: ../../src/expr/quicksum.log
+.. literalinclude:: /src/expr/quicksum.log
:language: none
If :attr:`start` is not a numeric value, then the :func:`quicksum
@@ -134,7 +134,7 @@ to be stored in an object that is passed into the function (e.g. the linear cont
term in :attr:`args` is misleading. Consider the following
example:
- .. literalinclude:: ../../src/expr/performance_warning.spy
+ .. literalinclude:: /src/expr/performance_warning.spy
The first term created by the generator is linear, but the
subsequent terms are nonlinear. Pyomo gracefully transitions
@@ -153,12 +153,12 @@ calling :func:`quicksum `. If two or more components
provided, then the result is the summation of their terms multiplied
together. For example:
-.. literalinclude:: ../../src/expr/performance_sum_product1.spy
+.. literalinclude:: /src/expr/performance_sum_product1.spy
The :attr:`denom` argument specifies components whose terms are in
the denominator. For example:
-.. literalinclude:: ../../src/expr/performance_sum_product2.spy
+.. literalinclude:: /src/expr/performance_sum_product2.spy
The terms summed by this function are explicitly specified, so
:func:`sum_product ` can identify
diff --git a/doc/OnlineDocs/explanation/philosophy/index.rst b/doc/OnlineDocs/explanation/philosophy/index.rst
new file mode 100644
index 00000000000..b45cf8806d0
--- /dev/null
+++ b/doc/OnlineDocs/explanation/philosophy/index.rst
@@ -0,0 +1,21 @@
+Pyomo Philosophy
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ abstract_modeling
+ component_design
+ expressions/index
+ transformations
+
+
+
+..
+ Reorganization notes:
+
+ `Pyomo Philosophy`
+ `Concrete and Abstract Models`
+ `Component Hierarchy`
+ `Expression System`
+ `Transformations`
diff --git a/doc/OnlineDocs/model_transformations/index.rst b/doc/OnlineDocs/explanation/philosophy/transformations.rst
similarity index 50%
rename from doc/OnlineDocs/model_transformations/index.rst
rename to doc/OnlineDocs/explanation/philosophy/transformations.rst
index 462538128e7..363bcce73eb 100644
--- a/doc/OnlineDocs/model_transformations/index.rst
+++ b/doc/OnlineDocs/explanation/philosophy/transformations.rst
@@ -1,7 +1,4 @@
Model Transformations
=====================
-.. toctree::
- :maxdepth: 1
-
- scaling.rst
+TODO
diff --git a/doc/OnlineDocs/contributed_packages/gdpopt.rst b/doc/OnlineDocs/explanation/solvers/gdpopt.rst
similarity index 55%
rename from doc/OnlineDocs/contributed_packages/gdpopt.rst
rename to doc/OnlineDocs/explanation/solvers/gdpopt.rst
index d550b0ced76..98eabc4b01d 100644
--- a/doc/OnlineDocs/contributed_packages/gdpopt.rst
+++ b/doc/OnlineDocs/explanation/solvers/gdpopt.rst
@@ -12,15 +12,16 @@ The main advantage of these techniques is their ability to solve subproblems
in a reduced space, including nonlinear constraints only for ``True`` logical blocks.
As a result, GDPopt is most effective for nonlinear GDP models.
-Three algorithms are available in GDPopt:
+Four algorithms are available in GDPopt:
1. Logic-based outer approximation (LOA) [`Turkay & Grossmann, 1996`_]
2. Global logic-based outer approximation (GLOA) [`Lee & Grossmann, 2001`_]
3. Logic-based branch-and-bound (LBB) [`Lee & Grossmann, 2001`_]
+4. Logic-based discrete steepest descent algorithm (LD-SDA) [`Ovalle et al., 2025`_]
Usage and implementation details for GDPopt can be found in the PSE 2018 paper
(`Chen et al., 2018`_), or via its
-`preprint `_.
+`preprint `_.
Credit for prototyping and development can be found in the ``GDPopt`` class documentation, below.
@@ -28,19 +29,20 @@ Credit for prototyping and development can be found in the ``GDPopt`` class docu
.. _Lee & Grossmann, 2001: https://doi.org/10.1016/S0098-1354(01)00732-3
.. _Lee & Grossmann, 2000: https://doi.org/10.1016/S0098-1354(00)00581-0
.. _Chen et al., 2018: https://doi.org/10.1016/B978-0-444-64241-7.50143-9
+.. _Ovalle et al., 2025: https://doi.org/10.1016/j.compchemeng.2024.108993
GDPopt can be used to solve a Pyomo.GDP concrete model in two ways.
The simplest is to instantiate the generic GDPopt solver and specify the desired algorithm as an argument to the ``solve`` method:
.. code::
- >>> SolverFactory('gdpopt').solve(model, algorithm='LOA')
+ >>> pyo.SolverFactory('gdpopt').solve(model, algorithm='LOA')
The alternative is to instantiate an algorithm-specific GDPopt solver:
.. code::
- >>> SolverFactory('gdpopt.loa').solve(model)
+ >>> pyo.SolverFactory('gdpopt.loa').solve(model)
In the above examples, GDPopt uses the GDPopt-LOA algorithm.
Other algorithms may be used by specifying them in the ``algorithm`` argument when using the generic solver or by instantiating the algorithm-specific GDPopt solvers. All GDPopt options are listed below.
@@ -63,27 +65,27 @@ An example that includes the modeling approach may be found below.
:skipif: not glpk_available
Required imports
- >>> from pyomo.environ import *
- >>> from pyomo.gdp import *
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.gdp import Disjunct, Disjunction
Create a simple model
- >>> model = ConcreteModel(name='LOA example')
+ >>> model = pyo.ConcreteModel(name='LOA example')
- >>> model.x = Var(bounds=(-1.2, 2))
- >>> model.y = Var(bounds=(-10,10))
- >>> model.c = Constraint(expr= model.x + model.y == 1)
+ >>> model.x = pyo.Var(bounds=(-1.2, 2))
+ >>> model.y = pyo.Var(bounds=(-10,10))
+ >>> model.c = pyo.Constraint(expr= model.x + model.y == 1)
>>> model.fix_x = Disjunct()
- >>> model.fix_x.c = Constraint(expr=model.x == 0)
+ >>> model.fix_x.c = pyo.Constraint(expr=model.x == 0)
>>> model.fix_y = Disjunct()
- >>> model.fix_y.c = Constraint(expr=model.y == 0)
+ >>> model.fix_y.c = pyo.Constraint(expr=model.y == 0)
>>> model.d = Disjunction(expr=[model.fix_x, model.fix_y])
- >>> model.objective = Objective(expr=model.x + 0.1*model.y, sense=minimize)
+ >>> model.objective = pyo.Objective(expr=model.x + 0.1*model.y, sense=pyo.minimize)
Solve the model using GDPopt
- >>> results = SolverFactory('gdpopt.loa').solve(
+ >>> results = pyo.SolverFactory('gdpopt.loa').solve(
... model, mip_solver='glpk') # doctest: +IGNORE_RESULT
Display the final solution
@@ -93,10 +95,10 @@ An example that includes the modeling approach may be found below.
Variables:
x : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
- None : -1.2 : 0.0 : 2 : False : False : Reals
+ None : -1.2 : 0 : 2 : False : False : Reals
y : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
- None : -10 : 1.0 : 10 : False : False : Reals
+ None : -10 : 1 : 10 : False : False : Reals
Objectives:
objective : Size=1, Index=None, Active=True
@@ -106,7 +108,7 @@ An example that includes the modeling approach may be found below.
Constraints:
c : Size=1
Key : Lower : Body : Upper
- None : 1.0 : 1.0 : 1.0
+ None : 1.0 : 1 : 1.0
.. note::
@@ -115,7 +117,7 @@ An example that includes the modeling approach may be found below.
.. code::
- >>> SolverFactory('gdpopt.loa').solve(model, tee=True)
+ >>> pyo.SolverFactory('gdpopt.loa').solve(model, tee=True)
Global Logic-based Outer Approximation (GLOA)
---------------------------------------------
@@ -124,7 +126,7 @@ The same algorithm can be used to solve GDPs involving nonconvex nonlinear const
.. code::
- >>> SolverFactory('gdpopt.gloa').solve(model)
+ >>> pyo.SolverFactory('gdpopt.gloa').solve(model)
.. warning::
@@ -137,7 +139,7 @@ Instead of outer approximation, GDPs can be solved using the same MILP relaxatio
.. code::
- >>> SolverFactory('gdpopt.ric').solve(model)
+ >>> pyo.SolverFactory('gdpopt.ric').solve(model)
Again, this is a global algorithm if the subproblems are solved globally, and is not otherwise.
@@ -158,25 +160,25 @@ To use the GDPopt-LBB solver, define your Pyomo GDP model as usual:
:skipif: not baron_available
Required imports
- >>> from pyomo.environ import *
+ >>> import pyomo.environ as pyo
>>> from pyomo.gdp import Disjunct, Disjunction
Create a simple model
- >>> m = ConcreteModel()
- >>> m.x1 = Var(bounds = (0,8))
- >>> m.x2 = Var(bounds = (0,8))
- >>> m.obj = Objective(expr=m.x1 + m.x2, sense=minimize)
+ >>> m = pyo.ConcreteModel()
+ >>> m.x1 = pyo.Var(bounds = (0,8))
+ >>> m.x2 = pyo.Var(bounds = (0,8))
+ >>> m.obj = pyo.Objective(expr=m.x1 + m.x2, sense=pyo.minimize)
>>> m.y1 = Disjunct()
>>> m.y2 = Disjunct()
- >>> m.y1.c1 = Constraint(expr=m.x1 >= 2)
- >>> m.y1.c2 = Constraint(expr=m.x2 >= 2)
- >>> m.y2.c1 = Constraint(expr=m.x1 >= 3)
- >>> m.y2.c2 = Constraint(expr=m.x2 >= 3)
+ >>> m.y1.c1 = pyo.Constraint(expr=m.x1 >= 2)
+ >>> m.y1.c2 = pyo.Constraint(expr=m.x2 >= 2)
+ >>> m.y2.c1 = pyo.Constraint(expr=m.x1 >= 3)
+ >>> m.y2.c2 = pyo.Constraint(expr=m.x2 >= 3)
>>> m.djn = Disjunction(expr=[m.y1, m.y2])
Invoke the GDPopt-LBB solver
- >>> results = SolverFactory('gdpopt.lbb').solve(m)
+ >>> results = pyo.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!
@@ -186,9 +188,70 @@ To use the GDPopt-LBB solver, define your Pyomo GDP model as usual:
>>> print(results.solver.termination_condition)
optimal
- >>> print([value(m.y1.indicator_var), value(m.y2.indicator_var)])
+ >>> print([pyo.value(m.y1.indicator_var), pyo.value(m.y2.indicator_var)])
[True, False]
+Logic-based Discrete-Steepest Descent Algorithm (LD-SDA)
+--------------------------------------------------------
+
+The GDPopt-LDSDA solver exploits the ordered Boolean variables in the disjunctions to solve the GDP model.
+It requires an **exclusive OR (XOR) logical constraint** to ensure that exactly one disjunct is active in each disjunction.
+The solver also requires a **starting point** for the discrete variables and allows users to choose between two **direction norms**, `'L2'` and `'Linf'`, to guide the search process.
+
+.. note::
+
+ The current implementation of the GDPopt-LDSDA requires an explicit LogicalConstraint to enforce the exclusive OR condition for each disjunction.
+
+To use the GDPopt-LDSDA solver, define your Pyomo GDP model as usual:
+
+.. doctest::
+ :skipif: not baron_available
+
+ Required imports
+ >>> import pyomo.environ as pyo
+ >>> from pyomo.gdp import Disjunct, Disjunction
+
+ Create a simple model
+ >>> m = pyo.ConcreteModel()
+
+ Define sets
+ >>> I = [1, 2, 3, 4, 5]
+ >>> J = [1, 2, 3, 4, 5]
+
+ Define variables
+ >>> m.a = pyo.Var(bounds=(-0.3, 0.2))
+ >>> m.b = pyo.Var(bounds=(-0.9, -0.5))
+
+ Define disjuncts for Y1
+ >>> m.Y1_disjuncts = Disjunct(I)
+ >>> for i in I:
+ ... m.Y1_disjuncts[i].y1_constraint = pyo.Constraint(expr=m.a == -0.3 + 0.1 * (i - 1))
+
+ Define disjuncts for Y2
+ >>> m.Y2_disjuncts = Disjunct(J)
+ >>> for j in J:
+ ... m.Y2_disjuncts[j].y2_constraint = pyo.Constraint(expr=m.b == -0.9 + 0.1 * (j - 1))
+
+ Define disjunctions
+ >>> m.y1_disjunction = Disjunction(expr=[m.Y1_disjuncts[i] for i in I])
+ >>> m.y2_disjunction = Disjunction(expr=[m.Y2_disjuncts[j] for j in J])
+
+ Logical constraints to enforce exactly one selection
+ >>> m.Y1_limit = pyo.LogicalConstraint(expr=pyo.exactly(1, [m.Y1_disjuncts[i].indicator_var for i in I]))
+ >>> m.Y2_limit = pyo.LogicalConstraint(expr=pyo.exactly(1, [m.Y2_disjuncts[j].indicator_var for j in J]))
+
+ Define objective function
+ >>> m.obj = pyo.Objective(
+ ... expr=4 * m.a**2 - 2.1 * m.a**4 + (1 / 3) * m.a**6 + m.a * m.b - 4 * m.b**2 + 4 * m.b**4,
+ ... sense=pyo.minimize
+ ... )
+
+ Invoke the GDPopt-LDSDA solver
+ >>> results = pyo.SolverFactory('gdpopt.ldsda').solve(m,
+ ... starting_point=[1,1],
+ ... logical_constraint_list=[m.Y1_limit, m.Y2_limit],
+ ... direction_norm='Linf',
+ ... )
GDPopt implementation and optional arguments
--------------------------------------------
@@ -197,17 +260,12 @@ GDPopt implementation and optional arguments
GDPopt optional arguments should be considered beta code and are
subject to change.
-.. autoclass:: pyomo.contrib.gdpopt.GDPopt.GDPoptSolver
- :members:
-
-.. autoclass:: pyomo.contrib.gdpopt.loa.GDP_LOA_Solver
- :members:
-
-.. autoclass:: pyomo.contrib.gdpopt.gloa.GDP_GLOA_Solver
- :members:
+.. autosummary::
-.. autoclass:: pyomo.contrib.gdpopt.ric.GDP_RIC_Solver
- :members:
+ ~pyomo.contrib.gdpopt.GDPopt.GDPoptSolver
+ ~pyomo.contrib.gdpopt.loa.GDP_LOA_Solver
+ ~pyomo.contrib.gdpopt.gloa.GDP_GLOA_Solver
+ ~pyomo.contrib.gdpopt.ric.GDP_RIC_Solver
+ ~pyomo.contrib.gdpopt.branch_and_bound.GDP_LBB_Solver
+ ~pyomo.contrib.gdpopt.ldsda.GDP_LDSDA_Solver
-.. autoclass:: pyomo.contrib.gdpopt.branch_and_bound.GDP_LBB_Solver
- :members:
diff --git a/doc/OnlineDocs/contributed_packages/gdpopt_flowchart.png b/doc/OnlineDocs/explanation/solvers/gdpopt_flowchart.png
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/gdpopt_flowchart.png
rename to doc/OnlineDocs/explanation/solvers/gdpopt_flowchart.png
diff --git a/doc/OnlineDocs/explanation/solvers/index.rst b/doc/OnlineDocs/explanation/solvers/index.rst
new file mode 100644
index 00000000000..a50a604f93e
--- /dev/null
+++ b/doc/OnlineDocs/explanation/solvers/index.rst
@@ -0,0 +1,15 @@
+Solvers
+=======
+
+.. toctree::
+ :maxdepth: 2
+
+ persistent
+ gdpopt
+ pyros
+ mindtpy
+ mcpp
+ multistart
+ trustregion
+ pynumero/index
+ z3_interface
diff --git a/doc/OnlineDocs/contributed_packages/mcpp.rst b/doc/OnlineDocs/explanation/solvers/mcpp.rst
similarity index 99%
rename from doc/OnlineDocs/contributed_packages/mcpp.rst
rename to doc/OnlineDocs/explanation/solvers/mcpp.rst
index 18cea7f9b20..b25868e37ad 100644
--- a/doc/OnlineDocs/contributed_packages/mcpp.rst
+++ b/doc/OnlineDocs/explanation/solvers/mcpp.rst
@@ -1,3 +1,5 @@
+.. _MC++:
+
MC++ Interface
==============
diff --git a/doc/OnlineDocs/contributed_packages/mindtpy.rst b/doc/OnlineDocs/explanation/solvers/mindtpy.rst
similarity index 90%
rename from doc/OnlineDocs/contributed_packages/mindtpy.rst
rename to doc/OnlineDocs/explanation/solvers/mindtpy.rst
index a850a42c740..60a3f0a816a 100644
--- a/doc/OnlineDocs/contributed_packages/mindtpy.rst
+++ b/doc/OnlineDocs/explanation/solvers/mindtpy.rst
@@ -11,22 +11,21 @@ The following algorithms are currently available in MindtPy:
- **Outer-Approximation (OA)** [`Duran & Grossmann, 1986`_]
- **LP/NLP based Branch-and-Bound (LP/NLP BB)** [`Quesada & Grossmann, 1992`_]
- **Extended Cutting Plane (ECP)** [`Westerlund & Petterson, 1995`_]
-- **Global Outer-Approximation (GOA)** [`Kesavan & Allgor, 2004`_, `MC++`_]
+- **Global Outer-Approximation (GOA)** [`Kesavan & Allgor, 2004`_]
- **Regularized Outer-Approximation (ROA)** [`Bernal & Peng, 2021`_, `Kronqvist & Bernal, 2018`_]
- **Feasibility Pump (FP)** [`Bernal & Vigerske, 2019`_, `Bonami & Cornuéjols, 2009`_]
Usage and early implementation details for MindtPy can be found in the PSE 2018 paper Bernal et al.,
(`ref `_,
-`preprint `_).
+`preprint `_).
This solver implementation has been developed by `David Bernal `_
and `Zedong Peng `_ as part of research efforts at the `Bernal Research Group
-`_ and the `Grossmann Research Group `_
+`_ and the `Grossmann Research Group `_
at Purdue University and Carnegie Mellon University.
.. _Duran & Grossmann, 1986: https://dx.doi.org/10.1007/BF02592064
.. _Westerlund & Petterson, 1995: http://dx.doi.org/10.1016/0098-1354(95)87027-X
.. _Kesavan & Allgor, 2004: https://link.springer.com/article/10.1007/s10107-004-0503-1
-.. _MC++: https://pyomo.readthedocs.io/en/stable/contributed_packages/mcpp.html
.. _Bernal & Peng, 2021: http://www.optimization-online.org/DB_HTML/2021/06/8452.html
.. _Kronqvist & Bernal, 2018: https://link.springer.com/article/10.1007%2Fs10107-018-1356-3
.. _Bonami & Cornuéjols, 2009: https://link.springer.com/article/10.1007/s10107-008-0212-2
@@ -66,28 +65,28 @@ Usage of MindtPy to solve a convex MINLP Pyomo model involves:
.. code::
- >>> SolverFactory('mindtpy').solve(model)
+ >>> pyo.SolverFactory('mindtpy').solve(model)
An example which includes the modeling approach may be found below.
.. doctest::
Required imports
- >>> from pyomo.environ import *
+ >>> import pyomo.environ as pyo
Create a simple model
- >>> model = ConcreteModel()
+ >>> model = pyo.ConcreteModel()
- >>> model.x = Var(bounds=(1.0,10.0),initialize=5.0)
- >>> model.y = Var(within=Binary)
+ >>> model.x = pyo.Var(bounds=(1.0,10.0),initialize=5.0)
+ >>> model.y = pyo.Var(within=pyo.Binary)
- >>> model.c1 = Constraint(expr=(model.x-4.0)**2 - model.x <= 50.0*(1-model.y))
- >>> model.c2 = Constraint(expr=model.x*log(model.x)+5.0 <= 50.0*(model.y))
+ >>> model.c1 = pyo.Constraint(expr=(model.x-4.0)**2 - model.x <= 50.0*(1-model.y))
+ >>> model.c2 = pyo.Constraint(expr=model.x*pyo.log(model.x)+5.0 <= 50.0*(model.y))
- >>> model.objective = Objective(expr=model.x, sense=minimize)
+ >>> model.objective = pyo.Objective(expr=model.x, sense=pyo.minimize)
Solve the model using MindtPy
- >>> SolverFactory('mindtpy').solve(model, mip_solver='glpk', nlp_solver='ipopt') # doctest: +SKIP
+ >>> pyo.SolverFactory('mindtpy').solve(model, mip_solver='glpk', nlp_solver='ipopt') # doctest: +SKIP
The solution may then be displayed by using the commands
@@ -104,13 +103,13 @@ The solution may then be displayed by using the commands
.. code::
- >>> SolverFactory('mindtpy').solve(model, mip_solver='glpk', nlp_solver='ipopt', tee=True)
+ >>> pyo.SolverFactory('mindtpy').solve(model, mip_solver='glpk', nlp_solver='ipopt', tee=True)
MindtPy also supports setting options for mip solvers and nlp solvers.
.. code::
- >>> SolverFactory('mindtpy').solve(model,
+ >>> pyo.SolverFactory('mindtpy').solve(model,
strategy='OA',
time_limit=3600,
mip_solver='gams',
@@ -130,9 +129,8 @@ The LP/NLP based branch-and-bound algorithm in MindtPy is implemented based on t
.. note::
- In Pyomo, `persistent solvers`_ are necessary to set or register callback functions. The single tree implementation currently only works with CPLEX and GUROBI, more exactly ``cplex_persistent`` and ``gurobi_persistent``. To use the `LazyConstraintCallback`_ function of CPLEX from Pyomo, the `CPLEX Python API`_ is required. This means both IBM ILOG CPLEX Optimization Studio and the CPLEX-Python modules should be installed on your computer. To use the `cbLazy`_ function of GUROBI from pyomo, `gurobipy`_ is required.
+ In Pyomo, :ref:`persistent solvers ` are necessary to set or register callback functions. The single tree implementation currently only works with CPLEX and GUROBI, more exactly ``cplex_persistent`` and ``gurobi_persistent``. To use the `LazyConstraintCallback`_ function of CPLEX from Pyomo, the `CPLEX Python API`_ is required. This means both IBM ILOG CPLEX Optimization Studio and the CPLEX-Python modules should be installed on your computer. To use the `cbLazy`_ function of GUROBI from pyomo, `gurobipy`_ is required.
-.. _`persistent solvers`: https://pyomo.readthedocs.io/en/stable/advanced_topics/persistent_solvers.html?highlight=persistent
.. _CPLEX Python API: https://www.ibm.com/docs/en/icos/20.1.0?topic=cplex-setting-up-python-api
.. _gurobipy: https://www.gurobi.com/documentation/9.1/quickstart_mac/cs_grbpy_the_gurobi_python.html
.. _LazyConstraintCallback: https://www.ibm.com/docs/en/icos/20.1.0?topic=classes-cplexcallbackslazyconstraintcallback
@@ -257,7 +255,7 @@ Augmented Penalty refers to the introduction of (non-negative) slack variables o
Global Outer-Approximation
^^^^^^^^^^^^^^^^^^^^^^^^^^
-Apart from the decomposition methods for convex MINLP problems [`Kronqvist et al., 2019`_], MindtPy provides an implementation of Global Outer Approximation (GOA) as described in [`Kesavan & Allgor, 2004`_], to provide optimality guaranteed for nonconvex MINLP problems. Here, the validity of the Mixed-integer Linear Programming relaxation of the original problem is guaranteed via the usage of Generalized McCormick envelopes, computed using the package `MC++`_. The NLP subproblems, in this case, need to be solved to global optimality, which can be achieved through global NLP solvers such as `BARON`_ or `SCIP`_.
+Apart from the decomposition methods for convex MINLP problems [`Kronqvist et al., 2019`_], MindtPy provides an implementation of Global Outer Approximation (GOA) as described in [`Kesavan & Allgor, 2004`_], to provide optimality guaranteed for nonconvex MINLP problems. Here, the validity of the Mixed-integer Linear Programming relaxation of the original problem is guaranteed via the usage of Generalized McCormick envelopes, computed using the :ref:`interface to the MC++ package `. The NLP subproblems, in this case, need to be solved to global optimality, which can be achieved through global NLP solvers such as `BARON`_ or `SCIP`_.
.. _BARON: https://minlp.com/baron-solver
.. _SCIP: https://www.scipopt.org/
@@ -301,6 +299,7 @@ MindtPy Implementation and Optional Arguments
subject to change.
.. autoclass:: pyomo.contrib.mindtpy.MindtPy.MindtPySolver
+ :noindex:
:members:
Get Help
diff --git a/doc/OnlineDocs/contributed_packages/multistart.rst b/doc/OnlineDocs/explanation/solvers/multistart.rst
similarity index 70%
rename from doc/OnlineDocs/contributed_packages/multistart.rst
rename to doc/OnlineDocs/explanation/solvers/multistart.rst
index 069d770aa91..39406a3bb6f 100644
--- a/doc/OnlineDocs/contributed_packages/multistart.rst
+++ b/doc/OnlineDocs/explanation/solvers/multistart.rst
@@ -14,21 +14,22 @@ To use the multistart solver, define your Pyomo model as usual:
.. doctest::
Required import
- >>> from pyomo.environ import *
+ >>> import pyomo.environ as pyo
Create a simple model
- >>> m = ConcreteModel()
- >>> m.x = Var()
- >>> m.y = Var()
- >>> m.obj = Objective(expr=m.x**2 + m.y**2)
- >>> m.c = Constraint(expr=m.y >= -2*m.x + 5)
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var()
+ >>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+ >>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
Invoke the multistart solver
- >>> SolverFactory('multistart').solve(m) # doctest: +SKIP
+ >>> pyo.SolverFactory('multistart').solve(m) # doctest: +SKIP
Multistart wrapper implementation and optional arguments
--------------------------------------------------------
.. autoclass:: pyomo.contrib.multistart.multi.MultiStart
+ :noindex:
:members:
diff --git a/doc/OnlineDocs/advanced_topics/persistent_solvers.rst b/doc/OnlineDocs/explanation/solvers/persistent.rst
similarity index 73%
rename from doc/OnlineDocs/advanced_topics/persistent_solvers.rst
rename to doc/OnlineDocs/explanation/solvers/persistent.rst
index aebb0545dd0..e9680c641bb 100644
--- a/doc/OnlineDocs/advanced_topics/persistent_solvers.rst
+++ b/doc/OnlineDocs/explanation/solvers/persistent.rst
@@ -1,3 +1,5 @@
+.. _persistent_solvers:
+
Persistent Solvers
==================
@@ -6,7 +8,7 @@ notify the solver of incremental changes to a Pyomo model. The
persistent solver interfaces create and store model instances from the
Python API for the corresponding solver. For example, the
:class:`GurobiPersistent`
-class maintaints a pointer to a gurobipy Model object. Thus, we can
+class maintains a pointer to a gurobipy Model object. Thus, we can
make small changes to the model and notify the solver rather than
recreating the entire model using the solver Python API (or rewriting
an entire model file - e.g., an lp file) every time the model is
@@ -22,16 +24,16 @@ Using Persistent Solvers
The first step in using a persistent solver is to create a Pyomo model
as usual.
->>> import pyomo.environ as pe
->>> m = pe.ConcreteModel()
->>> m.x = pe.Var()
->>> m.y = pe.Var()
->>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
->>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5)
+>>> import pyomo.environ as pyo
+>>> m = pyo.ConcreteModel()
+>>> m.x = pyo.Var()
+>>> m.y = pyo.Var()
+>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
You can create an instance of a persistent solver through the SolverFactory.
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
This returns an instance of :py:class:`GurobiPersistent`. Now we need
to tell the solver about our model.
@@ -46,7 +48,7 @@ variables and constraints. We can now solve the model.
We can also add or remove variables, constraints, blocks, and
objectives. For example,
->>> m.c2 = pe.Constraint(expr=m.y >= m.x) # doctest: +SKIP
+>>> m.c2 = pyo.Constraint(expr=m.y >= m.x) # doctest: +SKIP
>>> opt.add_constraint(m.c2) # doctest: +SKIP
This tells the solver to add one new constraint but otherwise leave
@@ -67,29 +69,29 @@ code will run without error, but the solver will have an extra
constraint. The solver will have both y >= -2*x + 5 and y <= x, which
is not what was intended!
->>> m = pe.ConcreteModel() # doctest: +SKIP
->>> m.x = pe.Var() # doctest: +SKIP
->>> m.y = pe.Var() # doctest: +SKIP
->>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> m = pyo.ConcreteModel() # doctest: +SKIP
+>>> m.x = pyo.Var() # doctest: +SKIP
+>>> m.y = pyo.Var() # doctest: +SKIP
+>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
>>> opt.set_instance(m) # doctest: +SKIP
>>> # WRONG:
>>> del m.c # doctest: +SKIP
->>> m.c = pe.Constraint(expr=m.y <= m.x) # doctest: +SKIP
+>>> m.c = pyo.Constraint(expr=m.y <= m.x) # doctest: +SKIP
>>> opt.add_constraint(m.c) # doctest: +SKIP
The correct way to do this is:
->>> m = pe.ConcreteModel() # doctest: +SKIP
->>> m.x = pe.Var() # doctest: +SKIP
->>> m.y = pe.Var() # doctest: +SKIP
->>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> m = pyo.ConcreteModel() # doctest: +SKIP
+>>> m.x = pyo.Var() # doctest: +SKIP
+>>> m.y = pyo.Var() # doctest: +SKIP
+>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
>>> opt.set_instance(m) # doctest: +SKIP
>>> # Correct:
>>> opt.remove_constraint(m.c) # doctest: +SKIP
>>> del m.c # doctest: +SKIP
->>> m.c = pe.Constraint(expr=m.y <= m.x) # doctest: +SKIP
+>>> m.c = pyo.Constraint(expr=m.y <= m.x) # doctest: +SKIP
>>> opt.add_constraint(m.c) # doctest: +SKIP
.. warning:: Components removed from a pyomo model must be removed
@@ -98,14 +100,14 @@ The correct way to do this is:
Additionally, unexpected behavior may result if a component is
modified before being removed.
->>> m = pe.ConcreteModel() # doctest: +SKIP
->>> m.b = pe.Block() # doctest: +SKIP
->>> m.b.x = pe.Var() # doctest: +SKIP
->>> m.b.y = pe.Var() # doctest: +SKIP
->>> m.b.c = pe.Constraint(expr=m.b.y >= -2*m.b.x + 5) # doctest: +SKIP
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> m = pyo.ConcreteModel() # doctest: +SKIP
+>>> m.b = pyo.Block() # doctest: +SKIP
+>>> m.b.x = pyo.Var() # doctest: +SKIP
+>>> m.b.y = pyo.Var() # doctest: +SKIP
+>>> m.b.c = pyo.Constraint(expr=m.b.y >= -2*m.b.x + 5) # doctest: +SKIP
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
>>> opt.set_instance(m) # doctest: +SKIP
->>> m.b.c2 = pe.Constraint(expr=m.b.y <= m.b.x) # doctest: +SKIP
+>>> m.b.c2 = pyo.Constraint(expr=m.b.y <= m.b.x) # doctest: +SKIP
>>> # ERROR: The constraint referenced by m.b.c2 does not
>>> # exist in the solver model.
>>> opt.remove_block(m.b) # doctest: +SKIP
@@ -115,12 +117,12 @@ the solver instance, modify it with Pyomo, and then add it back to the
solver instance. The only exception is with variables. Variables may
be modified and then updated with with solver:
->>> m = pe.ConcreteModel() # doctest: +SKIP
->>> m.x = pe.Var() # doctest: +SKIP
->>> m.y = pe.Var() # doctest: +SKIP
->>> m.obj = pe.Objective(expr=m.x**2 + m.y**2) # doctest: +SKIP
->>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> m = pyo.ConcreteModel() # doctest: +SKIP
+>>> m.x = pyo.Var() # doctest: +SKIP
+>>> m.y = pyo.Var() # doctest: +SKIP
+>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2) # doctest: +SKIP
+>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5) # doctest: +SKIP
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
>>> opt.set_instance(m) # doctest: +SKIP
>>> m.x.setlb(1.0) # doctest: +SKIP
>>> opt.update_var(m.x) # doctest: +SKIP
@@ -158,13 +160,13 @@ Persistent Solver Performance
In order to get the best performance out of the persistent solvers, use the
"save_results" flag:
->>> import pyomo.environ as pe
->>> m = pe.ConcreteModel()
->>> m.x = pe.Var()
->>> m.y = pe.Var()
->>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
->>> m.c = pe.Constraint(expr=m.y >= -2*m.x + 5)
->>> opt = pe.SolverFactory('gurobi_persistent') # doctest: +SKIP
+>>> import pyomo.environ as pyo
+>>> m = pyo.ConcreteModel()
+>>> m.x = pyo.Var()
+>>> m.y = pyo.Var()
+>>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+>>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
+>>> opt = pyo.SolverFactory('gurobi_persistent') # doctest: +SKIP
>>> opt.set_instance(m) # doctest: +SKIP
>>> results = opt.solve(save_results=False) # doctest: +SKIP
diff --git a/doc/OnlineDocs/explanation/solvers/pynumero/backward_compatibility.rst b/doc/OnlineDocs/explanation/solvers/pynumero/backward_compatibility.rst
new file mode 100644
index 00000000000..036a00bee62
--- /dev/null
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/backward_compatibility.rst
@@ -0,0 +1,14 @@
+Backward Compatibility
+======================
+
+While PyNumero is a third-party contribution to Pyomo, we intend to maintain
+the stability of its core functionality. The core functionality of PyNumero
+consists of:
+
+1. The ``NLP`` API and ``PyomoNLP`` implementation of this API
+2. HSL and MUMPS linear solver interfaces
+3. ``BlockVector`` and ``BlockMatrix`` classes
+4. CyIpopt and SciPy solver interfaces
+
+Other parts of PyNumero, such as ``ExternalGreyBoxBlock`` and
+``ImplicitFunctionSolver``, are experimental and subject to change without notice.
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/index.rst b/doc/OnlineDocs/explanation/solvers/pynumero/index.rst
similarity index 82%
rename from doc/OnlineDocs/contributed_packages/pynumero/index.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/index.rst
index 6ff8b29f812..c0507e01db8 100644
--- a/doc/OnlineDocs/contributed_packages/pynumero/index.rst
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/index.rst
@@ -5,14 +5,20 @@ PyNumero
PyNumero is a package for developing parallel algorithms for nonlinear
programs (NLPs). This documentation provides a brief introduction to
-PyNumero. For more details, see the API documentation (:ref:`pynumero_api`).
+PyNumero. For more details, see the :mod:`API documentation `).
.. toctree::
:maxdepth: 2
installation.rst
tutorial.rst
- api.rst
+ backward_compatibility.rst
+
+
+PyNumero API
+------------
+
+:mod:`pyomo.contrib.pynumero`
Developers
@@ -40,11 +46,3 @@ Papers utilizing PyNumero
* Rodriguez, J. S., Laird, C. D., & Zavala, V. M. (2020). Scalable
preconditioning of block-structured linear algebra systems using
ADMM. Computers & Chemical Engineering, 133, 106478.
-
-
-Indices and Tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/installation.rst b/doc/OnlineDocs/explanation/solvers/pynumero/installation.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/pynumero/installation.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/installation.rst
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.block_vectors_and_matrices.rst b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.block_vectors_and_matrices.rst
similarity index 89%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.block_vectors_and_matrices.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.block_vectors_and_matrices.rst
index 1ce98ce4a63..a8a66e81a46 100644
--- a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.block_vectors_and_matrices.rst
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.block_vectors_and_matrices.rst
@@ -65,7 +65,7 @@ Once the dimensions of a block have been set, they cannot be changed:
Properties:
.. doctest::
- :skipif: not numpy_available or not scipy_available
+ :skipif: not scipy_available or int(np.__version__[0]) >= 2
>>> v.shape
(5,)
@@ -82,10 +82,29 @@ Properties:
>>> m.nnz
12
+.. doctest::
+ :hide:
+ :skipif: not scipy_available or int(np.__version__[0]) < 2
+
+ >>> v.shape
+ (np.int64(5),)
+ >>> v.size
+ np.int64(5)
+ >>> v.nblocks
+ 3
+ >>> v.bshape
+ (3,)
+ >>> m.shape
+ (np.int64(5), np.int64(5))
+ >>> m.bshape
+ (3, 3)
+ >>> m.nnz
+ 12
+
Much of the `BlockVector` API matches that of NumPy arrays:
.. doctest::
- :skipif: not numpy_available or not scipy_available
+ :skipif: not scipy_available or int(np.__version__[0]) >= 2
>>> v.sum()
0.62846552
@@ -100,6 +119,23 @@ Much of the `BlockVector` API matches that of NumPy arrays:
>>> v.dot(v)
4.781303326558476
+.. doctest::
+ :hide:
+ :skipif: not scipy_available or int(np.__version__[0]) < 2
+
+ >>> v.sum()
+ np.float64(0.62846552)
+ >>> v.max()
+ np.float64(1.25)
+ >>> np.abs(v).flatten()
+ array([0.67025575, 1.2 , 0.1 , 1.14872127, 1.25 ])
+ >>> (2*v).flatten()
+ array([-1.3405115 , -2.4 , 0.2 , 2.29744254, 2.5 ])
+ >>> (v + v).flatten()
+ array([-1.3405115 , -2.4 , 0.2 , 2.29744254, 2.5 ])
+ >>> v.dot(v)
+ np.float64(4.781303326558476)
+
Similarly, `BlockMatrix` behaves very similarly to SciPy sparse matrices:
.. doctest::
@@ -269,4 +305,4 @@ Nested blocks:
Nested `BlockMatrix` applications work similarly.
-For more information, see the API documentation (:ref:`pynumero_api`).
+For more information, see the :mod:`API documentation `.
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.linear_solver_interfaces.rst b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.linear_solver_interfaces.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.linear_solver_interfaces.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.linear_solver_interfaces.rst
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.mpi_blocks.rst b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.mpi_blocks.rst
similarity index 91%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.mpi_blocks.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.mpi_blocks.rst
index b9cb1d5db7a..e65d4da9c96 100644
--- a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.mpi_blocks.rst
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.mpi_blocks.rst
@@ -12,7 +12,7 @@ or all processes/ranks.
Consider the following example (in a file called "parallel_vector_ops.py").
-.. literalinclude:: ../../../../pyomo/contrib/pynumero/examples/parallel_vector_ops.py
+.. literalinclude:: /../../pyomo/contrib/pynumero/examples/parallel_vector_ops.py
This example can be run with
@@ -46,7 +46,7 @@ except that the operations are now performed in parallel.
`MPIBlockMatrix` construction is very similar. Consider the following
example in a file called "parallel_matvec.py".
-.. literalinclude:: ../../../../pyomo/contrib/pynumero/examples/parallel_matvec.py
+.. literalinclude:: /../../pyomo/contrib/pynumero/examples/parallel_matvec.py
Which can be run with
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.nlp_interfaces.rst b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst
similarity index 86%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.nlp_interfaces.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst
index 28818709330..13dd5d0e366 100644
--- a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.nlp_interfaces.rst
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst
@@ -2,15 +2,15 @@ NLP Interfaces
==============
Below are examples of using PyNumero's interfaces to ASL for function
-and derivative evaluation. More information can be found in the API
-documentation (:ref:`pynumero_api`).
+and derivative evaluation. More information can be found in the
+:mod:`API documentation `.
Relevant imports
.. doctest::
:skipif: not numpy_available or not scipy_available or not asl_available
- >>> import pyomo.environ as pe
+ >>> import pyomo.environ as pyo
>>> from pyomo.contrib.pynumero.interfaces.pyomo_nlp import PyomoNLP
>>> import numpy as np
@@ -19,12 +19,12 @@ Create a Pyomo model
.. doctest::
:skipif: not numpy_available or not scipy_available or not asl_available
- >>> m = pe.ConcreteModel()
- >>> m.x = pe.Var(bounds=(-5, None))
- >>> m.y = pe.Var(initialize=2.5)
- >>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
- >>> m.c1 = pe.Constraint(expr=m.y == (m.x - 1)**2)
- >>> m.c2 = pe.Constraint(expr=m.y >= pe.exp(m.x))
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var(bounds=(-5, None))
+ >>> m.y = pyo.Var(initialize=2.5)
+ >>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+ >>> m.c1 = pyo.Constraint(expr=m.y == (m.x - 1)**2)
+ >>> m.c2 = pyo.Constraint(expr=m.y >= pyo.exp(m.x))
Create a :py:class:`pyomo.contrib.pynumero.interfaces.pyomo_nlp.PyomoNLP` instance
diff --git a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.rst b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.rst
diff --git a/doc/OnlineDocs/contributed_packages/pyros.rst b/doc/OnlineDocs/explanation/solvers/pyros.rst
similarity index 82%
rename from doc/OnlineDocs/contributed_packages/pyros.rst
rename to doc/OnlineDocs/explanation/solvers/pyros.rst
index aad37a9685a..bc5f59e9a1c 100644
--- a/doc/OnlineDocs/contributed_packages/pyros.rst
+++ b/doc/OnlineDocs/explanation/solvers/pyros.rst
@@ -14,45 +14,47 @@ The developers gratefully acknowledge support from the U.S. Department of Energy
Methodology Overview
-----------------------------
-Below is an overview of the type of optimization models PyROS can accommodate.
+PyROS can accommodate optimization models with:
+* **Continuous variables** only
+* **Nonlinearities** (including **nonconvexities**) in both the
+ variables and uncertain parameters
+* **First-stage degrees of freedom** and **second-stage degrees of freedom**
+* **Equality constraints** defining state variables,
+ including implicitly defined state variables that cannot be
+ eliminated from the model via reformulation
+* **Inequality constraints** in the degree-of-freedom and/or state variables
-* PyROS is suitable for optimization models of **continuous variables**
- that may feature non-linearities (including **non-convexities**) in
- both the variables and uncertain parameters.
-* PyROS can handle **equality constraints** defining state variables,
- including implicit state variables that cannot be eliminated via
- reformulation.
-* PyROS allows for **two-stage** optimization problems that may
- feature both first-stage and second-stage degrees of freedom.
-
-PyROS is designed to operate on deterministic models of the general form
+Supported deterministic models can be written in the general form
.. _deterministic-model:
.. math::
- \begin{array}{clll}
+ :nowrap:
+
+ \[\begin{array}{clll}
\displaystyle \min_{\substack{x \in \mathcal{X}, \\ z \in \mathbb{R}^{n_z}, y\in\mathbb{R}^{n_y}}} & ~~ f_1\left(x\right) + f_2(x,z,y; q^{\text{nom}}) & \\
\displaystyle \text{s.t.} & ~~ g_i(x, z, y; q^{\text{nom}}) \leq 0 & \forall\,i \in \mathcal{I} \\
& ~~ h_j(x,z,y; q^{\text{nom}}) = 0 & \forall\,j \in \mathcal{J} \\
- \end{array}
+ \end{array}\]
where:
-* :math:`x \in \mathcal{X}` are the "design" variables
- (i.e., first-stage degrees of freedom),
- where :math:`\mathcal{X} \subseteq \mathbb{R}^{n_x}` is the feasible space defined by the model constraints
- (including variable bounds specifications) referencing :math:`x` only.
-* :math:`z \in \mathbb{R}^{n_z}` are the "control" variables
- (i.e., second-stage degrees of freedom)
+* :math:`x \in \mathcal{X}` are the first-stage degrees of freedom,
+ (or "design" variables,)
+ of which the feasible space :math:`\mathcal{X} \subseteq \mathbb{R}^{n_x}`
+ is defined by the model constraints
+ (including variable bounds specifications) referencing :math:`x` only
+* :math:`z \in \mathbb{R}^{n_z}` are the second-stage degrees of freedom
+ (or "control" variables)
* :math:`y \in \mathbb{R}^{n_y}` are the "state" variables
* :math:`q \in \mathbb{R}^{n_q}` is the vector of model parameters considered
uncertain, and :math:`q^{\text{nom}}` is the vector of nominal values
- associated with those.
-* :math:`f_1\left(x\right)` are the terms of the objective function that depend
+ associated with those
+* :math:`f_1\left(x\right)` is the summand of the objective function that depends
only on design variables
-* :math:`f_2\left(x, z, y; q\right)` are the terms of the objective function
- that depend on all variables and the uncertain parameters
+* :math:`f_2\left(x, z, y; q\right)` is the summand of the objective function
+ that depends on all variables and the uncertain parameters
* :math:`g_i\left(x, z, y; q\right)` is the :math:`i^\text{th}`
inequality constraint function in set :math:`\mathcal{I}`
(see :ref:`Note `)
@@ -63,23 +65,11 @@ where:
.. _var-bounds-to-ineqs:
.. note::
- PyROS accepts models in which bounds are directly imposed on
- ``Var`` objects representing components of the variables :math:`z`
- and :math:`y`. These models are cast to
- :ref:`the form above `
- by reformulating the bounds as inequality constraints.
-
-.. _unique-mapping:
+ PyROS accepts models in which there are:
-.. note::
- A key requirement of PyROS is that each value of :math:`\left(x, z, q \right)`
- maps to a unique value of :math:`y`, a property that is assumed to
- be properly enforced by the system of equality constraints
- :math:`\mathcal{J}`.
- If the mapping is not unique, then the selection of 'state'
- (i.e., not degree of freedom) variables :math:`y` is incorrect,
- and one or more of the :math:`y` variables should be appropriately
- redesignated to be part of either :math:`x` or :math:`z`.
+ 1. Bounds declared on the ``Var`` objects representing
+ components of the variable vectors
+ 2. Ranged inequality constraints
In order to cast the robust optimization counterpart of the
:ref:`deterministic model `,
@@ -89,21 +79,80 @@ any realization in a compact uncertainty set
the nominal value :math:`q^{\text{nom}}`.
The set :math:`\mathcal{Q}` may be **either continuous or discrete**.
-Based on the above notation, the form of the robust counterpart addressed by PyROS is
+Based on the above notation,
+the form of the robust counterpart addressed by PyROS is
.. math::
- \begin{array}{ccclll}
+ :nowrap:
+
+ \[\begin{array}{ccclll}
\displaystyle \min_{x \in \mathcal{X}}
& \displaystyle \max_{q \in \mathcal{Q}}
& \displaystyle \min_{\substack{z \in \mathbb{R}^{n_z},\\y \in \mathbb{R}^{n_y}}} \ \ & \displaystyle ~~ f_1\left(x\right) + f_2\left(x, z, y, q\right) \\
& & \text{s.t.}~ & \displaystyle ~~ g_i\left(x, z, y, q\right) \leq 0 & & \forall\, i \in \mathcal{I}\\
& & & \displaystyle ~~ h_j\left(x, z, y, q\right) = 0 & & \forall\,j \in \mathcal{J}
- \end{array}
+ \end{array}\]
+
+PyROS accepts a deterministic model and accompanying uncertainty set
+and then, using the Generalized Robust Cutting-Set algorithm developed
+in [IAE+21]_, seeks a solution to the robust counterpart.
+When using PyROS, please consider citing [IAE+21]_.
+
+.. _unique-mapping:
+
+.. note::
+ A key assumption of PyROS is that
+ for every
+ :math:`x \in \mathcal{X}`,
+ :math:`z \in \mathbb{R}^{n_z}`,
+ :math:`q \in \mathcal{Q}`,
+ there exists a unique :math:`y \in \mathbb{R}^{n_y}`
+ for which :math:`(x, z, y, q)`
+ satisfies the equality constraints
+ :math:`h_j(x, z, y, q) = 0\,\,\forall\, j \in \mathcal{J}`.
+ If this assumption is not met,
+ then the selection of 'state'
+ (i.e., not degree of freedom) variables :math:`y` is incorrect,
+ and one or more of the :math:`y` variables should be appropriately
+ redesignated to be part of either :math:`x` or :math:`z`.
+
+PyROS Installation
+-----------------------------
+PyROS can be installed as follows:
+
+1. :ref:`Install Pyomo `.
+ PyROS is included in the Pyomo software package, at pyomo/contrib/pyros.
+2. Install NumPy and SciPy with your preferred package manager;
+ both NumPy and SciPy are required dependencies of PyROS.
+ You may install NumPy and SciPy with, for example, ``conda``:
+
+ ::
+
+ conda install numpy scipy
+
+ or ``pip``:
+
+ ::
-PyROS solves problems of this form using the
-Generalized Robust Cutting-Set algorithm developed in [Isenberg_et_al]_.
+ pip install numpy scipy
+3. (*Optional*) Test your installation:
+ install ``pytest`` and ``parameterized``
+ with your preferred package manager (as in the previous step):
+
+ ::
+
+ pip install pytest parameterized
+
+ You may then run the PyROS tests as follows:
+
+ ::
+
+ python -c 'import os, pytest, pyomo.contrib.pyros as p; pytest.main([os.path.dirname(p.__file__)])'
+
+ Some tests involving solvers may fail or be skipped,
+ depending on the solver distributions (e.g., Ipopt, BARON, SCIP)
+ that you have pre-installed and licensed on your system.
-When using PyROS, please consider citing the above paper.
PyROS Required Inputs
-----------------------------
@@ -128,16 +177,20 @@ These are more elaborately presented in the
PyROS Solver Interface
-----------------------------
+The PyROS solver is invoked through the
+:py:meth:`~pyomo.contrib.pyros.pyros.PyROS.solve` method.
+
.. autoclass:: pyomo.contrib.pyros.PyROS
:members: solve
+ :noindex:
.. note::
Upon successful convergence of PyROS, the solution returned is
certified to be robust optimal only if:
- 1. master problems are solved to global optimality
+ 1. Master problems are solved to global optimality
(by specifying ``solve_master_globally=True``)
- 2. a worst-case objective focus is chosen
+ 2. A worst-case objective focus is chosen
(by specifying ``objective_focus=ObjectiveType.worst_case``)
Otherwise, the solution returned is certified to only be robust feasible.
@@ -211,52 +264,25 @@ the various abstract and pre-implemented
PyROS Uncertainty Set Classes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.BoxSet
- :show-inheritance:
- :special-members: bounds, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.CardinalitySet
- :show-inheritance:
- :special-members: origin, positive_deviation, gamma, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.BudgetSet
- :show-inheritance:
- :special-members: coefficients_mat, rhs_vec, origin, budget_membership_mat, budget_rhs_vec, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.FactorModelSet
- :show-inheritance:
- :special-members: origin, number_of_factors, psi_mat, beta, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.PolyhedralSet
- :show-inheritance:
- :special-members: coefficients_mat, rhs_vec, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.AxisAlignedEllipsoidalSet
- :show-inheritance:
- :special-members: center, half_lengths, type, parameter_bounds, dim, point_in_set
+.. autosummary::
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.EllipsoidalSet
- :show-inheritance:
- :special-members: center, shape_matrix, scale, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.UncertaintySet
- :show-inheritance:
- :special-members: parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.DiscreteScenarioSet
- :show-inheritance:
- :special-members: scenarios, type, parameter_bounds, dim, point_in_set
-
-.. autoclass:: pyomo.contrib.pyros.uncertainty_sets.IntersectionSet
- :show-inheritance:
- :special-members: all_sets, type, parameter_bounds, dim, point_in_set
+ ~pyomo.contrib.pyros.uncertainty_sets.UncertaintySet
+ ~pyomo.contrib.pyros.uncertainty_sets.BoxSet
+ ~pyomo.contrib.pyros.uncertainty_sets.CardinalitySet
+ ~pyomo.contrib.pyros.uncertainty_sets.BudgetSet
+ ~pyomo.contrib.pyros.uncertainty_sets.FactorModelSet
+ ~pyomo.contrib.pyros.uncertainty_sets.PolyhedralSet
+ ~pyomo.contrib.pyros.uncertainty_sets.AxisAlignedEllipsoidalSet
+ ~pyomo.contrib.pyros.uncertainty_sets.EllipsoidalSet
+ ~pyomo.contrib.pyros.uncertainty_sets.DiscreteScenarioSet
+ ~pyomo.contrib.pyros.uncertainty_sets.IntersectionSet
PyROS Usage Example
-----------------------------
In this section, we illustrate the usage of PyROS with a modeling example.
-The deterministic problem of interest is called *hydro*
+The deterministic problem of interest is called *hydro*
(available `here `_),
a QCQP taken from the
`GAMS Model Library `_.
@@ -305,23 +331,30 @@ The deterministic Pyomo model for *hydro* is shown below.
.. note::
Primitive data (Python literals) that have been hard-coded within a
- deterministic model cannot be later considered uncertain,
- unless they are first converted to ``Param`` objects within
- the ``ConcreteModel`` object.
- Furthermore, any ``Param`` object that is to be later considered
- uncertain must have the property ``mutable=True``.
+ deterministic model (:class:`~pyomo.core.base.PyomoModel.ConcreteModel`)
+ cannot be later considered uncertain,
+ unless they are first converted to Pyomo
+ :class:`~pyomo.core.base.param.Param` instances declared on the
+ :class:`~pyomo.core.base.PyomoModel.ConcreteModel` object.
+ Furthermore, any :class:`~pyomo.core.base.param.Param`
+ object that is to be later considered uncertain must be instantiated
+ with the argument ``mutable=True``.
.. note::
- In case modifying the ``mutable`` property inside the deterministic
- model object itself is not straightforward in your context,
- you may consider adding the following statement **after**
+ If specifying/modifying the ``mutable`` argument in the
+ :class:`~pyomo.core.base.param.Param` declarations
+ of your deterministic model source code
+ is not straightforward in your context, then
+ you may consider adding **after** the line
``import pyomo.environ as pyo`` but **before** defining the model
- object: ``pyo.Param.DefaultMutable = True``.
- For all ``Param`` objects declared after this statement,
- the attribute ``mutable`` is set to ``True`` by default.
- Hence, non-mutable ``Param`` objects are now declared by
- explicitly passing the argument ``mutable=False`` to the
- ``Param`` constructor.
+ object the statement: ``pyo.Param.DefaultMutable = True``.
+ For all :class:`~pyomo.core.base.param.Param`
+ objects declared after this statement,
+ the attribute ``mutable`` is set to True by default.
+ Hence, non-mutable :class:`~pyomo.core.base.param.Param`
+ objects are now declared by explicitly passing the argument
+ ``mutable=False`` to the :class:`~pyomo.core.base.param.Param`
+ constructor.
.. doctest::
@@ -404,22 +437,37 @@ The deterministic Pyomo model for *hydro* is shown below.
Step 2: Define the Uncertainty
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-First, we need to collect into a list those ``Param`` objects of our model
-that represent potentially uncertain parameters.
-For the purposes of our example, we shall assume uncertainty in the model
-parameters ``[m.p[0], m.p[1], m.p[2], m.p[3]]``, for which we can
-conveniently utilize the object ``m.p`` (itself an indexed ``Param`` object).
+We first collect the components of our model that represent the
+uncertain parameters.
+In this example, we assume uncertainty in
+the parameter objects ``m.p[0]``, ``m.p[1]``, ``m.p[2]``, and ``m.p[3]``.
+Since these objects comprise the mutable :class:`~pyomo.core.base.param.Param`
+object ``m.p``, we can conveniently specify:
.. doctest::
- >>> # === Specify which parameters are uncertain ===
- >>> # We can pass IndexedParams this way to PyROS,
- >>> # or as an expanded list per index
- >>> uncertain_parameters = [m.p]
+ >>> uncertain_params = m.p
+
+Equivalently, we may instead set ``uncertain_params`` to
+either ``[m.p]``, ``[m.p[0], m.p[1], m.p[2], m.p[3]]``,
+or ``list(m.p.values())``.
+
+.. note::
+ Any :class:`~pyomo.core.base.param.Param` object that is
+ to be considered uncertain by PyROS must have the property
+ ``mutable=True``.
.. note::
- Any ``Param`` object that is to be considered uncertain by PyROS
- must have the property ``mutable=True``.
+ PyROS also allows uncertain parameters to be implemented as
+ :class:`~pyomo.core.base.var.Var` objects declared on the
+ deterministic model.
+ This may be convenient for users transitioning to PyROS from
+ parameter estimation and/or uncertainty quantification workflows,
+ in which the uncertain parameters are
+ often represented by :class:`~pyomo.core.base.var.Var` objects.
+ Prior to invoking PyROS,
+ all such :class:`~pyomo.core.base.var.Var` objects should be fixed.
+
PyROS will seek to identify solutions that remain feasible for any
realization of these parameters included in an uncertainty set.
@@ -466,7 +514,7 @@ global NLP solver:
.. note::
Additional NLP optimizers can be automatically used in the event the primary
subordinate local or global optimizer passed
- to the PyROS :meth:`~pyomo.contrib.pyros.PyROS.solve` method
+ to the PyROS :meth:`~pyomo.contrib.pyros.pyros.PyROS.solve` method
does not successfully solve a subproblem to an appropriate termination
condition. These alternative solvers are provided through the optional
keyword arguments ``backup_local_solvers`` and ``backup_global_solvers``.
@@ -531,7 +579,7 @@ correspond to first-stage degrees of freedom.
... model=m,
... first_stage_variables=first_stage_variables,
... second_stage_variables=second_stage_variables,
- ... uncertain_params=uncertain_parameters,
+ ... uncertain_params=uncertain_params,
... uncertainty_set=box_uncertainty_set,
... local_solver=local_solver,
... global_solver=global_solver,
@@ -575,7 +623,7 @@ The :ref:`preceding code snippet `
demonstrates how to retrieve this information.
If we pass ``load_solution=True`` (the default setting)
-to the :meth:`~pyomo.contrib.pyros.PyROS.solve` method,
+to the :meth:`~pyomo.contrib.pyros.pyros.PyROS.solve` method,
then the solution at which PyROS terminates will be loaded to
the variables of the original deterministic model.
Note that in the :ref:`preceding code snippet `,
@@ -605,7 +653,7 @@ freedom are in fact second-stage degrees of freedom.
PyROS handles second-stage degrees of freedom via the use of polynomial
decision rules, of which the degree is controlled through the
optional keyword argument ``decision_rule_order`` to the PyROS
-:meth:`~pyomo.contrib.pyros.PyROS.solve` method.
+:meth:`~pyomo.contrib.pyros.pyros.PyROS.solve` method.
In this example, we select affine decision rules by setting
``decision_rule_order=1``:
@@ -624,7 +672,7 @@ In this example, we select affine decision rules by setting
... model=m,
... first_stage_variables=first_stage_variables,
... second_stage_variables=second_stage_variables,
- ... uncertain_params=uncertain_parameters,
+ ... uncertain_params=uncertain_params,
... uncertainty_set=box_uncertainty_set,
... local_solver=local_solver,
... global_solver=global_solver,
@@ -662,10 +710,10 @@ to an affine decision rule.
Specifying Arguments Indirectly Through ``options``
"""""""""""""""""""""""""""""""""""""""""""""""""""
Like other Pyomo solver interface methods,
-:meth:`~pyomo.contrib.pyros.PyROS.solve`
+:meth:`~pyomo.contrib.pyros.pyros.PyROS.solve`
provides support for specifying options indirectly by passing
a keyword argument ``options``, whose value must be a :class:`dict`
-mapping names of arguments to :meth:`~pyomo.contrib.pyros.PyROS.solve`
+mapping names of arguments to :meth:`~pyomo.contrib.pyros.pyros.PyROS.solve`
to their desired values.
For example, the ``solve()`` statement in the
:ref:`two-stage problem snippet `
@@ -678,7 +726,7 @@ could have been equivalently written as:
... model=m,
... first_stage_variables=first_stage_variables,
... second_stage_variables=second_stage_variables,
- ... uncertain_params=uncertain_parameters,
+ ... uncertain_params=uncertain_params,
... uncertainty_set=box_uncertainty_set,
... local_solver=local_solver,
... global_solver=global_solver,
@@ -689,7 +737,7 @@ could have been equivalently written as:
... },
... )
==============================================================================
- PyROS: The Pyomo Robust Optimization Solver.
+ PyROS: The Pyomo Robust Optimization Solver...
...
------------------------------------------------------------------------------
Robust optimal solution identified.
@@ -744,7 +792,7 @@ instance and invoking the PyROS solver:
... model=m,
... first_stage_variables=first_stage_variables,
... second_stage_variables=second_stage_variables,
- ... uncertain_params=uncertain_parameters,
+ ... uncertain_params=uncertain_params,
... uncertainty_set= box_uncertainty_set,
... local_solver=local_solver,
... global_solver=global_solver,
@@ -799,7 +847,7 @@ PyROS Solver Log Output
The PyROS solver log output is controlled through the optional
``progress_logger`` argument, itself cast to
a standard Python logger (:py:class:`logging.Logger`) object
-at the outset of a :meth:`~pyomo.contrib.pyros.PyROS.solve` call.
+at the outset of a :meth:`~pyomo.contrib.pyros.pyros.PyROS.solve` call.
The level of detail of the solver log output
can be adjusted by adjusting the level of the
logger object; see :ref:`the following table `.
@@ -836,11 +884,12 @@ for a basic tutorial, see the :doc:`logging HOWTO `.
* Iteration log table
* Termination details: message, timing breakdown, summary of statistics
* - :py:obj:`logging.DEBUG`
- - * Termination outcomes and summary of statistics for
+ - * Progress through the various preprocessing subroutines
+ * Termination outcomes and summary of statistics for
every master feasility, master, and DR polishing problem
* Progress updates for the separation procedure
* Separation subproblem initial point infeasibilities
- * Summary of separation loop outcomes: performance constraints
+ * Summary of separation loop outcomes: second-stage inequality constraints
violated, uncertain parameter scenario added to the
master problem
* Uncertain parameter scenarios added to the master problem
@@ -861,12 +910,23 @@ Observe that the log contains the following information:
* **Preprocessing information** (lines 39--41).
Wall time required for preprocessing
the deterministic model and associated components,
- i.e. standardizing model components and adding the decision rule
+ i.e., standardizing model components and adding the decision rule
variables and equations.
* **Model component statistics** (lines 42--58).
Breakdown of model component statistics.
Includes components added by PyROS, such as the decision rule variables
and equations.
+ The preprocessor may find that some second-stage variables
+ and state variables are mathematically
+ not adjustable to the uncertain parameters.
+ To this end, in the logs, the numbers of
+ adjustable second-stage variables and state variables
+ are included in parentheses, next to the total numbers
+ of second-stage variables and state variables, respectively;
+ note that "adjustable" has been abbreviated as "adj."
+ The number of truly uncertain parameters detected during preprocessing
+ is also noted in parentheses
+ (in which "eff." is an abbreviation for "effective").
* **Iteration log table** (lines 59--69).
Summary information on the problem iterates and subproblem outcomes.
The constituent columns are defined in detail in
@@ -903,16 +963,16 @@ Observe that the log contains the following information:
:linenos:
==============================================================================
- PyROS: The Pyomo Robust Optimization Solver, v1.2.9.
- Pyomo version: 6.7.0
- Commit hash: unknown
- Invoked at UTC 2023-12-16T00:00:00.000000
+ PyROS: The Pyomo Robust Optimization Solver, v1.3.6.
+ Pyomo version: 6.9.2
+ Commit hash: 41cd797e0
+ Invoked at UTC 2025-03-13T16:20:31.105320+00:00
Developed by: Natalie M. Isenberg (1), Jason A. F. Sherman (1),
John D. Siirola (2), Chrysanthos E. Gounaris (1)
(1) Carnegie Mellon University, Department of Chemical Engineering
(2) Sandia National Laboratories, Center for Computing Research
-
+
The developers gratefully acknowledge support from the U.S. Department
of Energy's Institute for the Design of Advanced Energy Systems (IDAES).
==============================================================================
@@ -926,6 +986,7 @@ Observe that the log contains the following information:
keepfiles=False
tee=False
load_solution=True
+ symbolic_solver_labels=False
objective_focus=
nominal_uncertain_param_vals=[0.13248000000000001, 4.97, 4.97, 1800]
decision_rule_order=1
@@ -942,55 +1003,56 @@ Observe that the log contains the following information:
p_robustness={}
------------------------------------------------------------------------------
Preprocessing...
- Done preprocessing; required wall time of 0.175s.
+ Done preprocessing; required wall time of 0.013s.
------------------------------------------------------------------------------
- Model statistics:
+ Model Statistics:
Number of variables : 62
Epigraph variable : 1
First-stage variables : 7
- Second-stage variables : 6
- State variables : 18
+ Second-stage variables : 6 (6 adj.)
+ State variables : 18 (7 adj.)
Decision rule variables : 30
- Number of uncertain parameters : 4
- Number of constraints : 81
+ Number of uncertain parameters : 4 (4 eff.)
+ Number of constraints : 52
Equality constraints : 24
Coefficient matching constraints : 0
+ Other first-stage equations : 10
+ Second-stage equations : 8
Decision rule equations : 6
- All other equality constraints : 18
- Inequality constraints : 57
- First-stage inequalities (incl. certain var bounds) : 10
- Performance constraints (incl. var bounds) : 47
+ Inequality constraints : 28
+ First-stage inequalities : 1
+ Second-stage inequalities : 27
------------------------------------------------------------------------------
Itn Objective 1-Stg Shift 2-Stg Shift #CViol Max Viol Wall Time (s)
------------------------------------------------------------------------------
- 0 3.5838e+07 - - 5 1.8832e+04 1.741
- 1 3.5838e+07 3.5184e-15 3.9404e-15 10 4.2516e+06 3.766
- 2 3.5993e+07 1.8105e-01 7.1406e-01 13 5.2004e+06 6.288
- 3 3.6285e+07 5.1968e-01 7.7753e-01 4 1.7892e+04 8.247
- 4 3.6285e+07 9.1166e-13 1.9702e-15 0 7.1157e-10g 11.456
+ 0 3.5838e+07 - - 5 1.8832e+04 0.693
+ 1 3.5838e+07 1.2289e-09 1.5876e-12 5 3.7762e+04 1.514
+ 2 3.6129e+07 2.7244e-01 3.6878e-01 3 1.1093e+02 2.486
+ 3 3.6269e+07 3.7352e-01 4.3227e-01 1 2.7711e+01 3.667
+ 4 3.6285e+07 7.6526e-01 2.8426e-11 0 4.3364e-05g 6.291
------------------------------------------------------------------------------
Robust optimal solution identified.
------------------------------------------------------------------------------
Timing breakdown:
-
+
Identifier ncalls cumtime percall %
-----------------------------------------------------------
- main 1 11.457 11.457 100.0
+ main 1 6.291 6.291 100.0
------------------------------------------------------
- dr_polishing 4 0.682 0.171 6.0
- global_separation 47 1.109 0.024 9.7
- local_separation 235 5.810 0.025 50.7
- master 5 1.353 0.271 11.8
- master_feasibility 4 0.247 0.062 2.2
- preprocessing 1 0.429 0.429 3.7
- other n/a 1.828 n/a 16.0
+ dr_polishing 4 0.334 0.083 5.3
+ global_separation 27 0.954 0.035 15.2
+ local_separation 135 3.046 0.023 48.4
+ master 5 1.027 0.205 16.3
+ master_feasibility 4 0.133 0.033 2.1
+ preprocessing 1 0.013 0.013 0.2
+ other n/a 0.785 n/a 12.5
======================================================
===========================================================
-
+
------------------------------------------------------------------------------
Termination stats:
Iterations : 5
- Solve time (wall s) : 11.457
+ Solve time (wall s) : 6.291
Final objective value : 3.6285e+07
Termination condition : pyrosTerminationCondition.robust_optimal
------------------------------------------------------------------------------
@@ -1048,10 +1110,10 @@ The constituent columns are defined in the
there are no second-stage variables,
or the master problem of the current iteration is not solved successfully.
* - #CViol
- - Number of performance constraints found to be violated during
+ - Number of second-stage inequality constraints found to be violated during
the separation step of the current iteration.
- Unless a custom prioritization of the model's performance constraints
- is specified (through the ``separation_priority_order`` argument),
+ Unless a custom prioritization of the model's second-stage inequality
+ constraints is specified (through the ``separation_priority_order`` argument),
expect this number to trend downward as the iteration number increases.
A "+" is appended if not all of the separation problems
were solved successfully, either due to custom prioritization, a time out,
@@ -1059,13 +1121,13 @@ The constituent columns are defined in the
A dash ("-") is produced in lieu of a value if the separation
routine is not invoked during the current iteration.
* - Max Viol
- - Maximum scaled performance constraint violation.
+ - Maximum scaled second-stage inequality constraint violation.
Expect this value to trend downward as the iteration number increases.
A 'g' is appended to the value if the separation problems were solved
globally during the current iteration.
A dash ("-") is produced in lieu of a value if the separation
routine is not invoked during the current iteration, or if there are
- no performance constraints.
+ no second-stage inequality constraints.
* - Wall time (s)
- Total time elapsed by the solver, in seconds, up to the end of the
current iteration.
diff --git a/doc/OnlineDocs/contributed_packages/trustregion.rst b/doc/OnlineDocs/explanation/solvers/trustregion.rst
similarity index 91%
rename from doc/OnlineDocs/contributed_packages/trustregion.rst
rename to doc/OnlineDocs/explanation/solvers/trustregion.rst
index f477c905e33..234d05f2a54 100644
--- a/doc/OnlineDocs/contributed_packages/trustregion.rst
+++ b/doc/OnlineDocs/explanation/solvers/trustregion.rst
@@ -31,11 +31,13 @@ Methodology Overview
The formulation of the original hybrid problem is:
.. math::
- \begin{align*}
- \displaystyle \min_{} & ~~ f\left(z, w, d\left(w\right)\right) & \\
- \displaystyle \text{s.t.} \quad \: & ~~ h\left(z, w, d\left(w\right)\right) = 0 \\
- \displaystyle & ~~ g\left(z, w, d\left(w\right)\right) \leq 0
- \end{align*}
+ :nowrap:
+
+ \[\begin{array}{ll}
+ \min_{} & f\left(z, w, d\left(w\right)\right) \\
+ \text{s.t.} & h\left(z, w, d\left(w\right)\right) = 0 \\
+ & g\left(z, w, d\left(w\right)\right) \leq 0
+ \end{array}\]
where:
@@ -48,12 +50,14 @@ This formulation is reworked to separate all external function information as
follows to enable the usage of the trust region method:
.. math::
- \begin{align*}
- \displaystyle \min_{x} & ~~ f\left(x\right) & \\
- \displaystyle \text{s.t.} \quad \: & ~~ h\left(x\right) = 0 \\
- \displaystyle & ~~ g\left(x\right) \leq 0 \\
- \displaystyle & ~~ y = d\left(w\right)
- \end{align*}
+ :nowrap:
+
+ \[\begin{array}{ll}
+ \min_{x} & f\left(x\right) \\
+ \text{s.t.} & h\left(x\right) = 0 \\
+ & g\left(x\right) \leq 0 \\
+ & y = d\left(w\right)
+ \end{array}\]
where:
@@ -65,9 +69,7 @@ Using this formulation and a user-supplied low-fidelity/ideal model basis functi
the surrogate model:
.. math::
- \begin{align*}
r_k\left(w\right) = b\left(w\right) + \left( d\left(w_k\right) - b\left(w_k\right) \right) + \left( \nabla d\left(w_k\right) - \nabla b\left(w_k\right) \right)^T \left( w - w_k \right)
- \end{align*}
This acts similarly to Newton's method in that small, incremental steps are taken
towards an optimal solution. At each iteration, the current solution of the
@@ -102,11 +104,12 @@ TRF Solver Interface
The keyword arguments can be updated at solver instantiation or later when the ``solve`` method is called.
.. autoclass:: pyomo.contrib.trustregion.TRF.TrustRegionSolver
+ :noindex:
:members: solve
TRF Usage Example
------------------
-Two examples can be found in the examples_ subdirectory. One of them is
+Two examples can be found in the examples_ subdirectory. One of them is
implemented below.
.. _examples: https://github.com/Pyomo/pyomo/tree/main/pyomo/contrib/trustregion/examples
@@ -143,14 +146,14 @@ Step 2: Create the model
... m.z = pyo.Var(range(3), domain=pyo.Reals, initialize=2.)
... m.x = pyo.Var(range(2), initialize=2.)
... m.x[1] = 1.0
- ...
+ ...
... m.ext_fcn = pyo.ExternalFunction(ext_fcn, grad_ext_fcn)
- ...
+ ...
... m.obj = pyo.Objective(
... expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
... + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6
... )
- ...
+ ...
... m.c1 = pyo.Constraint(
... expr=m.x[0] * m.z[0]**2 + m.ext_fcn(m.x[0], m.x[1]) == 2*pyo.sqrt(2.0)
... )
diff --git a/doc/OnlineDocs/contributed_packages/satsolver.rst b/doc/OnlineDocs/explanation/solvers/z3_interface.rst
similarity index 77%
rename from doc/OnlineDocs/contributed_packages/satsolver.rst
rename to doc/OnlineDocs/explanation/solvers/z3_interface.rst
index 4cac9170b55..5bd2cb3e7b5 100644
--- a/doc/OnlineDocs/contributed_packages/satsolver.rst
+++ b/doc/OnlineDocs/explanation/solvers/z3_interface.rst
@@ -19,15 +19,15 @@ To use the sat solver define your pyomo model as usual:
.. doctest::
Required import
- >>> from pyomo.environ import *
+ >>> import pyomo.environ as pyo
>>> from pyomo.contrib.satsolver.satsolver import SMTSatSolver
Create a simple model
- >>> m = ConcreteModel()
- >>> m.x = Var()
- >>> m.y = Var()
- >>> m.obj = Objective(expr=m.x**2 + m.y**2)
- >>> m.c = Constraint(expr=m.y >= -2*m.x + 5)
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var()
+ >>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+ >>> m.c = pyo.Constraint(expr=m.y >= -2*m.x + 5)
Invoke the sat solver using optional argument model to automatically process
pyomo model
diff --git a/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py b/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py
new file mode 100644
index 00000000000..084e47e977a
--- /dev/null
+++ b/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py
@@ -0,0 +1,244 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+"""Custom Sphinx autodoc plugin for improved rendering of Enum types
+that plays nicely with sphinx.ext.autosummary.
+
+"""
+import enum
+import inspect
+import re
+import sphinx.locale
+
+from sphinx.application import Sphinx
+from sphinx.domains import ObjType
+from sphinx.domains.python import PyClasslike, PyAttribute, PyXRefRole
+from sphinx.ext import autodoc, autosummary
+from sphinx.ext.autosummary import mangle_signature as _msig
+from sphinx.ext.autosummary.generate import generate_autosummary_content as _gac
+from sphinx.util.inspect import object_description
+from sphinx_toolbox.more_autodoc.typehints import format_annotation
+from typing import Type, Any, Dict, List, Tuple, Union
+
+_pre_re = re.compile(r'^( = )(.*)')
+
+
+def _mangle_signature(sig: str, max_chars: int = 30) -> str:
+ """Override sphinx.ext.autosummary.mangle_signature() so we can exploit
+ it to emit the enum member value using the sig field. We overwrite
+ mangle_signature to not return '({sig})' when the sig starts with
+ ' = '
+
+ """
+ m = _pre_re.match(sig)
+ if m:
+ # Keep any initial whitespace; remove the parent that
+ # mangle_signature adds
+ return m.group(1) + _msig(m.group(2), max_chars)[1:-1]
+ return _msig(sig, max_chars)
+
+
+def _generate_autosummary_content(
+ name: str,
+ obj: Any,
+ parent: Any,
+ template: autosummary.generate.AutosummaryRenderer,
+ *gac_args,
+ **gac_kwargs,
+) -> str:
+ """Override sphinx.ext.autosummary.generate.generate_autosummary_content()
+ to provide additional fields to the namespace dictionary.
+
+ This allows us to create templates that itemize Enums separately
+ from attributes. Because we want to insert ourselves into the
+ *middle* of the original function (between the point where the
+ template namespace (``ns``) is set up and when it is rendered, we
+ will actually overload the template.render() method and pass the
+ modified template into the original generate_autosummary_content
+ function.
+
+ """
+ if template.__class__.__name__ != '_pyomo_template_wrapper':
+
+ class _pyomo_template_wrapper(template.__class__):
+ """Wrap the provided template object so we can add fields to ns before
+ calling the original render method.
+
+ """
+
+ def render(self, name, ns):
+ # Overload render() so that we can intercept calls to it
+ # and add additional fields to the NS. Note that we
+ # need variables from the generate_autosummary_content
+ # context ... but we know that context is the calling
+ # frame. Seems like cheating, but it works.
+ if ns['objtype'] not in ('module', 'enum'):
+ return super().render(name, ns)
+
+ caller = inspect.currentframe().f_back
+ l = caller.f_locals
+ doc = l['doc']
+ obj = l['obj']
+ args = {'obj': obj}
+ if '_get_members' in caller.f_globals:
+ _get_members = caller.f_globals['_get_members']
+ if 'config' in l:
+ # Sphinx >= 8.2.1
+ for field in ('config', 'doc', 'events', 'registry'):
+ args[field] = l[field]
+ else:
+ # Sphinx >= 7.2
+ args.update({'doc': doc, 'app': l['app']})
+ else:
+ # Sphinx < 7.2
+ _get_members = caller.f_locals['get_members']
+
+ if ns['objtype'] == 'module':
+ ns['enums'], ns['all_enums'] = _get_members(
+ types={'enum'}, imported=l['imported_members'], **args
+ )
+ elif ns['objtype'] == 'enum':
+ ns['members'] = dir(obj)
+ ns['inherited_members'] = set(dir(obj)) - set(obj.__dict__.keys())
+ try:
+ # We need _get_members to eventually call
+ # _get_class_members, so we will (temporarily)
+ # set the doc.objtype back to "class"
+ doc.objtype = 'class'
+ ns['methods'], ns['all_methods'] = _get_members(
+ types={'method'}, include_public={'__init__'}, **args
+ )
+ ns['attributes'], ns['all_attributes'] = _get_members(
+ types={'attribute', 'property'}, **args
+ )
+ ns['enum_members'], ns['all_enum_members'] = _get_members(
+ types={'enum_member'}, **args
+ )
+ finally:
+ doc.objtype = 'enum'
+
+ mro = obj.__mro__
+ for _base in mro[: mro.index(enum.Enum)]:
+ if not isinstance(_base, enum.EnumMeta):
+ ns['member_type'] = (
+ f"Member type: {format_annotation(_base)}"
+ )
+ break
+ return super().render(name, ns)
+
+ template.__class__ = _pyomo_template_wrapper
+
+ return _gac(name, obj, parent, template, *gac_args, **gac_kwargs)
+
+
+class EnumDocumenter(autodoc.ClassDocumenter):
+ objtype = "enum"
+
+ # More than Class; less than Exception
+ priority = autodoc.ClassDocumenter.priority + 1
+
+ member_order = 15
+
+ @classmethod
+ def can_document_member(cls, member, membername, isattr, parent):
+ return isinstance(member, enum.EnumMeta)
+
+ def format_signature(self, **kwargs: Any) -> str:
+ # hard-code the enum signature. This is mostly to preserve the
+ # behavior from enum-tools.autoenum. We might want to revisit
+ # this decision later.
+ return "(value)"
+
+ def sort_members(
+ self, documenters: List[Tuple[autodoc.Documenter, bool]], order: str
+ ) -> List[Tuple[autodoc.Documenter, bool]]:
+ if order != 'groupwise':
+ return super().sort_members(documenters, order)
+ # If we are grouping the members, then we want the groups
+ # alphabetical, *except* for the Enum members, which we want in
+ # declaration order:
+ mo = EnumDocumenter.member_order
+ tmp = [
+ (e, (e[0].member_order, (i if e[0].member_order == mo else e[0].name)))
+ for i, e in enumerate(documenters)
+ ]
+ tmp.sort(key=lambda x: x[1])
+ return [x[0] for x in tmp]
+
+
+class EnumMemberDocumenter(autodoc.AttributeDocumenter):
+ """Custom documenter for Enum members"""
+
+ # Note that we want to flag these attributes as "special" (i.e., not
+ # generic attributes, but we still want to emit regular py:attribute
+ # directives (so that we still refer to them with :py:attr:
+ # references).
+ objtype = "enum_member"
+ directivetype = autodoc.AttributeDocumenter.objtype
+
+ # More than AttributeDocumenter
+ priority = autodoc.AttributeDocumenter.priority + 3
+
+ member_order = 15
+
+ @classmethod
+ def can_document_member(cls, member, membername, isattr, parent):
+ return isinstance(member, enum.Enum)
+
+ def format_signature(self, **kwargs: Any) -> str:
+ """Custom format_signature() to return the value as the signature
+
+ This has the effect of putting the value in the autosummary documentation.
+ """
+ return " = " + object_description(self.object)
+
+ def add_directive_header(self, sig):
+ """Custom add_directive_header to remove the enum value
+
+ This undoes the effect of format_signature so that the entry
+ renders correctly (and ``:py:enum:`` links will be generated and
+ resolved correctly).
+
+ """
+ super().add_directive_header(sig.split(" = ", 1)[0].strip())
+
+
+def setup(app: Sphinx) -> Dict[str, Any]:
+ app.setup_extension('sphinx.ext.autodoc')
+ app.setup_extension('sphinx.ext.autosummary')
+ # Overwrite key parts of autosummary so that our version of autoenum
+ # plays nicely with it. We have tested this with Sphinx>7.2.
+ # Notably, 7.1.2 does NOT work (and cannot be easily made to work)
+ if 'generate_autosummary_content' not in dir(autosummary.generate):
+ raise RuntimeError(
+ "pyomo_autosummary_autoenum: Could not locate "
+ "autosummary.generate.generate_autosummary_content() "
+ "(possible incompatible Sphinx version)."
+ )
+ autosummary.generate.generate_autosummary_content = _generate_autosummary_content
+ if 'mangle_signature' not in dir(autosummary):
+ raise RuntimeError(
+ "pyomo_autosummary_autoenum: Could not locate "
+ "autosummary.mangle_signature() "
+ "(possible incompatible Sphinx version)."
+ )
+ autosummary.mangle_signature = _mangle_signature
+
+ app.add_autodocumenter(EnumMemberDocumenter)
+ app.add_autodocumenter(EnumDocumenter)
+
+ app.add_directive_to_domain("py", "enum", PyClasslike)
+ app.add_role_to_domain("py", "enum", PyXRefRole())
+ app.registry.domains["py"].object_types["enum"] = ObjType(
+ sphinx.locale._("enum"), "enum", "class", "obj"
+ )
+
+ return {"version": '0.0.0', "parallel_read_safe": True, "parallel_write_safe": True}
diff --git a/doc/OnlineDocs/ext/pyomo_tocref.py b/doc/OnlineDocs/ext/pyomo_tocref.py
new file mode 100644
index 00000000000..1f370578520
--- /dev/null
+++ b/doc/OnlineDocs/ext/pyomo_tocref.py
@@ -0,0 +1,58 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+"""Custom Sphinx autodoc plugin to generate TOC list-of-lists without
+creating duplicate TOC entries
+
+"""
+
+from docutils import nodes
+from sphinx.directives.other import TocTree
+from sphinx.environment.adapters.toctree import TocTree as TocTree_Adapter
+
+
+def setup(app):
+ app.connect('doctree-resolved', expand_tocrefs)
+ app.add_directive('tocref', TocRef)
+ return {'version': '0.0.0'}
+
+
+class tocref(nodes.Element):
+ pass
+
+
+class TocRef(TocTree):
+ tagname = 'tocref'
+
+ def run(self):
+ wrapped_toc = super().run()[0]
+ assert len(wrapped_toc.children) == 1
+ toc = wrapped_toc.children[0]
+ node = tocref()
+ node.attributes = toc.attributes
+ node.children = toc.children
+ self.set_source_info(node)
+ self.add_name(node)
+ return [node]
+
+
+def expand_tocrefs(app, doctree, docname):
+ toctree_adapter = TocTree_Adapter(app.env)
+ for node in doctree.findall(tocref):
+ node.replace_self(
+ toctree_adapter.resolve(
+ docname,
+ app.builder,
+ node,
+ maxdepth=node['maxdepth'],
+ titles_only=node['titlesonly'],
+ )
+ )
diff --git a/doc/OnlineDocs/getting_started/index.rst b/doc/OnlineDocs/getting_started/index.rst
new file mode 100644
index 00000000000..45b8bec019c
--- /dev/null
+++ b/doc/OnlineDocs/getting_started/index.rst
@@ -0,0 +1,8 @@
+Getting Started
+===============
+
+.. toctree::
+ :maxdepth: 2
+
+ installation.rst
+ pyomo_overview/index.rst
diff --git a/doc/OnlineDocs/installation.rst b/doc/OnlineDocs/getting_started/installation.rst
similarity index 65%
rename from doc/OnlineDocs/installation.rst
rename to doc/OnlineDocs/getting_started/installation.rst
index ecba05e13fb..5d2abe3c191 100644
--- a/doc/OnlineDocs/installation.rst
+++ b/doc/OnlineDocs/getting_started/installation.rst
@@ -1,9 +1,11 @@
+.. _pyomo_installation:
+
Installation
------------
Pyomo currently supports the following versions of Python:
-* CPython: 3.8, 3.9, 3.10, 3.11, 3.12
+* CPython: 3.9, 3.10, 3.11, 3.12, 3.13
* PyPy: 3
At the time of the first Pyomo release after the end-of-life of a minor Python
@@ -12,7 +14,7 @@ version, Pyomo will remove testing for that Python version.
Using CONDA
~~~~~~~~~~~
-We recommend installation with *conda*, which is included with the
+We recommend installation with ``conda``, which is included with the
Anaconda distribution of Python. You can install Pyomo in your system
Python installation by executing the following in a shell:
@@ -21,7 +23,7 @@ Python installation by executing the following in a shell:
conda install -c conda-forge pyomo
Optimization solvers are not installed with Pyomo, but some open source
-optimization solvers can be installed with conda as well:
+optimization solvers can be installed with ``conda`` as well:
::
@@ -31,7 +33,7 @@ optimization solvers can be installed with conda as well:
Using PIP
~~~~~~~~~
-The standard utility for installing Python packages is *pip*. You
+The standard utility for installing Python packages is ``pip``. You
can install Pyomo in your system Python installation by executing
the following in a shell:
@@ -43,14 +45,14 @@ the following in a shell:
Conditional Dependencies
~~~~~~~~~~~~~~~~~~~~~~~~
-Extensions to Pyomo, and many of the contributions in `pyomo.contrib`,
+Extensions to Pyomo, and many of the contributions in ``pyomo.contrib``,
often have conditional dependencies on a variety of third-party Python
packages including but not limited to: matplotlib, networkx, numpy,
openpyxl, pandas, pint, pymysql, pyodbc, pyro4, scipy, sympy, and
xlrd.
A full list of conditional dependencies can be found in Pyomo's
-`setup.py` and displayed using:
+``setup.py`` and displayed using:
::
@@ -72,3 +74,28 @@ with the standard Anaconda installation.
You can check which Python packages you have installed using the command
``conda list`` or ``pip list``. Additional Python packages may be
installed as needed.
+
+
+Installation with Cython
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Users can opt to install Pyomo with
+`cython `_
+initialized.
+
+.. note::
+ This can only be done via ``pip`` or from source.
+
+Via ``pip``:
+
+::
+
+ pip install pyomo --global-option="--with-cython"
+
+From source (recommended for advanced users only):
+
+::
+
+ git clone https://github.com/Pyomo/pyomo.git
+ cd pyomo
+ python setup.py install --with-cython
diff --git a/doc/OnlineDocs/pyomo_overview/abstract_concrete.rst b/doc/OnlineDocs/getting_started/pyomo_overview/abstract_concrete.rst
similarity index 86%
rename from doc/OnlineDocs/pyomo_overview/abstract_concrete.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/abstract_concrete.rst
index 24f2f2b8187..da2962a0acd 100644
--- a/doc/OnlineDocs/pyomo_overview/abstract_concrete.rst
+++ b/doc/OnlineDocs/getting_started/pyomo_overview/abstract_concrete.rst
@@ -9,11 +9,13 @@ values. For example, the following equations represent a linear program
.. math::
:nowrap:
+ \[
\begin{array}{lll}
- \min & \sum_{j=1}^n c_j x_j &\\
- \mathrm{s.t.} & \sum_{j=1}^n a_{ij} x_j \geq b_i & \forall i = 1 \ldots m\\
- & x_j \geq 0 & \forall j = 1 \ldots n
- \end{array}
+ \min & \sum_{j=1}^n c_j x_j &\\
+ \mathrm{s.t.} & \sum_{j=1}^n a_{ij} x_j \geq b_i & \forall i = 1 \ldots m\\
+ & x_j \geq 0 & \forall j = 1 \ldots n
+ \end{array}
+ \]
.. note::
@@ -36,11 +38,13 @@ model:
.. math::
:nowrap:
+ \[
\begin{array}{ll}
- \min & 2 x_1 + 3 x_2\\
+ \min & 2 x_1 + 3 x_2\\
\mathrm{s.t.} & 3 x_1 + 4 x_2 \geq 1\\
& x_1, x_2 \geq 0
\end{array}
+ \]
The ``ConcreteModel`` class is used to define concrete optimization
models in Pyomo.
diff --git a/doc/OnlineDocs/pyomo_overview/index.rst b/doc/OnlineDocs/getting_started/pyomo_overview/index.rst
similarity index 100%
rename from doc/OnlineDocs/pyomo_overview/index.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/index.rst
diff --git a/doc/OnlineDocs/pyomo_overview/math_modeling.rst b/doc/OnlineDocs/getting_started/pyomo_overview/math_modeling.rst
similarity index 97%
rename from doc/OnlineDocs/pyomo_overview/math_modeling.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/math_modeling.rst
index ccacca8d58d..89a6e3af08b 100644
--- a/doc/OnlineDocs/pyomo_overview/math_modeling.rst
+++ b/doc/OnlineDocs/getting_started/pyomo_overview/math_modeling.rst
@@ -6,7 +6,7 @@ Modeling Objects. A more complete description is contained in the
[PyomoBookIII]_ book. Pyomo supports the formulation and analysis of
mathematical models for complex optimization applications. This
capability is commonly associated with commercially available algebraic
-modeling languages (AMLs) such as [AMPL]_, [AIMMS]_, and [GAMS]_.
+modeling languages (AMLs) such as [FGK02]_, [AIMMS]_, and [GAMS]_.
Pyomo's modeling objects are embedded within Python, a full-featured,
high-level programming language that contains a rich set of supporting
libraries.
@@ -72,7 +72,7 @@ solvers to analyze a model introduces additional complexities.
Pyomo is an AML that extends Python to include objects for mathematical
-modeling. [PyomoBookI]_, [PyomoBookII]_, [PyomoBookIII]_, and [PyomoJournal]_
+modeling. [PyomoBookI]_, [PyomoBookII]_, [PyomoBookIII]_, and [Pyomo-paper]_
compare Pyomo with other AMLs. Although many good AMLs have been developed for
optimization models, the following are motivating factors for the
development of Pyomo:
diff --git a/doc/OnlineDocs/pyomo_overview/overview_components.rst b/doc/OnlineDocs/getting_started/pyomo_overview/overview_components.rst
similarity index 100%
rename from doc/OnlineDocs/pyomo_overview/overview_components.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/overview_components.rst
diff --git a/doc/OnlineDocs/pyomo_overview/simple_examples.rst b/doc/OnlineDocs/getting_started/pyomo_overview/simple_examples.rst
similarity index 97%
rename from doc/OnlineDocs/pyomo_overview/simple_examples.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/simple_examples.rst
index 11305884c54..4ea6200184d 100644
--- a/doc/OnlineDocs/pyomo_overview/simple_examples.rst
+++ b/doc/OnlineDocs/getting_started/pyomo_overview/simple_examples.rst
@@ -15,11 +15,11 @@ Given the following model from the previous section:
.. math::
:nowrap:
- \begin{array}{ll}
+ \[\begin{array}{ll}
\min & 2 x_1 + 3 x_2\\
\mathrm{s.t.} & 3 x_1 + 4 x_2 \geq 1\\
& x_1, x_2 \geq 0
- \end{array}
+ \end{array}\]
This can be implemented as a concrete model as follows:
@@ -48,11 +48,11 @@ We repeat the abstract model from the previous section:
.. math::
:nowrap:
- \begin{array}{lll}
- \min & \sum_{j=1}^n c_j x_j &\\
+ \[\begin{array}{lll}
+ \min & \sum_{j=1}^n c_j x_j &\\
\mathrm{s.t.} & \sum_{j=1}^n a_{ij} x_j \geq b_i & \forall i = 1 \ldots m\\
& x_j \geq 0 & \forall j = 1 \ldots n
- \end{array}
+ \end{array}\]
One way to implement this in Pyomo is as shown as follows:
@@ -263,7 +263,7 @@ parameters. Here is one file that provides data (in AMPL "``.dat``" format).
>>> # Create an instance to verify that the rules fire correctly
>>> inst = model.create_instance('src/scripting/abstract1.dat')
-.. literalinclude:: ../src/scripting/abstract1.dat
+.. literalinclude:: /src/scripting/abstract1.dat
:language: text
There are multiple formats that can be used to provide data to a Pyomo
@@ -327,18 +327,18 @@ the same model. To start with an illustration of general indexes,
consider a slightly different Pyomo implementation of the model we just
presented.
-.. literalinclude:: ../src/scripting/abstract2.py
+.. literalinclude:: /src/scripting/abstract2.py
:language: python
To get the same instantiated model, the following data file can be used.
-.. literalinclude:: ../src/scripting/abstract2a.dat
+.. literalinclude:: /src/scripting/abstract2a.dat
:language: none
However, this model can also be fed different data for problems of the
same general form using meaningful indexes.
-.. literalinclude:: ../src/scripting/abstract2.dat
+.. literalinclude:: /src/scripting/abstract2.dat
:language: none
diff --git a/doc/OnlineDocs/working_abstractmodels/BuildAction.rst b/doc/OnlineDocs/howto/abstract_models/BuildAction.rst
similarity index 85%
rename from doc/OnlineDocs/working_abstractmodels/BuildAction.rst
rename to doc/OnlineDocs/howto/abstract_models/BuildAction.rst
index 6840e15a1d5..c87b56b92c0 100644
--- a/doc/OnlineDocs/working_abstractmodels/BuildAction.rst
+++ b/doc/OnlineDocs/howto/abstract_models/BuildAction.rst
@@ -13,7 +13,7 @@ trigger actions to be done as part of the model building process. The
takes as arguments optional index sets and a function to perform the
action. For example,
-.. literalinclude:: ../src/scripting/abstract2piecebuild_BuildAction_example.spy
+.. literalinclude:: /src/scripting/abstract2piecebuild_BuildAction_example.spy
:language: python
calls the function ``bpts_build`` for each member of ``model.J``. The
@@ -21,14 +21,14 @@ function ``bpts_build`` should have the model and a variable for the
members of ``model.J`` as formal arguments. In this example, the
following would be a valid declaration for the function:
-.. literalinclude:: ../src/scripting/abstract2piecebuild_Function_valid_declaration.spy
+.. literalinclude:: /src/scripting/abstract2piecebuild_Function_valid_declaration.spy
:language: python
A full example, which extends the :ref:`abstract2.py` and
:ref:`abstract2piece.py` examples, is
-.. literalinclude:: ../src/scripting/abstract2piecebuild.spy
+.. literalinclude:: /src/scripting/abstract2piecebuild.spy
:language: python
This example uses the build action to create a model component with
@@ -51,13 +51,13 @@ clearer, to use a build action.
The full model is:
-.. literalinclude:: ../src/scripting/Isinglebuild.py
+.. literalinclude:: /src/scripting/Isinglebuild.py
:language: python
-for this model, the same data file can be used as for Isinglecomm.py in
+For this model, the same data file can be used as for Isinglecomm.py in
:ref:`Isinglecomm.py` such as the toy data file:
-.. literalinclude:: ../src/scripting/Isinglecomm.dat
+.. literalinclude:: /src/scripting/Isinglecomm.dat
Build actions can also be a way to implement data validation,
particularly when multiple Sets or Parameters must be analyzed. However,
diff --git a/doc/OnlineDocs/working_abstractmodels/data/ABCD.pdf b/doc/OnlineDocs/howto/abstract_models/data/ABCD.pdf
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/data/ABCD.pdf
rename to doc/OnlineDocs/howto/abstract_models/data/ABCD.pdf
diff --git a/doc/OnlineDocs/working_abstractmodels/data/ABCD.png b/doc/OnlineDocs/howto/abstract_models/data/ABCD.png
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/data/ABCD.png
rename to doc/OnlineDocs/howto/abstract_models/data/ABCD.png
diff --git a/doc/OnlineDocs/working_abstractmodels/data/PP.png b/doc/OnlineDocs/howto/abstract_models/data/PP.png
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/data/PP.png
rename to doc/OnlineDocs/howto/abstract_models/data/PP.png
diff --git a/doc/OnlineDocs/working_abstractmodels/data/dataportals.rst b/doc/OnlineDocs/howto/abstract_models/data/dataportals.rst
similarity index 88%
rename from doc/OnlineDocs/working_abstractmodels/data/dataportals.rst
rename to doc/OnlineDocs/howto/abstract_models/data/dataportals.rst
index 5ce907fda2a..10d4a884cfb 100644
--- a/doc/OnlineDocs/working_abstractmodels/data/dataportals.rst
+++ b/doc/OnlineDocs/howto/abstract_models/data/dataportals.rst
@@ -62,14 +62,14 @@ can be used to initialize both concrete and abstract Pyomo models.
Consider the file ``A.tab``, which defines a simple set with a tabular
format:
-.. literalinclude:: ../../src/dataportal/A.tab
+.. literalinclude:: /src/dataportal/A.tab
:language: none
The ``load`` method is used to load data into a :class:`~pyomo.environ.DataPortal` object. Components in a
concrete model can be explicitly initialized with data loaded by a
:class:`~pyomo.environ.DataPortal` object:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_concrete1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_concrete1.spy
:language: python
All data needed to initialize an abstract model *must* be provided by a
@@ -77,7 +77,7 @@ All data needed to initialize an abstract model *must* be provided by a
and the use of the :class:`~pyomo.environ.DataPortal` object to initialize components
is automated for the user:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_load.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_load.spy
:language: python
Note the difference in the execution of the ``load`` method in these two
@@ -126,7 +126,7 @@ that are loaded from different data sources. The ``[]`` operator is
used to access set and parameter values. Consider the following
example, which loads data and prints the value of the ``[]`` operator:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_getitem.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_getitem.spy
:language: python
The :class:`~pyomo.environ.DataPortal`
@@ -162,12 +162,12 @@ with lists and dictionaries:
For example, consider the following JSON file:
-.. literalinclude:: ../../src/dataportal/T.json
+.. literalinclude:: /src/dataportal/T.json
:language: none
The data in this file can be used to load the following model:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_json1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_json1.spy
:language: python
Note that no ``set`` or ``param`` option needs to be specified when
@@ -178,13 +178,13 @@ needed for model construction is used.
The following YAML file has a similar structure:
-.. literalinclude:: ../../src/dataportal/T.yaml
+.. literalinclude:: /src/dataportal/T.yaml
:language: none
The data in this file can be used to load a Pyomo model with the
same syntax as a JSON file:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_yaml1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_yaml1.spy
:language: python
@@ -212,7 +212,7 @@ TAB files represent tabular data in an ascii file using whitespace as a
delimiter. A TAB file consists of rows of values, where each row has
the same length. For example, the file ``PP.tab`` has the format:
-.. literalinclude:: ../../src/dataportal/PP.tab
+.. literalinclude:: /src/dataportal/PP.tab
:language: none
CSV files represent tabular data in a format that is very similar to TAB
@@ -220,7 +220,7 @@ files. Pyomo assumes that a CSV file consists of rows of values, where
each row has the same length. For example, the file ``PP.csv`` has the
format:
-.. literalinclude:: ../../src/dataportal/PP.csv
+.. literalinclude:: /src/dataportal/PP.csv
:language: none
Excel spreadsheets can express complex data relationships. A *range* is
@@ -242,7 +242,7 @@ sub-element of a ``row`` element represents a different column, where
each row has the same length. For example, the file ``PP.xml`` has the
format:
-.. literalinclude:: ../../src/dataportal/PP.xml
+.. literalinclude:: /src/dataportal/PP.xml
:language: none
Loading Set Data
@@ -256,13 +256,13 @@ Loading a Simple Set
Consider the file ``A.tab``, which defines a simple set:
-.. literalinclude:: ../../src/dataportal/A.tab
+.. literalinclude:: /src/dataportal/A.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a simple
set ``A``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_set1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_set1.spy
:language: python
Loading a Set of Tuples
@@ -270,13 +270,13 @@ Loading a Set of Tuples
Consider the file ``C.tab``:
-.. literalinclude:: ../../src/dataportal/C.tab
+.. literalinclude:: /src/dataportal/C.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a
two-dimensional set ``C``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_set2.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_set2.spy
:language: python
In this example, the column titles do not directly impact the process of
@@ -289,13 +289,13 @@ Loading a Set Array
Consider the file ``D.tab``, which defines an array representation of a
two-dimensional set:
-.. literalinclude:: ../../src/dataportal/D.tab
+.. literalinclude:: /src/dataportal/D.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a
two-dimensional set ``D``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_set3.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_set3.spy
:language: python
The ``format`` option indicates that the set data is declared in a array
@@ -313,13 +313,13 @@ Loading a Simple Parameter
The simplest parameter is simply a singleton value. Consider the file
``Z.tab``:
-.. literalinclude:: ../../src/dataportal/Z.tab
+.. literalinclude:: /src/dataportal/Z.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a simple
parameter ``z``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param1.spy
:language: python
Loading an Indexed Parameter
@@ -328,13 +328,13 @@ Loading an Indexed Parameter
An indexed parameter can be defined by a single column in a table. For
example, consider the file ``Y.tab``:
-.. literalinclude:: ../../src/dataportal/Y.tab
+.. literalinclude:: /src/dataportal/Y.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for an indexed
parameter ``y``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param2.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param2.spy
:language: python
When column names are not used to specify the index and parameter data,
@@ -351,19 +351,19 @@ The index set can be loaded with the parameter data using the ``index``
option. In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for set ``A``
and the indexed parameter ``y``
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param3.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param3.spy
:language: python
An index set with multiple dimensions can also be loaded with an indexed
parameter. Consider the file ``PP.tab``:
-.. literalinclude:: ../../src/dataportal/PP.tab
+.. literalinclude:: /src/dataportal/PP.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a tuple
set and an indexed parameter:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param10.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param10.spy
:language: python
Loading a Parameter with Missing Values
@@ -373,7 +373,7 @@ Missing parameter data can be expressed in two ways. First, parameter
data can be defined with indices that are a subset of valid indices in
the model. The following example loads the indexed parameter ``y``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param9.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param9.spy
:language: python
The model defines an index set with four values, but only three
@@ -382,13 +382,13 @@ parameter values are declared in the data file ``Y.tab``.
Parameter data can also be declared with missing values using the period
(``.``) symbol. For example, consider the file ``S.tab``:
-.. literalinclude:: ../../src/dataportal/PP.tab
+.. literalinclude:: /src/dataportal/PP.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for the index
set ``A`` and indexed parameter ``y``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param8.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param8.spy
:language: python
The period (``.``) symbol indicates a missing parameter value, but the
@@ -400,13 +400,13 @@ Loading Multiple Parameters
Multiple parameters can be initialized at once by specifying a list (or
tuple) of component parameters. Consider the file ``XW.tab``:
-.. literalinclude:: ../../src/dataportal/XW.tab
+.. literalinclude:: /src/dataportal/XW.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for parameters
``x`` and ``w``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param4.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param4.spy
:language: python
Selecting Parameter Columns
@@ -421,7 +421,7 @@ component data.
For example, consider the following load declaration:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param5.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param5.spy
:language: python
The columns ``A`` and ``W`` are selected from the file ``XW.tab``, and a
@@ -433,20 +433,20 @@ Loading a Parameter Array
Consider the file ``U.tab``, which defines an array representation of a
multiply-indexed parameter:
-.. literalinclude:: ../../src/dataportal/U.tab
+.. literalinclude:: /src/dataportal/U.tab
:language: none
In the following example, a :class:`~pyomo.environ.DataPortal` object loads data for a
two-dimensional parameter ``u``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param6.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param6.spy
:language: python
The ``format`` option indicates that the parameter data is declared in a
array format. The ``format`` option can also indicate that the
parameter data should be transposed.
-.. literalinclude:: ../../src/dataportal/dataportal_tab_param7.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_param7.spy
:language: python
Note that the transposed parameter data changes the index set for the
@@ -467,7 +467,7 @@ the following range of cells, which is named ``PPtable``:
In the following example, a :class:`~pyomo.environ.DataPortal` object loads the named range
``PPtable`` from the file ``excel.xls``:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_excel1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_excel1.spy
:language: python
Note that the ``range`` option is required to specify the table of cell
@@ -477,14 +477,14 @@ There are a variety of ways that data can be loaded from a relational
database. In the simplest case, a table can be specified within a
database:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_db1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_db1.spy
:language: python
In this example, the interface ``sqlite3`` is used to load data from an
SQLite database in the file ``PP.sqlite``. More generally, an SQL query
can be specified to dynamically generate a table. For example:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_db2.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_db2.spy
:language: python
Data Namespaces
@@ -524,7 +524,7 @@ components. For example, the following script generates two model
instances from an abstract model using data loaded into different
namespaces:
-.. literalinclude:: ../../src/dataportal/dataportal_tab_namespaces1.spy
+.. literalinclude:: /src/dataportal/dataportal_tab_namespaces1.spy
:language: python
diff --git a/doc/OnlineDocs/working_abstractmodels/data/datfiles.rst b/doc/OnlineDocs/howto/abstract_models/data/datfiles.rst
similarity index 89%
rename from doc/OnlineDocs/working_abstractmodels/data/datfiles.rst
rename to doc/OnlineDocs/howto/abstract_models/data/datfiles.rst
index 4982ed2fff0..c0ce901628b 100644
--- a/doc/OnlineDocs/working_abstractmodels/data/datfiles.rst
+++ b/doc/OnlineDocs/howto/abstract_models/data/datfiles.rst
@@ -6,7 +6,7 @@ Data Command Files
.. note::
The discussion and presentation below are adapted from Chapter 6 of
- the "Pyomo Book" [PyomoBookII]_. The discussion of the
+ the second edition of the "Pyomo Book" [PyomoBookII]_. The discussion of the
:class:`~pyomo.environ.DataPortal`
class uses these same examples to illustrate how data can be loaded
into Pyomo models within Python scripts (see the
@@ -16,7 +16,7 @@ Model Data
----------
Pyomo's *data command files* employ a domain-specific language whose
-syntax closely resembles the syntax of AMPL's data commands [AMPL]_. A
+syntax closely resembles the syntax of AMPL's data commands [FGK02]_. A
data command file consists of a sequence of commands that either (a)
specify set and parameter data for a model, or (b) specify where such
data is to be obtained from external sources (e.g. table files, CSV
@@ -104,7 +104,7 @@ A set may be empty, and it may contain any combination of numeric and
non-numeric string values. For example, the following are valid ``set``
commands:
-.. literalinclude:: ../../src/data/set1.dat
+.. literalinclude:: /src/data/set1.dat
:language: python
@@ -115,19 +115,19 @@ The ``set`` data command can also specify tuple data with the standard
notation for tuples. For example, suppose that set ``A`` contains
3-tuples:
-.. literalinclude:: ../../src/data/set2_decl.spy
+.. literalinclude:: /src/data/set2_decl.spy
:language: python
The following ``set`` data command then specifies that ``A`` is the set
containing the tuples ``(1,2,3)`` and ``(4,5,6)``:
-.. literalinclude:: ../../src/data/set2a.dat
+.. literalinclude:: /src/data/set2a.dat
:language: none
Alternatively, set data can simply be listed in the order that the tuple
is represented:
-.. literalinclude:: ../../src/data/set2.dat
+.. literalinclude:: /src/data/set2.dat
:language: none
Obviously, the number of data elements specified using this syntax
@@ -138,7 +138,7 @@ membership. For example, the following ``set`` data command declares
2-tuples in ``A`` using plus (``+``) to denote valid tuples and minus
(``-``) to denote invalid tuples:
-.. literalinclude:: ../../src/data/set4.dat
+.. literalinclude:: /src/data/set4.dat
:language: none
This data command declares the following five 2-tuples: ``('A1',1)``,
@@ -148,13 +148,13 @@ Finally, a set of tuple data can be concisely represented with tuple
*templates* that represent a *slice* of tuple data. For example,
suppose that the set ``A`` contains 4-tuples:
-.. literalinclude:: ../../src/data/set5_decl.spy
+.. literalinclude:: /src/data/set5_decl.spy
:language: python
The following ``set`` data command declares groups of tuples that are
defined by a template and data to complete this template:
-.. literalinclude:: ../../src/data/set5.dat
+.. literalinclude:: /src/data/set5.dat
:language: none
A tuple template consists of a tuple that contains one or more asterisk
@@ -163,7 +163,7 @@ tuple value is replaced by the values from the list of values that
follows the tuple template. In this example, the following tuples are
in set ``A``:
-.. literalinclude:: ../../src/data/set5.txt
+.. literalinclude:: /src/data/set5.txt
:language: none
Set Arrays
@@ -183,12 +183,12 @@ list of string values.
Suppose that a set ``A`` is used to index a set ``B`` as follows:
-.. literalinclude:: ../../src/data/set3_decl.spy
+.. literalinclude:: /src/data/set3_decl.spy
:language: python
Then set ``B`` is indexed using the values declared for set ``A``:
-.. literalinclude:: ../../src/data/set3.dat
+.. literalinclude:: /src/data/set3.dat
:language: none
The ``param`` Command
@@ -197,7 +197,7 @@ The ``param`` Command
Simple or non-indexed parameters are declared in an obvious way, as
shown by these examples:
-.. literalinclude:: ../../src/data/param1.dat
+.. literalinclude:: /src/data/param1.dat
:language: none
Parameters can be defined with numeric data, simple strings and quoted
@@ -213,33 +213,33 @@ parameter data. One-dimensional parameter data is indexed over a single
set. Suppose that the parameter ``B`` is a parameter indexed by the set
``A``:
-.. literalinclude:: ../../src/data/param2_decl.spy
+.. literalinclude:: /src/data/param2_decl.spy
:language: python
A ``param`` data command can specify values for ``B`` with a list of
index-value pairs:
-.. literalinclude:: ../../src/data/param2.dat
+.. literalinclude:: /src/data/param2.dat
:language: none
Because whitespace is ignored, this example data command file can be
reorganized to specify the same data in a tabular format:
-.. literalinclude:: ../../src/data/param2a.dat
+.. literalinclude:: /src/data/param2a.dat
:language: none
Multiple parameters can be defined using a single ``param`` data
command. For example, suppose that parameters ``B``, ``C``, and ``D``
are one-dimensional parameters all indexed by the set ``A``:
-.. literalinclude:: ../../src/data/param3_decl.spy
+.. literalinclude:: /src/data/param3_decl.spy
:language: python
Values for these parameters can be specified using a single ``param``
data command that declares these parameter names followed by a list of
index and parameter values:
-.. literalinclude:: ../../src/data/param3.dat
+.. literalinclude:: /src/data/param3.dat
:language: none
The values in the ``param`` data command are interpreted as a list of
@@ -249,7 +249,7 @@ corresponding numeric value.
Note that parameter values do not need to be defined for all indices.
For example, the following data command file is valid:
-.. literalinclude:: ../../src/data/param3a.dat
+.. literalinclude:: /src/data/param3a.dat
:language: none
The index ``g`` is omitted from the ``param`` command, and consequently
@@ -259,7 +259,7 @@ More complex patterns of missing data can be specified using the period
specifying multiple parameters that do not necessarily have the same
index values:
-.. literalinclude:: ../../src/data/param3b.dat
+.. literalinclude:: /src/data/param3b.dat
:language: none
This example provides a concise representation of parameters that share
@@ -270,13 +270,13 @@ Note that this data file specifies the data for set ``A`` twice:
defined. An alternate syntax for ``param`` allows the user to concisely
specify the definition of an index set along with associated parameters:
-.. literalinclude:: ../../src/data/param3c.dat
+.. literalinclude:: /src/data/param3c.dat
:language: none
Finally, we note that default values for missing data can also be
specified using the ``default`` keyword:
-.. literalinclude:: ../../src/data/param4.dat
+.. literalinclude:: /src/data/param4.dat
:language: none
Note that default values can only be specified in ``param`` commands
@@ -290,58 +290,58 @@ Multi-dimensional parameter data is indexed over either multiple sets or
a single multi-dimensional set. Suppose that parameter ``B`` is a
parameter indexed by set ``A`` that has dimension 2:
-.. literalinclude:: ../../src/data/param5_decl.spy
+.. literalinclude:: /src/data/param5_decl.spy
:language: python
The syntax of the ``param`` data command remains essentially the same
when specifying values for ``B`` with a list of index and parameter
values:
-.. literalinclude:: ../../src/data/param5.dat
+.. literalinclude:: /src/data/param5.dat
:language: none
Missing and default values are also handled in the same way with
multi-dimensional index sets:
-.. literalinclude:: ../../src/data/param5a.dat
+.. literalinclude:: /src/data/param5a.dat
:language: none
Similarly, multiple parameters can defined with a single ``param`` data
command. Suppose that parameters ``B``, ``C``, and ``D`` are parameters
indexed over set ``A`` that has dimension 2:
-.. literalinclude:: ../../src/data/param6_decl.spy
+.. literalinclude:: /src/data/param6_decl.spy
:language: python
These parameters can be defined with a single ``param`` command that
declares the parameter names followed by a list of index and parameter
values:
-.. literalinclude:: ../../src/data/param6.dat
+.. literalinclude:: /src/data/param6.dat
:language: none
Similarly, the following ``param`` data command defines the index set
along with the parameters:
-.. literalinclude:: ../../src/data/param6a.dat
+.. literalinclude:: /src/data/param6a.dat
:language: none
The ``param`` command also supports a matrix syntax for specifying the
values in a parameter that has a 2-dimensional index. Suppose parameter
``B`` is indexed over set ``A`` that has dimension 2:
-.. literalinclude:: ../../src/data/param7a_decl.spy
+.. literalinclude:: /src/data/param7a_decl.spy
:language: python
The following ``param`` command defines a matrix of parameter values:
-.. literalinclude:: ../../src/data/param7a.dat
+.. literalinclude:: /src/data/param7a.dat
:language: none
Additionally, the following syntax can be used to specify a transposed
matrix of parameter values:
-.. literalinclude:: ../../src/data/param7b.dat
+.. literalinclude:: /src/data/param7b.dat
:language: none
This functionality facilitates the presentation of parameter data in a
@@ -355,13 +355,13 @@ be specified as a series of slices. Each slice is defined by a template
followed by a list of index and parameter values. Suppose that
parameter ``B`` is indexed over set ``A`` that has dimension 4:
-.. literalinclude:: ../../src/data/param8a_decl.spy
+.. literalinclude:: /src/data/param8a_decl.spy
:language: python
The following ``param`` command defines a matrix of parameter values
with multiple templates:
-.. literalinclude:: ../../src/data/param8a.dat
+.. literalinclude:: /src/data/param8a.dat
:language: none
The ``B`` parameter consists of four values: ``B[a,1,a,1]=10``,
@@ -376,7 +376,7 @@ data declaration than is possible with a ``param`` declaration. The
following example illustrates a simple ``table`` command that declares
data for a single parameter:
-.. literalinclude:: ../../src/data/table0.dat
+.. literalinclude:: /src/data/table0.dat
:language: none
The parameter ``M`` is indexed by column ``A``, which must be
@@ -385,20 +385,20 @@ are provided after the colon and before the colon-equal (``:=``).
Subsequently, the table data is provided. The syntax is not sensitive
to whitespace, so the following is an equivalent ``table`` command:
-.. literalinclude:: ../../src/data/table1.dat
+.. literalinclude:: /src/data/table1.dat
:language: none
Multiple parameters can be declared by simply including additional
parameter names. For example:
-.. literalinclude:: ../../src/data/table2.dat
+.. literalinclude:: /src/data/table2.dat
:language: none
This example declares data for the ``M`` and ``N`` parameters, which
have different indexing columns. The indexing columns represent set
data, which is specified separately. For example:
-.. literalinclude:: ../../src/data/table3.dat
+.. literalinclude:: /src/data/table3.dat
:language: none
This example declares data for the ``M`` and ``N`` parameters, along
@@ -406,12 +406,12 @@ with the ``A`` and ``Z`` indexing sets. The correspondence between the
index set ``Z`` and the indices of parameter ``N`` can be made more
explicit by indexing ``N`` by ``Z``:
-.. literalinclude:: ../../src/data/table4.dat
+.. literalinclude:: /src/data/table4.dat
:language: none
Set data can also be specified independent of parameter data:
-.. literalinclude:: ../../src/data/table5.dat
+.. literalinclude:: /src/data/table5.dat
:language: none
.. warning::
@@ -423,13 +423,13 @@ Set data can also be specified independent of parameter data:
that is initialized. For example, the ``table`` command initializes
a set ``Z`` and a parameter ``M`` that are not related:
- .. literalinclude:: ../../src/data/table7.dat
+ .. literalinclude:: /src/data/table7.dat
:language: none
Finally, simple parameter values can also be specified with a ``table``
command:
-.. literalinclude:: ../../src/data/table6.dat
+.. literalinclude:: /src/data/table6.dat
:language: none
The previous examples considered examples of the ``table`` command where
@@ -437,7 +437,7 @@ column labels are provided. The ``table`` command can also be used
without column labels. For example, the first example can be revised to
omit column labels as follows:
-.. literalinclude:: ../../src/data/table0.ul.dat
+.. literalinclude:: /src/data/table0.ul.dat
:language: none
The ``columns=4`` is a keyword-value pair that defines the number of
@@ -450,12 +450,12 @@ braces syntax declares the column where the ``M`` data is provided.
Similarly, set data can be declared referencing the integer column
labels:
-.. literalinclude:: ../../src/data/table3.ul.dat
+.. literalinclude:: /src/data/table3.ul.dat
:language: none
Declared set names can also be used to index parameters:
-.. literalinclude:: ../../src/data/table4.ul.dat
+.. literalinclude:: /src/data/table4.ul.dat
:language: none
Finally, we compare and contrast the ``table`` and ``param`` commands.
@@ -521,13 +521,13 @@ Simple Load Examples
The simplest illustration of the ``load`` command is specifying data for
an indexed parameter. Consider the file ``Y.tab``:
-.. literalinclude:: ../../src/data/Y.tab
+.. literalinclude:: /src/data/Y.tab
:language: none
This file specifies the values of parameter ``Y`` which is indexed by
set ``A``. The following ``load`` command loads the parameter data:
-.. literalinclude:: ../../src/data/import1.tab.dat
+.. literalinclude:: /src/data/import1.tab.dat
:language: none
The first argument is the filename. The options after the colon
@@ -538,7 +538,7 @@ indicates the parameter that is initialized.
Similarly, the following load command loads both the parameter data as
well as the index set ``A``:
-.. literalinclude:: ../../src/data/import2.tab.dat
+.. literalinclude:: /src/data/import2.tab.dat
:language: none
The difference is the specification of the index set, ``A=[A]``, which
@@ -548,24 +548,24 @@ ASCII table file.
Set data can also be loaded from a ASCII table file that contains a
single column of data:
-.. literalinclude:: ../../src/data/A.tab
+.. literalinclude:: /src/data/A.tab
:language: none
The ``format`` option must be specified to denote the fact that the
relational data is being interpreted as a set:
-.. literalinclude:: ../../src/data/import3.tab.dat
+.. literalinclude:: /src/data/import3.tab.dat
:language: none
Note that this allows for specifying set data that contains tuples.
Consider file ``C.tab``:
-.. literalinclude:: ../../src/data/C.tab
+.. literalinclude:: /src/data/C.tab
:language: none
A similar ``load`` syntax will load this data into set ``C``:
-.. literalinclude:: ../../src/data/import4.tab.dat
+.. literalinclude:: /src/data/import4.tab.dat
:language: none
Note that this example requires that ``C`` be declared with dimension
@@ -609,7 +609,7 @@ describes different specifications and how they define how data is
loaded into a model. Suppose file ``ABCD.tab`` defines the following
relational table:
-.. literalinclude:: ../../src/data/ABCD.tab
+.. literalinclude:: /src/data/ABCD.tab
:language: none
There are many ways to interpret this relational table. It could
@@ -621,7 +621,7 @@ for specifying how a table is interpreted.
A simple specification is to interpret the relational table as a set:
-.. literalinclude:: ../../src/data/ABCD1.dat
+.. literalinclude:: /src/data/ABCD1.dat
:language: none
Note that ``Z`` is a set in the model that the data is being loaded
@@ -631,7 +631,7 @@ data from this table.
Another simple specification is to interpret the relational table as a
parameter with indexed by 3-tuples:
-.. literalinclude:: ../../src/data/ABCD2.dat
+.. literalinclude:: /src/data/ABCD2.dat
:language: none
Again, this requires that ``D`` be a parameter in the model that the
@@ -639,14 +639,14 @@ data is being loaded into. Additionally, the index set for ``D`` must
contain the indices that are specified in the table. The ``load``
command also allows for the specification of the index set:
-.. literalinclude:: ../../src/data/ABCD3.dat
+.. literalinclude:: /src/data/ABCD3.dat
:language: none
This specifies that the index set is loaded into the ``Z`` set in the
model. Similarly, data can be loaded into another parameter than what
is specified in the relational table:
-.. literalinclude:: ../../src/data/ABCD4.dat
+.. literalinclude:: /src/data/ABCD4.dat
:language: none
This specifies that the index set is loaded into the ``Z`` set and that
@@ -658,13 +658,13 @@ specification of data mappings from columns in a relational table into
index sets and parameters. For example, suppose that a model is defined
with set ``Z`` and parameters ``Y`` and ``W``:
-.. literalinclude:: ../../src/data/ABCD5_decl.spy
+.. literalinclude:: /src/data/ABCD5_decl.spy
:language: python
Then the following command defines how these data items are loaded using
columns ``B``, ``C`` and ``D``:
-.. literalinclude:: ../../src/data/ABCD5.dat
+.. literalinclude:: /src/data/ABCD5.dat
:language: none
When the ``using`` option is omitted the data manager is inferred from
@@ -672,13 +672,13 @@ the filename suffix. However, the filename suffix does not always
reflect the format of the data it contains. For example, consider the
relational table in the file ``ABCD.txt``:
-.. literalinclude:: ../../src/data/ABCD.txt
+.. literalinclude:: /src/data/ABCD.txt
:language: none
We can specify the ``using`` option to load from this file into
parameter ``D`` and set ``Z``:
-.. literalinclude:: ../../src/data/ABCD6.dat
+.. literalinclude:: /src/data/ABCD6.dat
:language: none
.. note::
@@ -692,7 +692,7 @@ parameter ``D`` and set ``Z``:
The following data managers are supported in Pyomo 5.1:
- .. literalinclude:: ../../src/data/data_managers.txt
+ .. literalinclude:: /src/data/data_managers.txt
:language: none
Interpreting Tabular Data
@@ -725,12 +725,12 @@ A table with a single value can be interpreted as a simple parameter
using the ``param`` format value. Suppose that ``Z.tab`` contains the
following table:
-.. literalinclude:: ../../src/data/Z.tab
+.. literalinclude:: /src/data/Z.tab
:language: none
The following load command then loads this value into parameter ``p``:
-.. literalinclude:: ../../src/data/import6.tab.dat
+.. literalinclude:: /src/data/import6.tab.dat
:language: none
Sets with 2-tuple data can be represented with a matrix format that
@@ -739,12 +739,12 @@ relational table as a matrix that defines a set of 2-tuples where ``+``
denotes a valid tuple and ``-`` denotes an invalid tuple. Suppose that
``D.tab`` contains the following relational table:
-.. literalinclude:: ../../src/data/D.tab
+.. literalinclude:: /src/data/D.tab
:language: none
Then the following load command loads data into set ``B``:
-.. literalinclude:: ../../src/data/import5.tab.dat
+.. literalinclude:: /src/data/import5.tab.dat
:language: none
This command declares the following 2-tuples: ``('A1',1)``,
@@ -754,19 +754,19 @@ Parameters with 2-tuple indices can be interpreted with a matrix format
that where rows and columns are different indices. Suppose that
``U.tab`` contains the following table:
-.. literalinclude:: ../../src/data/U.tab
+.. literalinclude:: /src/data/U.tab
:language: none
Then the following load command loads this value into parameter ``U``
with a 2-dimensional index using the ``array`` format value.:
-.. literalinclude:: ../../src/data/import7.tab.dat
+.. literalinclude:: /src/data/import7.tab.dat
:language: none
The ``transpose_array`` format value also interprets the table as a
matrix, but it loads the data in a transposed format:
-.. literalinclude:: ../../src/data/import8.tab.dat
+.. literalinclude:: /src/data/import8.tab.dat
:language: none
Note that these format values do not support the initialization of the
@@ -789,7 +789,7 @@ in the following figure:
The following command loads this data to initialize parameter ``D`` and
index ``Z``:
-.. literalinclude:: ../../src/data/ABCD7.dat
+.. literalinclude:: /src/data/ABCD7.dat
:language: none
Thus, the syntax for loading data from spreadsheets only differs from
@@ -809,7 +809,7 @@ command loads data from the Excel spreadsheet ``ABCD.xls`` using the
``pyodbc`` interface. The command loads this data to initialize
parameter ``D`` and index ``Z``:
-.. literalinclude:: ../../src/data/ABCD8.dat
+.. literalinclude:: /src/data/ABCD8.dat
:language: none
The ``using`` option specifies that the ``pyodbc`` package will be
@@ -818,7 +818,7 @@ specifies that the table ``ABCD`` is loaded from this spreadsheet.
Similarly, the following command specifies a data connection string
to specify the ODBC driver explicitly:
-.. literalinclude:: ../../src/data/ABCD9.dat
+.. literalinclude:: /src/data/ABCD9.dat
:language: none
ODBC drivers are generally tailored to the type of data source that
@@ -836,7 +836,7 @@ task of minimizing the cost for a meal at a fast food restaurant -- they
must purchase a sandwich, side, and a drink for the lowest cost. The
following is a Pyomo model for this problem:
-.. literalinclude:: ../../src/data/diet1.py
+.. literalinclude:: /src/data/diet1.py
:language: python
Suppose that the file ``diet1.sqlite`` be a SQLite database file that
@@ -884,7 +884,7 @@ We can solve the ``diet1`` model using the Python definition in
``diet.sqlite.dat`` specifies a ``load`` command that uses that
``sqlite3`` data manager and embeds a SQL query to retrieve the data:
-.. literalinclude:: ../../src/data/diet.sqlite.dat
+.. literalinclude:: /src/data/diet.sqlite.dat
:language: none
The PyODBC driver module will pass the SQL query through an Access ODBC
@@ -904,7 +904,7 @@ The ``include`` command allows a data command file to execute data
commands from another file. For example, the following command file
executes data commands from ``ex1.dat`` and then ``ex2.dat``:
-.. literalinclude:: ../../src/data/ex.dat
+.. literalinclude:: /src/data/ex.dat
:language: none
Pyomo is sensitive to the order of execution of data commands, since
@@ -921,7 +921,7 @@ to structure the specification of Pyomo's data commands. Specifically,
a namespace declaration is used to group data commands and to provide a
group label. Consider the following data command file:
-.. literalinclude:: ../../src/data/namespace1.dat
+.. literalinclude:: /src/data/namespace1.dat
:language: none
This data file defines two namespaces: ``ns1`` and ``ns2`` that
diff --git a/doc/OnlineDocs/working_abstractmodels/data/index.rst b/doc/OnlineDocs/howto/abstract_models/data/index.rst
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/data/index.rst
rename to doc/OnlineDocs/howto/abstract_models/data/index.rst
diff --git a/doc/OnlineDocs/working_abstractmodels/data/native.rst b/doc/OnlineDocs/howto/abstract_models/data/native.rst
similarity index 70%
rename from doc/OnlineDocs/working_abstractmodels/data/native.rst
rename to doc/OnlineDocs/howto/abstract_models/data/native.rst
index ed92d78d78e..f1a25183795 100644
--- a/doc/OnlineDocs/working_abstractmodels/data/native.rst
+++ b/doc/OnlineDocs/howto/abstract_models/data/native.rst
@@ -4,7 +4,8 @@ Using Standard Data Types
Defining Constant Values
------------------------
-In many cases, Pyomo models can be constructed without :class:`~pyomo.environ.Set` and :class:`~pyomo.environ.Param` data components. Native Python data types
+In many cases, Pyomo models can be constructed without :class:`Set` and
+:class:`~Param` data components. Native Python data types
class can be simply used to define constant values in Pyomo expressions.
Consequently, Python sets, lists and dictionaries can be used to
construct Pyomo models, as well as a wide range of other Python classes.
@@ -34,51 +35,51 @@ can be initialized with:
* list, set and tuple data:
- .. literalinclude:: ../../src/dataportal/set_initialization_decl2.spy
+ .. literalinclude:: /src/dataportal/set_initialization_decl2.spy
:language: python
* generators:
- .. literalinclude:: ../../src/dataportal/set_initialization_decl3.spy
+ .. literalinclude:: /src/dataportal/set_initialization_decl3.spy
:language: python
* numpy arrays:
- .. literalinclude:: ../../src/dataportal/set_initialization_decl4.spy
+ .. literalinclude:: /src/dataportal/set_initialization_decl4.spy
:language: python
Sets can also be indirectly initialized with functions that return
native Python data:
-.. literalinclude:: ../../src/dataportal/set_initialization_decl5.spy
+.. literalinclude:: /src/dataportal/set_initialization_decl5.spy
:language: python
Indexed sets can be initialized with dictionary data where the
dictionary values are iterable data:
-.. literalinclude:: ../../src/dataportal/set_initialization_decl6.spy
+.. literalinclude:: /src/dataportal/set_initialization_decl6.spy
:language: python
Parameter Components
^^^^^^^^^^^^^^^^^^^^
-When a parameter is a single value, then a :class:`~pyomo.environ.Param` component can be simply initialized with a
-value:
+When a parameter is a single value, then a :class:`~pyomo.environ.Param`
+component can be simply initialized with a value:
-.. literalinclude:: ../../src/dataportal/param_initialization_decl1.spy
+.. literalinclude:: /src/dataportal/param_initialization_decl1.spy
:language: python
More generally, :class:`~pyomo.environ.Param`
components can be initialized with dictionary data where the dictionary
values are single values:
-.. literalinclude:: ../../src/dataportal/param_initialization_decl2.spy
+.. literalinclude:: /src/dataportal/param_initialization_decl2.spy
:language: python
Parameters can also be indirectly initialized with functions that
return native Python data:
-.. literalinclude:: ../../src/dataportal/param_initialization_decl3.spy
+.. literalinclude:: /src/dataportal/param_initialization_decl3.spy
:language: python
diff --git a/doc/OnlineDocs/working_abstractmodels/data/raw_dicts.rst b/doc/OnlineDocs/howto/abstract_models/data/raw_dicts.rst
similarity index 88%
rename from doc/OnlineDocs/working_abstractmodels/data/raw_dicts.rst
rename to doc/OnlineDocs/howto/abstract_models/data/raw_dicts.rst
index f78e349c28b..77ce78effd6 100644
--- a/doc/OnlineDocs/working_abstractmodels/data/raw_dicts.rst
+++ b/doc/OnlineDocs/howto/abstract_models/data/raw_dicts.rst
@@ -14,12 +14,12 @@ components, the required data dictionary maps the implicit index
.. doctest::
- >>> from pyomo.environ import *
- >>> m = AbstractModel()
- >>> m.I = Set()
- >>> m.p = Param()
- >>> m.q = Param(m.I)
- >>> m.r = Param(m.I, m.I, default=0)
+ >>> import pyomo.environ as pyo
+ >>> m = pyo.AbstractModel()
+ >>> m.I = pyo.Set()
+ >>> m.p = pyo.Param()
+ >>> m.q = pyo.Param(m.I)
+ >>> m.r = pyo.Param(m.I, m.I, default=0)
>>> data = {None: {
... 'I': {None: [1,2,3]},
... 'p': {None: 100},
diff --git a/doc/OnlineDocs/working_abstractmodels/data/storing_data.rst b/doc/OnlineDocs/howto/abstract_models/data/storing_data.rst
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/data/storing_data.rst
rename to doc/OnlineDocs/howto/abstract_models/data/storing_data.rst
diff --git a/doc/OnlineDocs/working_abstractmodels/index.rst b/doc/OnlineDocs/howto/abstract_models/index.rst
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/index.rst
rename to doc/OnlineDocs/howto/abstract_models/index.rst
diff --git a/doc/OnlineDocs/working_abstractmodels/instantiating_models.rst b/doc/OnlineDocs/howto/abstract_models/instantiating_models.rst
similarity index 100%
rename from doc/OnlineDocs/working_abstractmodels/instantiating_models.rst
rename to doc/OnlineDocs/howto/abstract_models/instantiating_models.rst
diff --git a/doc/OnlineDocs/working_abstractmodels/pyomo_command.rst b/doc/OnlineDocs/howto/abstract_models/pyomo_command.rst
similarity index 97%
rename from doc/OnlineDocs/working_abstractmodels/pyomo_command.rst
rename to doc/OnlineDocs/howto/abstract_models/pyomo_command.rst
index aabfc8667f7..13fac82cc71 100644
--- a/doc/OnlineDocs/working_abstractmodels/pyomo_command.rst
+++ b/doc/OnlineDocs/howto/abstract_models/pyomo_command.rst
@@ -90,7 +90,7 @@ When there seem to be troubles expressing the model, it is often useful
to embed print commands in the model in places that will yield helpful
information. Consider the following snippet:
-.. literalinclude:: ../src/scripting/spy4PyomoCommand_Troubleshooting_printed_command.spy
+.. literalinclude:: /src/scripting/spy4PyomoCommand_Troubleshooting_printed_command.spy
:language: python
The effect will be to output every member of the set ``model.I`` at the
diff --git a/doc/OnlineDocs/howto/debugging.rst b/doc/OnlineDocs/howto/debugging.rst
new file mode 100644
index 00000000000..f876dd39459
--- /dev/null
+++ b/doc/OnlineDocs/howto/debugging.rst
@@ -0,0 +1,4 @@
+Debugging Models
+================
+
+TODO
diff --git a/doc/OnlineDocs/howto/index.rst b/doc/OnlineDocs/howto/index.rst
new file mode 100644
index 00000000000..9f700bff4e8
--- /dev/null
+++ b/doc/OnlineDocs/howto/index.rst
@@ -0,0 +1,12 @@
+How-To Guides
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ interrogating
+ manipulating
+ solver_recipes
+ abstract_models/index.rst
+ debugging
+ ../contribution_guide
diff --git a/doc/OnlineDocs/howto/interrogating.rst b/doc/OnlineDocs/howto/interrogating.rst
new file mode 100644
index 00000000000..909b1bf9490
--- /dev/null
+++ b/doc/OnlineDocs/howto/interrogating.rst
@@ -0,0 +1,166 @@
+Interrogating Models
+====================
+
+.. _VarAccess:
+
+Accessing Variable Values
+-------------------------
+
+Primal Variable Values
+^^^^^^^^^^^^^^^^^^^^^^
+
+Often, the point of optimization is to get optimal values of
+variables. Some users may want to process the values in a script. We
+will describe how to access a particular variable from a Python script
+as well as how to access all variables from a Python script and from a
+callback. This should enable the reader to understand how to get the
+access that they desire. The Iterative example given above also
+illustrates access to variable values.
+
+One Variable from a Python Script
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Assuming the model has been instantiated and solved and the results have
+been loaded back into the instance object, then we can make use of the
+fact that the variable is a member of the instance object and its value
+can be accessed using its ``value`` member. For example, suppose the
+model contains a variable named ``quant`` that is a singleton (has no
+indexes) and suppose further that the name of the instance object is
+``instance``. Then the value of this variable can be accessed using
+``pyo.value(instance.quant)``. Variables with indexes can be referenced
+by supplying the index.
+
+Consider the following very simple example, which is similar to the
+iterative example. This is a concrete model. In this example, the value
+of ``x[2]`` is accessed.
+
+.. literalinclude:: /src/scripting/noiteration1.py
+ :language: python
+
+.. note::
+
+ If this script is run without modification, Pyomo is likely to issue
+ a warning because there are no constraints. The warning is because
+ some solvers may fail if given a problem instance that does not have
+ any constraints.
+
+All Variables from a Python Script
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As with one variable, we assume that the model has been instantiated
+and solved. Assuming the instance object has the name ``instance``,
+the following code snippet displays all variables and their values:
+
+ >>> for v in instance.component_objects(pyo.Var, active=True):
+ ... print("Variable",v) # doctest: +SKIP
+ ... for index in v:
+ ... print (" ",index, pyo.value(v[index])) # doctest: +SKIP
+
+
+Alternatively,
+
+ >>> for v in instance.component_data_objects(pyo.Var, active=True):
+ ... print(v, pyo.value(v)) # doctest: +SKIP
+
+This code could be improved by checking to see if the variable is not
+indexed (i.e., the only index value is ``None``), then the code could
+print the value without the word ``None`` next to it.
+
+Assuming again that the model has been instantiated and solved and the
+results have been loaded back into the instance object. Here is a code
+snippet for fixing all integers at their current value:
+
+ >>> for var in instance.component_data_objects(pyo.Var, active=True):
+ ... if not var.is_continuous():
+ ... print ("fixing "+str(v)) # doctest: +SKIP
+ ... var.fixed = True # fix the current value
+
+
+Another way to access all of the variables (particularly if there are
+blocks) is as follows (this particular snippet assumes that instead of
+`import pyomo.environ as pyo` `from pyo.environ import *` was used):
+
+.. literalinclude:: /src/scripting/block_iter_example_compprintloop.spy
+ :language: python
+
+.. _ParamAccess:
+
+Accessing Parameter Values
+--------------------------
+
+Accessing parameter values is completely analogous to accessing variable
+values. For example, here is a code snippet to print the name and value
+of every Parameter in a model:
+
+ >>> for parmobject in instance.component_objects(pyo.Param, active=True):
+ ... nametoprint = str(str(parmobject.name))
+ ... print ("Parameter ", nametoprint) # doctest: +SKIP
+ ... for index in parmobject:
+ ... vtoprint = pyo.value(parmobject[index])
+ ... print (" ",index, vtoprint) # doctest: +SKIP
+
+
+Accessing Duals
+---------------
+
+Access to dual values in scripts is similar to accessing primal variable
+values, except that dual values are not captured by default so
+additional directives are needed before optimization to signal that
+duals are desired.
+
+To get duals without a script, use the ``pyomo`` option
+``--solver-suffixes='dual'`` which will cause dual values to be included
+in output. Note: In addition to duals (``dual``) , reduced costs
+(``rc``) and slack values (``slack``) can be requested. All suffixes can
+be requested using the ``pyomo`` option ``--solver-suffixes='.*'``
+
+.. warning::
+
+ Some of the duals may have the value ``None``, rather than ``0``.
+
+Access Duals in a Python Script
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To signal that duals are desired, declare a Suffix component with the
+name "dual" on the model or instance with an IMPORT or IMPORT_EXPORT
+direction.
+
+.. literalinclude:: /src/scripting/driveabs2_Create_dual_suffix_component.spy
+ :language: python
+
+See the section on Suffixes :ref:`Suffixes` for more information on
+Pyomo's Suffix component. After the results are obtained and loaded into
+an instance, duals can be accessed in the following fashion.
+
+.. literalinclude:: /src/scripting/driveabs2_Access_all_dual.spy
+ :language: python
+
+The following snippet will only work, of course, if there is a
+constraint with the name ``AxbConstraint`` that has and index, which is
+the string ``Film``.
+
+.. literalinclude:: /src/scripting/driveabs2_Access_one_dual.spy
+ :language: python
+
+Here is a complete example that relies on the file ``abstract2.py`` to
+provide the model and the file ``abstract2.dat`` to provide the
+data. Note that the model in ``abstract2.py`` does contain a constraint
+named ``AxbConstraint`` and ``abstract2.dat`` does specify an index for
+it named ``Film``.
+
+.. literalinclude:: /src/scripting/driveabs2.spy
+ :language: python
+
+Concrete models are slightly different because the model is the
+instance. Here is a complete example that relies on the file
+``concrete1.py`` to provide the model and instantiate it.
+
+.. literalinclude:: /src/scripting/driveconc1.py
+ :language: python
+
+Accessing Slacks
+----------------
+
+The functions ``lslack()`` and ``uslack()`` return the upper and lower
+slacks, respectively, for a constraint.
+
diff --git a/doc/OnlineDocs/working_models.rst b/doc/OnlineDocs/howto/manipulating.rst
similarity index 52%
rename from doc/OnlineDocs/working_models.rst
rename to doc/OnlineDocs/howto/manipulating.rst
index dbd7aa383e3..783fa4fe0e2 100644
--- a/doc/OnlineDocs/working_models.rst
+++ b/doc/OnlineDocs/howto/manipulating.rst
@@ -1,4 +1,4 @@
-Working with Pyomo Models
+Manipulating Pyomo Models
=========================
This section gives an overview of commonly used scripting commands when
@@ -58,7 +58,7 @@ computer to solve the problem or even to iterate over solutions. This
example is provided just to illustrate some elementary aspects of
scripting.
-.. literalinclude:: src/scripting/iterative1.spy
+.. literalinclude:: /src/scripting/iterative1.spy
:language: python
Let us now analyze this script. The first line is a comment that happens
@@ -66,7 +66,7 @@ to give the name of the file. This is followed by two lines that import
symbols for Pyomo. The pyomo namespace is imported as
``pyo``. Therefore, ``pyo.`` must precede each use of a Pyomo name.
-.. literalinclude:: src/scripting/iterative1_Import_symbols_for_pyomo.spy
+.. literalinclude:: /src/scripting/iterative1_Import_symbols_for_pyomo.spy
:language: python
An object to perform optimization is created by calling
@@ -74,7 +74,7 @@ An object to perform optimization is created by calling
argument would be ``'gurobi'`` if, e.g., Gurobi was desired instead of
glpk:
-.. literalinclude:: src/scripting/iterative1_Call_SolverFactory_with_argument.spy
+.. literalinclude:: /src/scripting/iterative1_Call_SolverFactory_with_argument.spy
:language: python
The next lines after a comment create a model. For our discussion here,
@@ -86,13 +86,13 @@ to keep it simple. Constraints could be present in the base model.
Even though it is an abstract model, the base model is fully specified
by these commands because it requires no external data:
-.. literalinclude:: src/scripting/iterative1_Create_base_model.spy
+.. literalinclude:: /src/scripting/iterative1_Create_base_model.spy
:language: python
The next line is not part of the base model specification. It creates an
empty constraint list that the script will use to add constraints.
-.. literalinclude:: src/scripting/iterative1_Create_empty_constraint_list.spy
+.. literalinclude:: /src/scripting/iterative1_Create_empty_constraint_list.spy
:language: python
The next non-comment line creates the instantiated model and refers to
@@ -103,19 +103,19 @@ the ``create`` function is called without arguments because none are
needed; however, the name of a file with data commands is given as an
argument in many scripts.
-.. literalinclude:: src/scripting/iterative1_Create_instantiated_model.spy
+.. literalinclude:: /src/scripting/iterative1_Create_instantiated_model.spy
:language: python
The next line invokes the solver and refers to the object contain
results with the Python variable ``results``.
-.. literalinclude:: src/scripting/iterative1_Solve_and_refer_to_results.spy
+.. literalinclude:: /src/scripting/iterative1_Solve_and_refer_to_results.spy
:language: python
The solve function loads the results into the instance, so the next line
writes out the updated values.
-.. literalinclude:: src/scripting/iterative1_Display_updated_value.spy
+.. literalinclude:: /src/scripting/iterative1_Display_updated_value.spy
:language: python
The next non-comment line is a Python iteration command that will
@@ -123,7 +123,7 @@ successively assign the integers from 0 to 4 to the Python variable
``i``, although that variable is not used in script. This loop is what
causes the script to generate five more solutions:
-.. literalinclude:: src/scripting/iterative1_Assign_integers.spy
+.. literalinclude:: /src/scripting/iterative1_Assign_integers.spy
:language: python
An expression is built up in the Python variable named ``expr``. The
@@ -135,7 +135,7 @@ zero and the expression in ``expr`` is augmented accordingly. Although
Pyomo expression when it is assigned expressions involving Pyomo
variable objects:
-.. literalinclude:: src/scripting/iterative1_Iteratively_assign_and_test.spy
+.. literalinclude:: /src/scripting/iterative1_Iteratively_assign_and_test.spy
:language: python
During the first iteration (when ``i`` is 0), we know that all values of
@@ -159,15 +159,15 @@ function to get it.
The next line adds to the constraint list called ``c`` the requirement
that the expression be greater than or equal to one:
-.. literalinclude:: src/scripting/iterative1_Add_expression_constraint.spy
+.. literalinclude:: /src/scripting/iterative1_Add_expression_constraint.spy
:language: python
-The proof that this precludes the last solution is left as an exerise
+The proof that this precludes the last solution is left as an exercise
for the reader.
The final lines in the outer for loop find a solution and display it:
-.. literalinclude:: src/scripting/iterative1_Find_and_display_solution.spy
+.. literalinclude:: /src/scripting/iterative1_Find_and_display_solution.spy
:language: python
.. note::
@@ -268,14 +268,14 @@ Fixing Variables and Re-solving
Instead of changing model data, scripts are often used to fix variable
values. The following example illustrates this.
-.. literalinclude:: src/scripting/iterative2.spy
+.. literalinclude:: /src/scripting/iterative2.spy
:language: python
In this example, the variables are binary. The model is solved and then
the value of ``model.x[2]`` is flipped to the opposite value before
solving the model again. The main lines of interest are:
-.. literalinclude:: src/scripting/iterative2_Flip_value_before_solve_again.spy
+.. literalinclude:: /src/scripting/iterative2_Flip_value_before_solve_again.spy
:language: python
This could also have been accomplished by setting the upper and lower
@@ -393,312 +393,3 @@ individual index:
>>> model.con = pyo.Constraint(model.s, rule=_con)
>>> model.con.deactivate() # Deactivate all indices
>>> model.con[1].activate() # Activate single index
-
-
-
-
-.. _VarAccess:
-
-Accessing Variable Values
--------------------------
-
-Primal Variable Values
-^^^^^^^^^^^^^^^^^^^^^^
-
-Often, the point of optimization is to get optimal values of
-variables. Some users may want to process the values in a script. We
-will describe how to access a particular variable from a Python script
-as well as how to access all variables from a Python script and from a
-callback. This should enable the reader to understand how to get the
-access that they desire. The Iterative example given above also
-illustrates access to variable values.
-
-One Variable from a Python Script
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Assuming the model has been instantiated and solved and the results have
-been loaded back into the instance object, then we can make use of the
-fact that the variable is a member of the instance object and its value
-can be accessed using its ``value`` member. For example, suppose the
-model contains a variable named ``quant`` that is a singleton (has no
-indexes) and suppose further that the name of the instance object is
-``instance``. Then the value of this variable can be accessed using
-``pyo.value(instance.quant)``. Variables with indexes can be referenced
-by supplying the index.
-
-Consider the following very simple example, which is similar to the
-iterative example. This is a concrete model. In this example, the value
-of ``x[2]`` is accessed.
-
-.. literalinclude:: src/scripting/noiteration1.py
- :language: python
-
-.. note::
-
- If this script is run without modification, Pyomo is likely to issue
- a warning because there are no constraints. The warning is because
- some solvers may fail if given a problem instance that does not have
- any constraints.
-
-All Variables from a Python Script
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-As with one variable, we assume that the model has been instantiated
-and solved. Assuming the instance object has the name ``instance``,
-the following code snippet displays all variables and their values:
-
- >>> for v in instance.component_objects(pyo.Var, active=True):
- ... print("Variable",v) # doctest: +SKIP
- ... for index in v:
- ... print (" ",index, pyo.value(v[index])) # doctest: +SKIP
-
-
-Alternatively,
-
- >>> for v in instance.component_data_objects(pyo.Var, active=True):
- ... print(v, pyo.value(v)) # doctest: +SKIP
-
-This code could be improved by checking to see if the variable is not
-indexed (i.e., the only index value is ``None``), then the code could
-print the value without the word ``None`` next to it.
-
-Assuming again that the model has been instantiated and solved and the
-results have been loaded back into the instance object. Here is a code
-snippet for fixing all integers at their current value:
-
- >>> for var in instance.component_data_objects(pyo.Var, active=True):
- ... if not var.is_continuous():
- ... print ("fixing "+str(v)) # doctest: +SKIP
- ... var.fixed = True # fix the current value
-
-
-Another way to access all of the variables (particularly if there are
-blocks) is as follows (this particular snippet assumes that instead of
-`import pyomo.environ as pyo` `from pyo.environ import *` was used):
-
-.. literalinclude:: src/scripting/block_iter_example_compprintloop.spy
- :language: python
-
-.. _ParamAccess:
-
-Accessing Parameter Values
---------------------------
-
-Accessing parameter values is completely analogous to accessing variable
-values. For example, here is a code snippet to print the name and value
-of every Parameter in a model:
-
- >>> for parmobject in instance.component_objects(pyo.Param, active=True):
- ... nametoprint = str(str(parmobject.name))
- ... print ("Parameter ", nametoprint) # doctest: +SKIP
- ... for index in parmobject:
- ... vtoprint = pyo.value(parmobject[index])
- ... print (" ",index, vtoprint) # doctest: +SKIP
-
-
-Accessing Duals
----------------
-
-Access to dual values in scripts is similar to accessing primal variable
-values, except that dual values are not captured by default so
-additional directives are needed before optimization to signal that
-duals are desired.
-
-To get duals without a script, use the ``pyomo`` option
-``--solver-suffixes='dual'`` which will cause dual values to be included
-in output. Note: In addition to duals (``dual``) , reduced costs
-(``rc``) and slack values (``slack``) can be requested. All suffixes can
-be requested using the ``pyomo`` option ``--solver-suffixes='.*'``
-
-.. warning::
-
- Some of the duals may have the value ``None``, rather than ``0``.
-
-Access Duals in a Python Script
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To signal that duals are desired, declare a Suffix component with the
-name "dual" on the model or instance with an IMPORT or IMPORT_EXPORT
-direction.
-
-.. literalinclude:: src/scripting/driveabs2_Create_dual_suffix_component.spy
- :language: python
-
-See the section on Suffixes :ref:`Suffixes` for more information on
-Pyomo's Suffix component. After the results are obtained and loaded into
-an instance, duals can be accessed in the following fashion.
-
-.. literalinclude:: src/scripting/driveabs2_Access_all_dual.spy
- :language: python
-
-The following snippet will only work, of course, if there is a
-constraint with the name ``AxbConstraint`` that has and index, which is
-the string ``Film``.
-
-.. literalinclude:: src/scripting/driveabs2_Access_one_dual.spy
- :language: python
-
-Here is a complete example that relies on the file ``abstract2.py`` to
-provide the model and the file ``abstract2.dat`` to provide the
-data. Note that the model in ``abstract2.py`` does contain a constraint
-named ``AxbConstraint`` and ``abstract2.dat`` does specify an index for
-it named ``Film``.
-
-.. literalinclude:: src/scripting/driveabs2.spy
- :language: python
-
-Concrete models are slightly different because the model is the
-instance. Here is a complete example that relies on the file
-``concrete1.py`` to provide the model and instantiate it.
-
-.. literalinclude:: src/scripting/driveconc1.py
- :language: python
-
-Accessing Slacks
-----------------
-
-The functions ``lslack()`` and ``uslack()`` return the upper and lower
-slacks, respectively, for a constraint.
-
-
-Accessing Solver Status
------------------------
-
-After a solve, the results object has a member ``Solution.Status`` that
-contains the solver status. The following snippet shows an example of
-access via a ``print`` statement:
-
-.. literalinclude:: src/scripting/spy4scripts_Print_solver_status.spy
- :language: python
-
-The use of the Python ``str`` function to cast the value to a be string
-makes it easy to test it. In particular, the value 'optimal' indicates
-that the solver succeeded. It is also possible to access Pyomo data that
-can be compared with the solver status as in the following code snippet:
-
-.. literalinclude:: src/scripting/spy4scripts_Pyomo_data_comparedwith_solver_status_1.spy
- :language: python
-
-Alternatively,
-
-.. literalinclude:: src/scripting/spy4scripts_Pyomo_data_comparedwith_solver_status_2.spy
- :language: python
-
-.. _TeeTrue:
-
-Display of Solver Output
-------------------------
-
-
-To see the output of the solver, use the option ``tee=True`` as in
-
-.. literalinclude:: src/scripting/spy4scripts_See_solver_output.spy
- :language: python
-
-This can be useful for troubleshooting solver difficulties.
-
-.. _SolverOpts:
-
-Sending Options to the Solver
------------------------------
-
-Most solvers accept options and Pyomo can pass options through to a
-solver. In scripts or callbacks, the options can be attached to the
-solver object by adding to its options dictionary as illustrated by this
-snippet:
-
-.. literalinclude:: src/scripting/spy4scripts_Add_option_to_solver.spy
- :language: python
-
-If multiple options are needed, then multiple dictionary entries should
-be added.
-
-Sometimes it is desirable to pass options as part of the call to the
-solve function as in this snippet:
-
-.. literalinclude:: src/scripting/spy4scripts_Add_multiple_options_to_solver.spy
- :language: python
-
-The quoted string is passed directly to the solver. If multiple options
-need to be passed to the solver in this way, they should be separated by
-a space within the quoted string. Notice that ``tee`` is a Pyomo option
-and is solver-independent, while the string argument to ``options`` is
-passed to the solver without very little processing by Pyomo. If the
-solver does not have a "threads" option, it will probably complain, but
-Pyomo will not.
-
-There are no default values for options on a ``SolverFactory``
-object. If you directly modify its options dictionary, as was done
-above, those options will persist across every call to
-``optimizer.solve(…)`` unless you delete them from the options
-dictionary. You can also pass a dictionary of options into the
-``opt.solve(…)`` method using the ``options`` keyword. Those options
-will only persist within that solve and temporarily override any
-matching options in the options dictionary on the solver object.
-
-Specifying the Path to a Solver
--------------------------------
-
-Often, the executables for solvers are in the path; however, for
-situations where they are not, the SolverFactory function accepts the
-keyword ``executable``, which you can use to set an absolute or relative
-path to a solver executable. E.g.,
-
-.. literalinclude:: src/scripting/spy4scripts_Set_path_to_solver_executable.spy
- :language: python
-
-Warm Starts
------------
-
-Some solvers support a warm start based on current values of
-variables. To use this feature, set the values of variables in the
-instance and pass ``warmstart=True`` to the ``solve()`` method. E.g.,
-
-.. literalinclude:: src/scripting/spy4scripts_Pass_warmstart_to_solver.spy
- :language: python
-
-.. note::
-
- The Cplex and Gurobi LP file (and Python) interfaces will generate an
- MST file with the variable data and hand this off to the solver in
- addition to the LP file.
-
-.. warning::
-
- Solvers using the NL file interface (e.g., "gurobi_ampl", "cplexamp")
- do not accept warmstart as a keyword to the solve() method as the NL
- file format, by default, includes variable initialization data (drawn
- from the current value of all variables).
-
-
-Solving Multiple Instances in Parallel
---------------------------------------
-
-Building and solving Pyomo models in parallel is a common requirement
-for many applications. We recommend using MPI for Python (mpi4py) for
-this purpose. For more information on mpi4py, see the mpi4py
-documentation (https://mpi4py.readthedocs.io/en/stable/). The example
-below demonstrates how to use mpi4py to solve two pyomo models in
-parallel. The example can be run with the following command:
-
-.. code-block::
-
- mpirun -np 2 python -m mpi4py parallel.py
-
-
-.. literalinclude:: src/scripting/parallel.py
- :language: python
-
-
-Changing the temporary directory
---------------------------------
-
-A "temporary" directory is used for many intermediate files. Normally,
-the name of the directory for temporary files is provided by the
-operating system, but the user can specify their own directory name.
-The pyomo command-line ``--tempdir`` option propagates through to the
-TempFileManager service. One can accomplish the same through the
-following few lines of code in a script:
-
-.. literalinclude:: src/scripting/spy4scripts_Specify_temporary_directory_name.spy
- :language: python
diff --git a/doc/OnlineDocs/howto/solver_recipes.rst b/doc/OnlineDocs/howto/solver_recipes.rst
new file mode 100644
index 00000000000..c9be02405e2
--- /dev/null
+++ b/doc/OnlineDocs/howto/solver_recipes.rst
@@ -0,0 +1,145 @@
+Solver Recipes
+==============
+
+
+Accessing Solver Status
+-----------------------
+
+After a solve, the results object has a member ``Solution.Status`` that
+contains the solver status. The following snippet shows an example of
+access via a ``print`` statement:
+
+.. literalinclude:: /src/scripting/spy4scripts_Print_solver_status.spy
+ :language: python
+
+The use of the Python ``str`` function to cast the value to a be string
+makes it easy to test it. In particular, the value 'optimal' indicates
+that the solver succeeded. It is also possible to access Pyomo data that
+can be compared with the solver status as in the following code snippet:
+
+.. literalinclude:: /src/scripting/spy4scripts_Pyomo_data_comparedwith_solver_status_1.spy
+ :language: python
+
+Alternatively,
+
+.. literalinclude:: /src/scripting/spy4scripts_Pyomo_data_comparedwith_solver_status_2.spy
+ :language: python
+
+.. _TeeTrue:
+
+Display of Solver Output
+------------------------
+
+
+To see the output of the solver, use the option ``tee=True`` as in
+
+.. literalinclude:: /src/scripting/spy4scripts_See_solver_output.spy
+ :language: python
+
+This can be useful for troubleshooting solver difficulties.
+
+.. _SolverOpts:
+
+Sending Options to the Solver
+-----------------------------
+
+Most solvers accept options and Pyomo can pass options through to a
+solver. In scripts or callbacks, the options can be attached to the
+solver object by adding to its options dictionary as illustrated by this
+snippet:
+
+.. literalinclude:: /src/scripting/spy4scripts_Add_option_to_solver.spy
+ :language: python
+
+If multiple options are needed, then multiple dictionary entries should
+be added.
+
+Sometimes it is desirable to pass options as part of the call to the
+solve function as in this snippet:
+
+.. literalinclude:: /src/scripting/spy4scripts_Add_multiple_options_to_solver.spy
+ :language: python
+
+The quoted string is passed directly to the solver. If multiple options
+need to be passed to the solver in this way, they should be separated by
+a space within the quoted string. Notice that ``tee`` is a Pyomo option
+and is solver-independent, while the string argument to ``options`` is
+passed to the solver without very little processing by Pyomo. If the
+solver does not have a "threads" option, it will probably complain, but
+Pyomo will not.
+
+There are no default values for options on a ``SolverFactory``
+object. If you directly modify its options dictionary, as was done
+above, those options will persist across every call to
+``optimizer.solve(…)`` unless you delete them from the options
+dictionary. You can also pass a dictionary of options into the
+``opt.solve(…)`` method using the ``options`` keyword. Those options
+will only persist within that solve and temporarily override any
+matching options in the options dictionary on the solver object.
+
+Specifying the Path to a Solver
+-------------------------------
+
+Often, the executables for solvers are in the path; however, for
+situations where they are not, the SolverFactory function accepts the
+keyword ``executable``, which you can use to set an absolute or relative
+path to a solver executable. E.g.,
+
+.. literalinclude:: /src/scripting/spy4scripts_Set_path_to_solver_executable.spy
+ :language: python
+
+Warm Starts
+-----------
+
+Some solvers support a warm start based on current values of
+variables. To use this feature, set the values of variables in the
+instance and pass ``warmstart=True`` to the ``solve()`` method. E.g.,
+
+.. literalinclude:: /src/scripting/spy4scripts_Pass_warmstart_to_solver.spy
+ :language: python
+
+.. note::
+
+ The Cplex and Gurobi LP file (and Python) interfaces will generate an
+ MST file with the variable data and hand this off to the solver in
+ addition to the LP file.
+
+.. warning::
+
+ Solvers using the NL file interface (e.g., "gurobi_ampl", "cplexamp")
+ do not accept warmstart as a keyword to the solve() method as the NL
+ file format, by default, includes variable initialization data (drawn
+ from the current value of all variables).
+
+
+Solving Multiple Instances in Parallel
+--------------------------------------
+
+Building and solving Pyomo models in parallel is a common requirement
+for many applications. We recommend using MPI for Python (mpi4py) for
+this purpose. For more information on mpi4py, see the mpi4py
+documentation (https://mpi4py.readthedocs.io/en/stable/). The example
+below demonstrates how to use mpi4py to solve two pyomo models in
+parallel. The example can be run with the following command:
+
+.. code-block::
+
+ mpirun -np 2 python -m mpi4py parallel.py
+
+
+.. literalinclude:: /src/scripting/parallel.py
+ :language: python
+
+
+Changing the temporary directory
+--------------------------------
+
+A "temporary" directory is used for many intermediate files. Normally,
+the name of the directory for temporary files is provided by the
+operating system, but the user can specify their own directory name.
+The pyomo command-line ``--tempdir`` option propagates through to the
+TempFileManager service. One can accomplish the same through the
+following few lines of code in a script:
+
+.. literalinclude:: /src/scripting/spy4scripts_Specify_temporary_directory_name.spy
+ :language: python
diff --git a/doc/OnlineDocs/index.rst b/doc/OnlineDocs/index.rst
index ef986a3429f..4d52f25c8d9 100644
--- a/doc/OnlineDocs/index.rst
+++ b/doc/OnlineDocs/index.rst
@@ -1,55 +1,125 @@
+=============================
Pyomo Documentation |release|
=============================
-.. image:: /../logos/pyomo/PyomoNewBlue3.png
- :scale: 10%
- :align: right
-
-Pyomo is a Python-based, open-source optimization modeling language
-with a diverse set of optimization capabilities.
-
-.. toctree::
- :maxdepth: 2
-
- installation.rst
- citing_pyomo.rst
- pyomo_overview/index.rst
- pyomo_modeling_components/index.rst
- solving_pyomo_models.rst
- working_models.rst
- working_abstractmodels/index.rst
- model_transformations/index.rst
- modeling_extensions/index.rst
- tutorial_examples.rst
- model_debugging/index.rst
- advanced_topics/index.rst
- errors.rst
- developer_reference/index.rst
- library_reference/index.rst
- contribution_guide.rst
- contributed_packages/index.rst
- related_packages.rst
- bibliography.rst
-
-Indices and Tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+.. Note: using rubric here so that the actual content from the toctree
+ is not considered to be sub-sections of "about" in LaTeX
+.. rubric:: About Pyomo
+ :heading-level: 2
+
+.. only:: html
+
+ .. image:: /../logos/pyomo/PyomoNewBlue3.png
+ :scale: 10%
+ :align: right
+
+Pyomo is a Python-based open-source software package that supports a
+diverse set of optimization capabilities for formulating, solving, and
+analyzing optimization models.
+
+A core capability of Pyomo is modeling structured optimization
+applications. Pyomo can be used to define general symbolic problems,
+create specific problem instances, and solve these instances using
+commercial and open-source solvers.
+
+.. only:: latex or text
+
+ .. toctree::
+ :maxdepth: 3
+
+ getting_started/index
+ howto/index
+ explanation/index
+ reference/index
-Pyomo Resources
----------------
-The Pyomo home page provides resources for Pyomo users:
+.. only:: html
-* http://pyomo.org
+ Contents
+ ========
+
+ .. list-table::
+ :width: 100%
+ :class: diataxis
+
+ * - .. tocref::
+ :maxdepth: 2
+ :titlesonly:
+
+ getting_started/index
+ - .. tocref::
+ :maxdepth: 2
+ :titlesonly:
+
+ howto/index
+ * - .. tocref::
+ :maxdepth: 3
+ :titlesonly:
+
+ explanation/index
+ - .. tocref::
+ :maxdepth: 3
+ :titlesonly:
+
+ reference/index
+
+
+Pyomo Resources
+===============
Pyomo development is hosted at GitHub:
* https://github.com/Pyomo/pyomo
-See the Pyomo Forum for online discussions of Pyomo:
+See the Pyomo Forum for online discussions of Pyomo or to ask a question:
* http://groups.google.com/group/pyomo-forum/
+
+Ask a question on StackOverflow using the ``#pyomo`` tag:
+
+* https://stackoverflow.com/questions/ask?tags=pyomo
+
+Additional Pyomo tutorials and examples can be found at the following links:
+
+* `Pyomo — Optimization Modeling in Python
+ `_ ([PyomoBookIII]_)
+
+* `Pyomo Workshop Slides and Exercises
+ `_
+
+* `Prof. Jeffrey Kantor's Pyomo Cookbook
+ `_
+
+* The `companion notebooks `_
+ for *Hands-On Mathematical Optimization with Python*
+
+* `Pyomo Gallery `_
+
+
+Contributing to Pyomo
+=====================
+
+Interested in contributing code or documentation to the project? Check out our
+:doc:`Contribution Guide `
+
+Related Packages
+================
+
+Pyomo is a key dependency for a number of other software packages for
+specific domains or customized solution strategies. A non-comprehensive
+list of Pyomo-related packages may be found :doc:`here `.
+
+
+Citing Pyomo
+============
+
+If you use Pyomo in your work, please cite:
+
+ Bynum, Michael L., Gabriel A. Hackebeil, William E. Hart, Carl D. Laird,
+ Bethany L. Nicholson, John D. Siirola, Jean-Paul Watson, and
+ David L. Woodruff. Pyomo - Optimization Modeling in Python, 3rd
+ Edition. Springer, 2021.
+
+Additionally, several Pyomo capabilities and subpackages are described
+in further detail in separate :ref:`publications`.
diff --git a/doc/OnlineDocs/library_reference/aml/index.rst b/doc/OnlineDocs/library_reference/aml/index.rst
deleted file mode 100644
index f06ca35b087..00000000000
--- a/doc/OnlineDocs/library_reference/aml/index.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-AML Library Reference
-=====================
-
-The following modeling components make up the core of the Pyomo
-Algebraic Modeling Language (AML). These classes are all available
-through the `pyomo.environ` namespace.
-
-.. currentmodule:: pyomo.environ
-
-.. autosummary::
-
- ConcreteModel
- AbstractModel
- Block
- Set
- RangeSet
- Param
- Var
- Objective
- Constraint
- ExternalFunction
- Reference
- SOSConstraint
-
-
-AML Component Documentation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: ConcreteModel
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: AbstractModel
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: Block
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: Constraint
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: ExternalFunction
- :show-inheritance:
- :special-members: __init__
- :members:
- :inherited-members:
-
-.. autoclass:: Objective
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: Param
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: RangeSet
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autofunction:: Reference
-
-.. autoclass:: Set
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: Var
- :show-inheritance:
- :members:
- :inherited-members:
-
-.. autoclass:: SOSConstraint
- :show-inheritance:
- :members:
- :inherited-members:
-
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.base.rst b/doc/OnlineDocs/library_reference/appsi/appsi.base.rst
deleted file mode 100644
index 1b6d5761182..00000000000
--- a/doc/OnlineDocs/library_reference/appsi/appsi.base.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-APPSI Base Classes
-==================
-
-.. autoclass:: pyomo.contrib.appsi.base.TerminationCondition
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.base.Results
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.base.Solver
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.base.PersistentSolver
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.base.SolverConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
- :exclude-members: NoArgument
-
-.. autoclass:: pyomo.contrib.appsi.base.MIPSolverConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
- :exclude-members: NoArgument
-
-.. autoclass:: pyomo.contrib.appsi.base.UpdateConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
- :exclude-members: NoArgument
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cbc.rst b/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cbc.rst
deleted file mode 100644
index a0a2f7d0f27..00000000000
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cbc.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-Cbc
-===
-
-.. autoclass:: pyomo.contrib.appsi.solvers.cbc.CbcConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
- :exclude-members: NoArgument
-
-.. autoclass:: pyomo.contrib.appsi.solvers.cbc.Cbc
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cplex.rst b/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cplex.rst
deleted file mode 100644
index 0906fd7ea76..00000000000
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.cplex.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-Cplex
-=====
-
-.. autoclass:: pyomo.contrib.appsi.solvers.cplex.CplexConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
- :exclude-members: NoArgument
-
-.. autoclass:: pyomo.contrib.appsi.solvers.cplex.CplexResults
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.solvers.cplex.Cplex
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.highs.rst b/doc/OnlineDocs/library_reference/appsi/appsi.solvers.highs.rst
deleted file mode 100644
index f2f72d0ad85..00000000000
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.highs.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-HiGHS
-=====
-
-.. autoclass:: pyomo.contrib.appsi.solvers.highs.HighsResults
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.solvers.highs.Highs
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.ipopt.rst b/doc/OnlineDocs/library_reference/appsi/appsi.solvers.ipopt.rst
deleted file mode 100644
index 0d095644100..00000000000
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.ipopt.rst
+++ /dev/null
@@ -1,14 +0,0 @@
-Ipopt
-=====
-
-.. autoclass:: pyomo.contrib.appsi.solvers.ipopt.IpoptConfig
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.solvers.ipopt.Ipopt
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/common/config.rst b/doc/OnlineDocs/library_reference/common/config.rst
deleted file mode 100644
index c5dc607977a..00000000000
--- a/doc/OnlineDocs/library_reference/common/config.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-pyomo.common.config
-===================
-
-.. currentmodule:: pyomo.common.config
-
-Core classes
-~~~~~~~~~~~~
-
-.. autosummary::
-
- ConfigDict
- ConfigList
- ConfigValue
-
-Utilities
-~~~~~~~~~
-
-.. autosummary::
-
- document_kwargs_from_configdict
-
-
-Domain validators
-~~~~~~~~~~~~~~~~~
-
-.. autosummary::
-
- Bool
- Integer
- PositiveInt
- NegativeInt
- NonNegativeInt
- NonPositiveInt
- PositiveFloat
- NegativeFloat
- NonPositiveFloat
- NonNegativeFloat
- In
- IsInstance
- InEnum
- ListOf
- Module
- Path
- PathList
- DynamicImplicitDomain
-
-.. autoclass:: ConfigBase
- :members:
- :undoc-members:
-
-.. autoclass:: ConfigDict
- :show-inheritance:
- :members:
- :undoc-members:
-
-.. autoclass:: ConfigList
- :show-inheritance:
- :members:
- :undoc-members:
-
-.. autoclass:: ConfigValue
- :show-inheritance:
- :members:
- :undoc-members:
-
-.. autodecorator:: document_kwargs_from_configdict
-
-.. autofunction:: Bool
-.. autofunction:: Integer
-.. autofunction:: PositiveInt
-.. autofunction:: NegativeInt
-.. autofunction:: NonNegativeInt
-.. autofunction:: NonPositiveInt
-.. autofunction:: PositiveFloat
-.. autofunction:: NegativeFloat
-.. autofunction:: NonPositiveFloat
-.. autofunction:: NonNegativeFloat
-.. autoclass:: In
-.. autoclass:: IsInstance
-.. autoclass:: InEnum
-.. autoclass:: ListOf
-.. autoclass:: Module
-.. autoclass:: Path
-.. autoclass:: PathList
-.. autoclass:: DynamicImplicitDomain
diff --git a/doc/OnlineDocs/library_reference/common/dependencies.rst b/doc/OnlineDocs/library_reference/common/dependencies.rst
deleted file mode 100644
index 18d5647681c..00000000000
--- a/doc/OnlineDocs/library_reference/common/dependencies.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-
-pyomo.common.dependencies
-=========================
-
-.. automodule:: pyomo.common.dependencies
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/deprecation.rst b/doc/OnlineDocs/library_reference/common/deprecation.rst
deleted file mode 100644
index 41066c040c4..00000000000
--- a/doc/OnlineDocs/library_reference/common/deprecation.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-pyomo.common.deprecation
-========================
-
-.. automodule:: pyomo.common.deprecation
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/errors.rst b/doc/OnlineDocs/library_reference/common/errors.rst
deleted file mode 100644
index 7b2bd01fe32..00000000000
--- a/doc/OnlineDocs/library_reference/common/errors.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-pyomo.common.errors
-===================
-
-.. automodule:: pyomo.common.errors
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/fileutils.rst b/doc/OnlineDocs/library_reference/common/fileutils.rst
deleted file mode 100644
index e582f4c2e94..00000000000
--- a/doc/OnlineDocs/library_reference/common/fileutils.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-pyomo.common.fileutils
-======================
-
-.. automodule:: pyomo.common.fileutils
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/formatting.rst b/doc/OnlineDocs/library_reference/common/formatting.rst
deleted file mode 100644
index 25f0ef2404c..00000000000
--- a/doc/OnlineDocs/library_reference/common/formatting.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-pyomo.common.formatting
-=======================
-
-.. automodule:: pyomo.common.formatting
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/index.rst b/doc/OnlineDocs/library_reference/common/index.rst
deleted file mode 100644
index c9c99008250..00000000000
--- a/doc/OnlineDocs/library_reference/common/index.rst
+++ /dev/null
@@ -1,18 +0,0 @@
-Common Utilities
-================
-
-Pyomo provides a set of general-purpose utilities through
-``pyomo.common``. These utilities are self-contained and do not import
-or rely on any other parts of Pyomo.
-
-.. toctree::
- :maxdepth: 1
-
- config.rst
- dependencies.rst
- deprecation.rst
- errors.rst
- fileutils.rst
- formatting.rst
- tempfiles.rst
- timing.rst
diff --git a/doc/OnlineDocs/library_reference/common/tempfiles.rst b/doc/OnlineDocs/library_reference/common/tempfiles.rst
deleted file mode 100644
index 03cb056dffe..00000000000
--- a/doc/OnlineDocs/library_reference/common/tempfiles.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-
-pyomo.common.tempfiles
-======================
-
-.. automodule:: pyomo.common.tempfiles
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/common/timing.rst b/doc/OnlineDocs/library_reference/common/timing.rst
deleted file mode 100644
index 06b6fc0f588..00000000000
--- a/doc/OnlineDocs/library_reference/common/timing.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-
-pyomo.common.timing
-===================
-
-.. automodule:: pyomo.common.timing
- :members:
- :member-order: bysource
diff --git a/doc/OnlineDocs/library_reference/expressions/building.rst b/doc/OnlineDocs/library_reference/expressions/building.rst
deleted file mode 100644
index 8ffcca9e310..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/building.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Utilities to Build Expressions
-==============================
-
-.. autofunction:: pyomo.core.util.prod
-.. autofunction:: pyomo.core.util.quicksum
-.. autofunction:: pyomo.core.util.sum_product
-.. autodata:: pyomo.core.util.summation
-.. autodata:: pyomo.core.util.dot_product
-
diff --git a/doc/OnlineDocs/library_reference/expressions/classes.rst b/doc/OnlineDocs/library_reference/expressions/classes.rst
deleted file mode 100644
index 4d448d2da6a..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/classes.rst
+++ /dev/null
@@ -1,105 +0,0 @@
-Core Classes
-============
-
-The following are the two core classes documented here:
-
- * :class:`NumericValue`
- * :class:`NumericExpression`
-
-The remaining classes are the public classes for expressions, which
-developers may need to know about. The methods for these classes are not
-documented because they are described in the
-:class:`NumericExpression` class.
-
-Sets with Expression Types
---------------------------
-
-The following sets can be used to develop visitor patterns for
-Pyomo expressions.
-
-.. autodata:: pyomo.core.expr.numvalue.native_numeric_types
-.. autodata:: pyomo.core.expr.numvalue.native_types
-.. autodata:: pyomo.core.expr.numvalue.nonpyomo_leaf_types
-
-NumericValue and NumericExpression
-----------------------------------
-
-.. autoclass:: pyomo.core.expr.numvalue.NumericValue
- :members:
- :special-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.NumericExpression
- :members:
- :show-inheritance:
- :special-members:
- :private-members:
-
-Other Public Classes
---------------------
-
-.. autoclass:: pyomo.core.expr.NegationExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.ExternalFunctionExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.ProductExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.DivisionExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.InequalityExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.EqualityExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.SumExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.GetItemExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.Expr_ifExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.UnaryFunctionExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
-
-.. autoclass:: pyomo.core.expr.AbsExpression
- :members:
- :show-inheritance:
- :undoc-members:
- :private-members:
diff --git a/doc/OnlineDocs/library_reference/expressions/context_managers.rst b/doc/OnlineDocs/library_reference/expressions/context_managers.rst
deleted file mode 100644
index ae6884d684f..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/context_managers.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Context Managers
-================
-
-.. autoclass:: pyomo.core.expr.nonlinear_expression
- :members:
-
-.. autoclass:: pyomo.core.expr.linear_expression
- :members:
-
diff --git a/doc/OnlineDocs/library_reference/expressions/managing.rst b/doc/OnlineDocs/library_reference/expressions/managing.rst
deleted file mode 100644
index 369dd3aace1..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/managing.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-
-Utilities to Manage and Analyze Expressions
-===========================================
-
-Functions
-~~~~~~~~~
-
-.. autofunction:: pyomo.core.expr.expression_to_string
-.. autofunction:: pyomo.core.expr.decompose_term
-.. autofunction:: pyomo.core.expr.clone_expression
-.. autofunction:: pyomo.core.expr.evaluate_expression
-.. autofunction:: pyomo.core.expr.identify_components
-.. autofunction:: pyomo.core.expr.identify_variables
-.. autofunction:: pyomo.core.expr.differentiate
-
-Classes
-~~~~~~~
-
-.. autoclass:: pyomo.core.expr.symbol_map.SymbolMap
diff --git a/doc/OnlineDocs/library_reference/expressions/visitors.rst b/doc/OnlineDocs/library_reference/expressions/visitors.rst
deleted file mode 100644
index 77cffe7905f..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/visitors.rst
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Visitor Classes
-===============
-
-.. autoclass:: pyomo.core.expr.StreamBasedExpressionVisitor
- :members:
- :inherited-members:
-
-.. autoclass:: pyomo.core.expr.SimpleExpressionVisitor
- :members:
- :inherited-members:
-
-.. autoclass:: pyomo.core.expr.ExpressionValueVisitor
- :members:
- :inherited-members:
-
-.. autoclass:: pyomo.core.expr.ExpressionReplacementVisitor
- :members:
- :inherited-members:
-
diff --git a/doc/OnlineDocs/library_reference/kernel/base.rst b/doc/OnlineDocs/library_reference/kernel/base.rst
deleted file mode 100644
index 47a2afef68d..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/base.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Base Object Storage Interface
-=============================
-
-.. automodule:: pyomo.core.kernel.base
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/block.rst b/doc/OnlineDocs/library_reference/kernel/block.rst
deleted file mode 100644
index a61c12610eb..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/block.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-Blocks
-======
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.block.block
- pyomo.core.kernel.block.block_tuple
- pyomo.core.kernel.block.block_list
- pyomo.core.kernel.block.block_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.block.block
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.block.block_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.block.block_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.block.block_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/constraint.rst b/doc/OnlineDocs/library_reference/kernel/constraint.rst
deleted file mode 100644
index 1645e57f9f2..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/constraint.rst
+++ /dev/null
@@ -1,34 +0,0 @@
-Constraints
-===========
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.constraint.constraint
- pyomo.core.kernel.constraint.linear_constraint
- pyomo.core.kernel.constraint.constraint_tuple
- pyomo.core.kernel.constraint.constraint_list
- pyomo.core.kernel.constraint.constraint_dict
- pyomo.core.kernel.matrix_constraint.matrix_constraint
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.constraint.constraint
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.constraint.linear_constraint
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.constraint.constraint_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.constraint.constraint_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.constraint.constraint_dict
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.matrix_constraint.matrix_constraint
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/dict_container.rst b/doc/OnlineDocs/library_reference/kernel/dict_container.rst
deleted file mode 100644
index 6e710fa76eb..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/dict_container.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Dict-like Object Storage
-========================
-
-.. autoclass:: pyomo.core.kernel.dict_container.DictContainer
- :show-inheritance:
- :members:
- :inherited-members:
- :special-members:
diff --git a/doc/OnlineDocs/library_reference/kernel/expression.rst b/doc/OnlineDocs/library_reference/kernel/expression.rst
deleted file mode 100644
index b2d4c2d1b35..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/expression.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-Expressions
-===========
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.expression.expression
- pyomo.core.kernel.expression.expression_tuple
- pyomo.core.kernel.expression.expression_list
- pyomo.core.kernel.expression.expression_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.expression.expression
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.expression.expression_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.expression.expression_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.expression.expression_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/heterogeneous_container.rst b/doc/OnlineDocs/library_reference/kernel/heterogeneous_container.rst
deleted file mode 100644
index 74dad1d754e..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/heterogeneous_container.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Heterogeneous Object Containers
-===============================
-
-.. automodule:: pyomo.core.kernel.heterogeneous_container
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/homogeneous_container.rst b/doc/OnlineDocs/library_reference/kernel/homogeneous_container.rst
deleted file mode 100644
index b722e026dc1..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/homogeneous_container.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Homogeneous Object Containers
-=============================
-
-.. automodule:: pyomo.core.kernel.homogeneous_container
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/list_container.rst b/doc/OnlineDocs/library_reference/kernel/list_container.rst
deleted file mode 100644
index b82c6d9c6f0..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/list_container.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-List-like Object Storage
-========================
-
-.. autoclass:: pyomo.core.kernel.list_container.ListContainer
- :show-inheritance:
- :members:
- :inherited-members:
- :special-members:
diff --git a/doc/OnlineDocs/library_reference/kernel/objective.rst b/doc/OnlineDocs/library_reference/kernel/objective.rst
deleted file mode 100644
index 77f26d2f441..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/objective.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-Objectives
-==========
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.objective.objective
- pyomo.core.kernel.objective.objective_tuple
- pyomo.core.kernel.objective.objective_list
- pyomo.core.kernel.objective.objective_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.objective.objective
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.objective.objective_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.objective.objective_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.objective.objective_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/parameter.rst b/doc/OnlineDocs/library_reference/kernel/parameter.rst
deleted file mode 100644
index 212b0cb125e..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/parameter.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-Parameters
-==========
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.parameter.parameter
- pyomo.core.kernel.parameter.functional_value
- pyomo.core.kernel.parameter.parameter_tuple
- pyomo.core.kernel.parameter.parameter_list
- pyomo.core.kernel.parameter.parameter_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.parameter.parameter
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.parameter.functional_value
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.parameter.parameter_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.parameter.parameter_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.parameter.parameter_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise.rst b/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise.rst
deleted file mode 100644
index 25c250d6559..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-Single-variate Piecewise Functions
-==================================
-
-Summary
-~~~~~~~
-.. autosummary::
- pyomo.core.kernel.piecewise_library.transforms.piecewise
- pyomo.core.kernel.piecewise_library.transforms.PiecewiseLinearFunction
- pyomo.core.kernel.piecewise_library.transforms.TransformedPiecewiseLinearFunction
- pyomo.core.kernel.piecewise_library.transforms.piecewise_convex
- pyomo.core.kernel.piecewise_library.transforms.piecewise_sos2
- pyomo.core.kernel.piecewise_library.transforms.piecewise_dcc
- pyomo.core.kernel.piecewise_library.transforms.piecewise_cc
- pyomo.core.kernel.piecewise_library.transforms.piecewise_mc
- pyomo.core.kernel.piecewise_library.transforms.piecewise_inc
- pyomo.core.kernel.piecewise_library.transforms.piecewise_dlog
- pyomo.core.kernel.piecewise_library.transforms.piecewise_log
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autofunction:: pyomo.core.kernel.piecewise_library.transforms.piecewise
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.PiecewiseLinearFunction
- :show-inheritance:
- :special-members: __call__
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.TransformedPiecewiseLinearFunction
- :show-inheritance:
- :special-members: __call__
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_convex
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_sos2
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_dcc
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_cc
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_mc
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_inc
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_dlog
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms.piecewise_log
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise_nd.rst b/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise_nd.rst
deleted file mode 100644
index e5c71a4ec15..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/piecewise/piecewise_nd.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-Multi-variate Piecewise Functions
-=================================
-
-Summary
-~~~~~~~
-.. autosummary::
- pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd
- pyomo.core.kernel.piecewise_library.transforms_nd.PiecewiseLinearFunctionND
- pyomo.core.kernel.piecewise_library.transforms_nd.TransformedPiecewiseLinearFunctionND
- pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd_cc
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autofunction:: pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms_nd.PiecewiseLinearFunctionND
- :show-inheritance:
- :special-members: __call__
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms_nd.TransformedPiecewiseLinearFunctionND
- :show-inheritance:
- :special-members: __call__
- :members:
-.. autoclass:: pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd_cc
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/piecewise/util.rst b/doc/OnlineDocs/library_reference/kernel/piecewise/util.rst
deleted file mode 100644
index 52b7b1de8f7..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/piecewise/util.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Utilities for Piecewise Functions
-=================================
-
-.. automodule:: pyomo.core.kernel.piecewise_library.util
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/sos.rst b/doc/OnlineDocs/library_reference/kernel/sos.rst
deleted file mode 100644
index 0f3f5fedf54..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/sos.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-Special Ordered Sets
-====================
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.sos.sos
- pyomo.core.kernel.sos.sos1
- pyomo.core.kernel.sos.sos2
- pyomo.core.kernel.sos.sos_tuple
- pyomo.core.kernel.sos.sos_list
- pyomo.core.kernel.sos.sos_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.sos.sos
- :show-inheritance:
- :members:
-.. autofunction:: pyomo.core.kernel.sos.sos1
-.. autofunction:: pyomo.core.kernel.sos.sos2
-.. autoclass:: pyomo.core.kernel.sos.sos_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.sos.sos_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.sos.sos_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/suffix.rst b/doc/OnlineDocs/library_reference/kernel/suffix.rst
deleted file mode 100644
index d833f56daa9..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/suffix.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Suffixes
-========
-
-.. automodule:: pyomo.core.kernel.suffix
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/kernel/syntax_comparison.rst b/doc/OnlineDocs/library_reference/kernel/syntax_comparison.rst
deleted file mode 100644
index 71c739214e3..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/syntax_comparison.rst
+++ /dev/null
@@ -1,133 +0,0 @@
-.. _kernel_syntax_comparison:
-
-Syntax Comparison Table (pyomo.kernel vs pyomo.environ)
-=======================================================
-
-.. list-table::
- :header-rows: 1
- :align: center
-
- * -
- - **pyomo.kernel**
- - **pyomo.environ**
-
- * - **Import**
- - .. literalinclude:: examples/kernel_example_Import_Syntax.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Import_Syntax.spy
- :language: python
- * - **Model** [#models_fn]_
- - .. literalinclude:: examples/kernel_example_AbstractModels.spy
- :language: python
- .. literalinclude:: examples/kernel_example_ConcreteModels.spy
- :language: python
- - .. literalinclude:: examples/aml_example_AbstractModels.spy
- :language: python
- .. literalinclude:: examples/aml_example_ConcreteModels.spy
- :language: python
- * - **Set** [#sets_fn]_
- - .. literalinclude:: examples/kernel_example_Sets_1.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Sets_2.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Sets_1.spy
- :language: python
- .. literalinclude:: examples/aml_example_Sets_2.spy
- :language: python
- * - **Parameter** [#parameters_fn]_
- - .. literalinclude:: examples/kernel_example_Parameters_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Parameters_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Parameters_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Parameters_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Parameters_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_Parameters_list.spy
- :language: python
- * - **Variable**
- - .. literalinclude:: examples/kernel_example_Variables_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Variables_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Variables_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Variables_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Variables_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_Variables_list.spy
- :language: python
- * - **Constraint**
- - .. literalinclude:: examples/kernel_example_Constraints_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Constraints_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Constraints_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Constraints_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Constraints_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_Constraints_list.spy
- :language: python
- * - **Expression**
- - .. literalinclude:: examples/kernel_example_Expressions_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Expressions_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Expressions_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Expressions_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Expressions_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_Expressions_list.spy
- :language: python
- * - **Objective**
- - .. literalinclude:: examples/kernel_example_Objectives_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Objectives_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Objectives_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Objectives_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Objectives_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_Objectives_list.spy
- :language: python
- * - **SOS** [#sos_fn]_
- - .. literalinclude:: examples/kernel_example_SOS_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_SOS_dict.spy
- :language: python
- .. literalinclude:: examples/kernel_example_SOS_list.spy
- :language: python
- - .. literalinclude:: examples/aml_example_SOS_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_SOS_dict.spy
- :language: python
- .. literalinclude:: examples/aml_example_SOS_list.spy
- :language: python
- * - **Suffix**
- - .. literalinclude:: examples/kernel_example_Suffix_single.spy
- :language: python
- .. literalinclude:: examples/kernel_example_Suffix_dict.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Suffix_single.spy
- :language: python
- .. literalinclude:: examples/aml_example_Suffix_dict.spy
- :language: python
- * - **Piecewise** [#pw_fn]_
- - .. literalinclude:: examples/kernel_example_Piecewise_1d.spy
- :language: python
- - .. literalinclude:: examples/aml_example_Piecewise_1d.spy
- :language: python
-.. [#models_fn] :python:`pyomo.kernel` does not include an alternative to the :python:`AbstractModel` component from :python:`pyomo.environ`. All data necessary to build a model must be imported by the user.
-.. [#sets_fn] :python:`pyomo.kernel` does not include an alternative to the Pyomo :python:`Set` component from :python:`pyomo.environ`.
-.. [#parameters_fn] :python:`pyomo.kernel.parameter` objects are always mutable.
-.. [#sos_fn] Special Ordered Sets
-.. [#pw_fn] Both :python:`pyomo.kernel.piecewise` and :python:`pyomo.kernel.piecewise_nd` create objects that are sub-classes of :python:`pyomo.kernel.block`. Thus, these objects can be stored in containers such as :python:`pyomo.kernel.block_dict` and :python:`pyomo.kernel.block_list`.
diff --git a/doc/OnlineDocs/library_reference/kernel/tuple_container.rst b/doc/OnlineDocs/library_reference/kernel/tuple_container.rst
deleted file mode 100644
index 8a2798753c4..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/tuple_container.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-Tuple-like Object Storage
-=========================
-
-.. autoclass:: pyomo.core.kernel.tuple_container.TupleContainer
- :show-inheritance:
- :members:
- :inherited-members:
- :special-members:
diff --git a/doc/OnlineDocs/library_reference/kernel/variable.rst b/doc/OnlineDocs/library_reference/kernel/variable.rst
deleted file mode 100644
index f743cee4003..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/variable.rst
+++ /dev/null
@@ -1,26 +0,0 @@
-Variables
-=========
-
-Summary
-~~~~~~~
-.. autosummary::
-
- pyomo.core.kernel.variable.variable
- pyomo.core.kernel.variable.variable_tuple
- pyomo.core.kernel.variable.variable_list
- pyomo.core.kernel.variable.variable_dict
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.variable.variable
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.variable.variable_tuple
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.variable.variable_list
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.variable.variable_dict
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/library_reference/solvers/cplex_persistent.rst b/doc/OnlineDocs/library_reference/solvers/cplex_persistent.rst
deleted file mode 100644
index ee28ecda5e5..00000000000
--- a/doc/OnlineDocs/library_reference/solvers/cplex_persistent.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-CPLEXPersistent
-================
-
-.. autoclass:: pyomo.solvers.plugins.solvers.cplex_persistent.CPLEXPersistent
- :members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/solvers/xpress_persistent.rst b/doc/OnlineDocs/library_reference/solvers/xpress_persistent.rst
deleted file mode 100644
index 2a98b4a09db..00000000000
--- a/doc/OnlineDocs/library_reference/solvers/xpress_persistent.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-XpressPersistent
-================
-
-.. autoclass:: pyomo.solvers.plugins.solvers.xpress_persistent.XpressPersistent
- :members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/make.bat b/doc/OnlineDocs/make.bat
deleted file mode 100644
index 5c7a2549fca..00000000000
--- a/doc/OnlineDocs/make.bat
+++ /dev/null
@@ -1,36 +0,0 @@
-@ECHO OFF
-
-pushd %~dp0
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set SOURCEDIR=.
-set BUILDDIR=_build
-set SPHINXPROJ=pyomocontrib_simplemodel
-
-if "%1" == "" goto help
-
-%SPHINXBUILD% >NUL 2>NUL
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.http://sphinx-doc.org/
- exit /b 1
-)
-
-%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
-goto end
-
-:help
-%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
-
-:end
-popd
diff --git a/doc/OnlineDocs/model_debugging/FAQ.rst b/doc/OnlineDocs/model_debugging/FAQ.rst
deleted file mode 100644
index eef8ad9bd56..00000000000
--- a/doc/OnlineDocs/model_debugging/FAQ.rst
+++ /dev/null
@@ -1,29 +0,0 @@
-FAQ
-===
-
-#. Solver not found
-
-Solvers are **not** distributed with Pyomo and must be installed
-separately by the user. In general, the solver executable must be accessible using a terminal command. For example, ipopt can only be used as a solver if
-the command
-
-::
-
- $ ipopt
-
-invokes the solver. For example
-
-::
-
- $ ipopt -?
- usage: ipopt [options] stub [-AMPL] [ ...]
-
- Options:
- -- {end of options}
- -= {show name= possibilities}
- -? {show usage}
- -bf {read boundsfile f}
- -e {suppress echoing of assignments}
- -of {write .sol file to file f}
- -s {write .sol file (without -AMPL)}
- -v {just show version}
diff --git a/doc/OnlineDocs/model_debugging/getting_help.rst b/doc/OnlineDocs/model_debugging/getting_help.rst
deleted file mode 100644
index acc7c60b29e..00000000000
--- a/doc/OnlineDocs/model_debugging/getting_help.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-Getting Help
-============
-
-See the Pyomo Forum for online discussions of Pyomo or to ask a question:
-
-* http://groups.google.com/group/pyomo-forum/
-
-Ask a question on StackOverflow using the `#pyomo` tag:
-
-* https://stackoverflow.com/questions/ask?tags=pyomo
diff --git a/doc/OnlineDocs/model_debugging/index.rst b/doc/OnlineDocs/model_debugging/index.rst
deleted file mode 100644
index e1dafe45e0a..00000000000
--- a/doc/OnlineDocs/model_debugging/index.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-Debugging Pyomo Models
-======================
-
-.. toctree::
- :maxdepth: 1
-
- model_interrogation.rst
- FAQ.rst
- getting_help.rst
diff --git a/doc/OnlineDocs/model_debugging/model_interrogation.rst b/doc/OnlineDocs/model_debugging/model_interrogation.rst
deleted file mode 100644
index 4e019da88eb..00000000000
--- a/doc/OnlineDocs/model_debugging/model_interrogation.rst
+++ /dev/null
@@ -1,32 +0,0 @@
-Interrogating Pyomo Models
-==========================
-
-.. doctest::
- :hide:
-
- >>> import pyomo.environ as pyo
- >>> from pyomo.opt import SolverFactory
- >>> model = pyo.ConcreteModel()
- >>> model.n = pyo.Param(default=4)
- >>> model.x = pyo.Var(pyo.RangeSet(model.n), within=pyo.Binary)
- >>> def o_rule(model):
- ... return pyo.summation(model.x)
- >>> model.o = pyo.Objective(rule=o_rule)
- >>> model.c = pyo.Constraint(expr=model.x[2] + model.x[3] >= 1)
- >>> r = SolverFactory('glpk').solve(model)
-
-Show solver output by adding the `tee=True` option when calling the
-`solve` function
-
-.. doctest::
-
- >>> SolverFactory('glpk').solve(model, tee=True) # doctest: +SKIP
-
-You can use the `pprint` function to display the model or individual
-model components
-
-.. doctest::
-
- >>> model.pprint() # doctest: +SKIP
- >>> model.x.pprint() # doctest: +SKIP
-
diff --git a/doc/OnlineDocs/modeling_extensions/bilevel.rst b/doc/OnlineDocs/modeling_extensions/bilevel.rst
deleted file mode 100644
index 5e9ee9b0a7c..00000000000
--- a/doc/OnlineDocs/modeling_extensions/bilevel.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Bilevel Programming
-===================
-
-``pyomo.bilevel`` provides extensions supporting modeling of multi-level
-optimization problems.
-
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/index.rst b/doc/OnlineDocs/modeling_extensions/gdp/index.rst
deleted file mode 100644
index 0c8529c60cb..00000000000
--- a/doc/OnlineDocs/modeling_extensions/gdp/index.rst
+++ /dev/null
@@ -1,79 +0,0 @@
-.. _gdp-main-page:
-
-***********************************
-Generalized Disjunctive Programming
-***********************************
-
-.. image:: /../logos/gdp/Pyomo-GDP-150.png
- :scale: 35%
- :align: right
- :class: no-scaled-link
-
-The Pyomo.GDP modeling extension\ [#gdp-main-paper]_ provides support for Generalized Disjunctive Programming (GDP)\ [#gdp]_, an extension of Disjunctive Programming\ [#dp]_ from the operations research community to include nonlinear relationships. The classic form for a GDP is given by:
-
-.. math::
-
- \min\ obj = &\ f(x, z) \\
- \text{s.t.} \quad &\ Ax+Bz \leq d\\
- &\ g(x,z) \leq 0\\
- &\ \bigvee_{i\in D_k} \left[
- \begin{gathered}
- Y_{ik} \\
- M_{ik} x + N_{ik} z \leq e_{ik} \\
- r_{ik}(x,z)\leq 0\\
- \end{gathered}
- \right] \quad k \in K\\
- &\ \Omega(Y) = True \\
- &\ x \in X \subseteq \mathbb{R}^n\\
- &\ Y \in \{True, False\}^{p}\\
- &\ z \in Z \subseteq \mathbb{Z}^m
-
-Here, we have the minimization of an objective :math:`obj` subject to global linear constraints :math:`Ax+Bz \leq d` and nonlinear constraints :math:`g(x,z) \leq 0`, with conditional linear constraints :math:`M_{ik} x + N_{ik} z \leq e_{ik}` and nonlinear constraints :math:`r_{ik}(x,z)\leq 0`.
-These conditional constraints are collected into disjuncts :math:`D_k`, organized into disjunctions :math:`K`. Finally, there are logical propositions :math:`\Omega(Y) = True`.
-Decision/state variables can be continuous :math:`x`, Boolean :math:`Y`, and/or integer :math:`z`.
-
-GDP is useful to model discrete decisions that have implications on the system behavior\ [#gdpreview]_.
-For example, in process design, a disjunction may model the choice between processes A and B.
-If A is selected, then its associated equations and inequalities will apply; otherwise, if B is selected, then its respective constraints should be enforced.
-
-Modelers often ask to model if-then-else relationships.
-These can be expressed as a disjunction as follows:
-
-.. math::
- :nowrap:
-
- \begin{gather*}
- \left[\begin{gathered}
- Y_1 \\
- \text{constraints} \\
- \text{for }\textit{then}
- \end{gathered}\right]
- \vee
- \left[\begin{gathered}
- Y_2 \\
- \text{constraints} \\
- \text{for }\textit{else}
- \end{gathered}\right] \\
- Y_1 \veebar Y_2
- \end{gather*}
-
-Here, if the Boolean :math:`Y_1` is ``True``, then the constraints in the first disjunct are enforced; otherwise, the constraints in the second disjunct are enforced.
-The following sections describe the key concepts, modeling, and solution approaches available for Generalized Disjunctive Programming.
-
-.. toctree::
- :caption: Pyomo.GDP Contents
- :maxdepth: 2
-
- concepts
- modeling
- solving
-
-Literature References
-=====================
-.. [#gdp-main-paper] Chen, Q., Johnson, E. S., Bernal, D. E., Valentin, R., Kale, S., Bates, J., Siirola, J. D. and Grossmann, I. E. (2021). Pyomo.GDP: an ecosystem for logic based modeling and optimization development, *Optimization and Engineering* (pp. 1-36).https://doi.org/10.1007/s11081-021-09601-7
-
-.. [#gdp] Raman, R., & Grossmann, I. E. (1994). Modelling and computational techniques for logic based integer programming. *Computers & Chemical Engineering*, 18(7), 563–578. https://doi.org/10.1016/0098-1354(93)E0010-7
-
-.. [#dp] Balas, E. (1985). Disjunctive Programming and a Hierarchy of Relaxations for Discrete Optimization Problems. *SIAM Journal on Algebraic Discrete Methods*, 6(3), 466–486. https://doi.org/10.1137/0606047
-
-.. [#gdpreview] Grossmann, I. E., & Trespalacios, F. (2013). Systematic modeling of discrete-continuous optimization models through generalized disjunctive programming. *AIChE Journal*, 59(9), 3276–3295. https://doi.org/10.1002/aic.14088
diff --git a/doc/OnlineDocs/modeling_extensions/index.rst b/doc/OnlineDocs/modeling_extensions/index.rst
deleted file mode 100644
index 3a3370e510a..00000000000
--- a/doc/OnlineDocs/modeling_extensions/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-Modeling Extensions
-===================
-
-.. toctree::
- :maxdepth: 1
-
- bilevel.rst
- dae.rst
- gdp/index.rst
- mpec.rst
- stochastic_programming.rst
- network.rst
diff --git a/doc/OnlineDocs/modeling_extensions/stochastic_programming.rst b/doc/OnlineDocs/modeling_extensions/stochastic_programming.rst
deleted file mode 100644
index 227a8d9aa8d..00000000000
--- a/doc/OnlineDocs/modeling_extensions/stochastic_programming.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-Stochastic Programming in Pyomo
-===============================
-
-There are two extensions for modeling and solving Stochastic Programs in
-Pyomo. Both are currently distributed as independent Python packages.
-PySP was the original extension (and up through Pyomo 5.7.3 was
-distributed as part of Pyomo). You can find the documentation here:
-
- `https://pysp.readthedocs.io `_
-
-In 2020, the PySP developers released the mpi-sppy package, which
-reimplemented much of the functionality from PySP in a new scalable
-framework built on top of MPI and the mpi4py package. Future
-development of stochastic programming capabilities is occurring in
-mpi-sppy. The documentation is available here:
-
- `https://mpi-sppy.readthedocs.io `_
diff --git a/doc/OnlineDocs/pyomo_modeling_components/index.rst b/doc/OnlineDocs/pyomo_modeling_components/index.rst
deleted file mode 100644
index c7f455be02c..00000000000
--- a/doc/OnlineDocs/pyomo_modeling_components/index.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-Pyomo Modeling Components
-=========================
-
-.. toctree::
- :maxdepth: 1
-
- Sets.rst
- Parameters.rst
- Variables.rst
- Objectives.rst
- Constraints.rst
- Expressions.rst
- Suffixes.rst
diff --git a/doc/OnlineDocs/reference/bibliography.rst b/doc/OnlineDocs/reference/bibliography.rst
new file mode 100644
index 00000000000..4a4ea37f3e5
--- /dev/null
+++ b/doc/OnlineDocs/reference/bibliography.rst
@@ -0,0 +1,154 @@
+.. _publications:
+
+Publications
+============
+..
+ Note to developers: For these references, we will use the package
+ name followed by a description of the publication type.
+
+These publications describe various Pyomo capabilitites or subpackages:
+
+.. [Pyomo-paper] William E. Hart, Jean-Paul Watson, David L. Woodruff.
+ "Pyomo: modeling and solving mathematical programs in Python,"
+ Mathematical Programming Computation, 3(3), August 2011.
+
+.. [PyomoBookI] William E. Hart, Carl D. Laird, Jean-Paul Watson,
+ David L. Woodruff. Pyomo – Optimization Modeling in Python,
+ Springer Optimization and Its Applications, Vol 67. Springer. 2012.
+
+.. [PyomoBookII] William E. Hart, Carl D. Laird, Jean-Paul Watson,
+ David L. Woodruff, Gabriel A. Hackebeil, Bethany L. Nicholson,
+ John D. Siirola. Pyomo - Optimization Modeling in Python, 2nd Edition.
+ Springer Optimization and Its Applications, Vol 67.
+ Springer. 2017.
+
+.. [PyomoBookIII] Michael L. Bynum, Gabriel A. Hackebeil,
+ William E. Hart, Carl D. Laird, Bethany L. Nicholson,
+ John D. Siirola, Jean-Paul Watson, and David L. Woodruff. Pyomo -
+ Optimization Modeling in Python, 3rd Edition.
+ Vol. 67. Springer. 2021. DOI `10.1007/978-3-030-68928-5
+ `_
+
+.. [PyomoDAE-paper] Bethany Nicholson, John D. Siirola, Jean-Paul Watson,
+ Victor M. Zavala, and Lorenz T. Biegler. "pyomo.dae: a modeling and
+ automatic discretization framework for optimization with differential
+ and algebraic equations", *Mathematical Programming Computation*, 10(2),
+ 187-223. 2018.
+
+.. [Parmest-paper] Katherine A. Klise, Bethany L. Nicholson, Andrea
+ Staid, David L.Woodruff. "Parmest: Parameter Estimation Via Pyomo."
+ *Computer Aided Chemical Engineering*, 47, 41-46. 2019.
+
+.. [PyomoGDP-paper] Qi Chen, Emma S. Johnson, David E. Bernal, Romeo
+ Valentin, Sunjeev Kale, Johnny Bates, John D. Siirola, and
+ Ignacio E. Grossmann. "Pyomo.GDP: an ecosystem for logic based
+ modeling and optimization development." *Optimization and
+ Engineering*, 1-36. 2021. DOI `10.1007/s11081-021-09601-7
+ `_
+
+.. [PyomoGDP-proceedings] Qi Chen, Emma S. Johnson, John D. Siirola, and
+ Ignacio E. Grossmann. "Pyomo.GDP: Disjunctive Models in Python."
+ In M. R. Eden, M. G. Ierapetritou, and G. P. Towler (Eds.),
+ *Proceedings of the 13th International Symposium on Process Systems
+ Engineering*, 889–894, 2018. DOI `10.1016/B978-0-444-64241-7.50143-9
+ `_
+
+
+Bibliography
+============
+
+..
+ Note to developers: We are using BiBTeX's `alpha` format for naming
+ bibliographic references:
+
+ - single Author references use the 1st 3 characters (CamelCase) from
+ the last name plus the two digit publication year (e.g., [Aut00])
+
+ - 2- and 3-author references use the 1st character (capitalized)
+ from each last name plus the two digit publication year (e.g., [HWW11])
+
+ - 4+ author references use the 1st character (capitalized) from the
+ first 3 authors last names, plus a "+", plus the two digit
+ publication year (e.g., [BHH+21])
+
+ Reference collisions are resolved by adding a lower case character
+ (beginning with 'a', ordered in the same order that the references
+ appear in this Bibliography list) to *all* colliding references.
+
+.. [AIMMS] http://www.aimms.com/
+
+.. [AM00] O. Abel and W. Marquardt, "Scenario-integrated modeling and
+ optimization of dynamic systems", *AIChE Journal*, 46(4). 2000.
+
+.. [Bal85] E. Balas. "Disjunctive Programming and a Hierarchy of
+ Relaxations for Discrete Optimization Problems", *SIAM Journal on
+ Algebraic Discrete Methods*, 6(3), 466–486, 1985. DOI
+ `10.1137/0606047 `_
+
+.. [BJ72] E. Balas and R. Jeroslow. "Canonical Cuts on the Unit Hypercube",
+ *SIAM Journal on Applied Mathematics* 23(1), 61-19, 1972.
+ DOI `10.1137/0123007 `_
+
+.. [FGK02] R. Fourer, D. M. Gay, and B. W. Kernighan. *AMPL: A Modeling
+ Language for Mathematical Programming*, 2nd Edition, Duxbury
+ Press, 2002.
+
+.. [GAMS] http://www.gams.com
+
+.. [GLM99] A. Grothey, S. Leyffer, and K. I. M. McKinnon. "A note
+ on feasibility in Benders Decomposition", Numerical Analysis Report
+ NA/188, Dundee University. 1999.
+
+.. [GT13] I. E. Grossmann and F. Trespalacios. "Systematic modeling
+ of discrete-continuous optimization models through generalized
+ disjunctive programming", *AIChE Journal*, 59(9),
+ 3276–3295. 2013. DOI `10.1002/aic.14088 `_
+
+.. [IAE+21] N. M. Isenberg, P. Akula, J. C. Eslick, D. Bhattacharyya,
+ D. C. Miller, and C. E. Gounaris. "A generalized cutting‐set approach
+ for nonlinear robust optimization in process systems engineering",
+ *AIChE Journal*, 67:e17175. 2021. DOI `10.1002/aic.17175
+ `_
+
+.. [KMM+23] B. Knueven, D. Mildebrath, C. Muir, J. D. Siirola,
+ J.-P. Watson, and D. L. Woodruff. "A Parallel Hub-and-Spoke System
+ for Large-Scale Scenario-Based Optimization Under Uncertainty", *Math
+ Programming Computation*, 15, 591-619. 2023. DOI
+ `10.1007/s12532-023-00247-3
+ `_
+
+.. [KMT21] J. Kronqvist, R. Misener, and C. Tsay. "Between Steps:
+ Intermediate Relaxations between big-M and Convex Hull
+ Reformulations". 2021. https://arxiv.org/abs/2101.12708
+
+.. [NW88] G. L. Nemhauser and L. A. Wolsey. *Integer and combinatorial
+ optimization*, New York: Wiley. 1988.
+
+.. [RB01] W. C. Rooney and L. T. Biegler. "Design for model parameter
+ uncertainty using nonlinear confidence regions", *AIChE Journal*,
+ 47(8). 2001.
+
+.. [RG94] R. Raman and I. E. Grossmann. "Modelling and computational
+ techniques for logic based integer programming", *Computers and
+ Chemical Engineering*, 18(7), 563–578. 1994. DOI
+ `10.1016/0098-1354(93)E0010-7
+ `_
+
+.. [SG03] N. W. Sawaya and I. E. Grossmann. "A cutting plane
+ method for solving linear generalized disjunctive programming
+ problems", *Computer Aided Chemical Engineering*, 15(C),
+ 1032–1037. 2003. DOI `10.1016/S1570-7946(03)80444-3
+ `_
+
+.. [TG15] F. Trespalacios and I. E. Grossmann. "Improved Big-M
+ reformulation for generalized disjunctive programs", *Computers and
+ Chemical Engineering*, 76, 98–103. 2015. DOI
+ `10.1016/j.compchemeng.2015.02.013
+ `_
+
+.. [VAN10] J. P. Vielma, S. Ahmed, and G. Nemhauser. "Mixed-Integer
+ Models for Non-separable Piecewise Linear Optimization: Unifying
+ framework and Extensions", *Operations Research* 58(2), 303-315. 2010.
+
+.. [NW99] Nocedal, Jorge, and Stephen J. Wright, eds. Numerical
+ optimization. New York, NY: Springer New York, 1999.
diff --git a/doc/OnlineDocs/reference/future.rst b/doc/OnlineDocs/reference/future.rst
new file mode 100644
index 00000000000..1dd7a1060f3
--- /dev/null
+++ b/doc/OnlineDocs/reference/future.rst
@@ -0,0 +1,5 @@
+Accessing preview features
+==========================
+
+.. automodule:: pyomo.__future__
+ :noindex:
diff --git a/doc/OnlineDocs/reference/index.rst b/doc/OnlineDocs/reference/index.rst
new file mode 100644
index 00000000000..6941c951c8c
--- /dev/null
+++ b/doc/OnlineDocs/reference/index.rst
@@ -0,0 +1,23 @@
+Reference Guides
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ topical/index
+
+.. only:: html
+
+ .. toctree::
+ :maxdepth: 2
+
+ Library Reference <../api/pyomo>
+
+.. toctree::
+ :maxdepth: 1
+
+ future
+ ../errors
+ ../related_packages
+ bibliography
+
diff --git a/doc/OnlineDocs/reference/topical/aml/index.rst b/doc/OnlineDocs/reference/topical/aml/index.rst
new file mode 100644
index 00000000000..bdc3c5529d0
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/aml/index.rst
@@ -0,0 +1,22 @@
+AML Library Reference
+=====================
+
+The following modeling components make up the core of the Pyomo
+Algebraic Modeling Language (AML). These classes are all available
+through the :mod:`pyomo.environ` namespace.
+
+.. autosummary::
+
+ ~pyomo.core.base.PyomoModel.ConcreteModel
+ ~pyomo.core.base.PyomoModel.AbstractModel
+ ~pyomo.core.base.block.Block
+ ~pyomo.core.base.set.Set
+ ~pyomo.core.base.set.RangeSet
+ ~pyomo.core.base.param.Param
+ ~pyomo.core.base.var.Var
+ ~pyomo.core.base.objective.Objective
+ ~pyomo.core.base.constraint.Constraint
+ ~pyomo.core.base.external.ExternalFunction
+ ~pyomo.core.base.reference.Reference
+ ~pyomo.core.base.sos.SOSConstraint
+
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.base.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.base.rst
new file mode 100644
index 00000000000..c99d86350b7
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.base.rst
@@ -0,0 +1,12 @@
+APPSI Base Classes
+==================
+
+.. autosummary::
+
+ pyomo.contrib.appsi.base.TerminationCondition
+ pyomo.contrib.appsi.base.Results
+ pyomo.contrib.appsi.base.Solver
+ pyomo.contrib.appsi.base.PersistentSolver
+ pyomo.contrib.appsi.base.SolverConfig
+ pyomo.contrib.appsi.base.MIPSolverConfig
+ pyomo.contrib.appsi.base.UpdateConfig
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.rst
similarity index 81%
rename from doc/OnlineDocs/library_reference/appsi/appsi.rst
rename to doc/OnlineDocs/reference/topical/appsi/appsi.rst
index e26e4b0e82a..797c37040d2 100644
--- a/doc/OnlineDocs/library_reference/appsi/appsi.rst
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.rst
@@ -6,6 +6,7 @@ APPSI
Auto-Persistent Pyomo Solver Interfaces
.. automodule:: pyomo.contrib.appsi
+ :noindex:
:members:
:show-inheritance:
@@ -23,17 +24,17 @@ example of using an APPSI solver interface.
.. code-block:: python
- >>> import pyomo.environ as pe
+ >>> import pyomo.environ as pyo
>>> from pyomo.contrib import appsi
>>> import numpy as np
>>> from pyomo.common.timing import HierarchicalTimer
- >>> m = pe.ConcreteModel()
- >>> m.x = pe.Var()
- >>> m.y = pe.Var()
- >>> m.p = pe.Param(mutable=True)
- >>> m.obj = pe.Objective(expr=m.x**2 + m.y**2)
- >>> m.c1 = pe.Constraint(expr=m.y >= pe.exp(m.x))
- >>> m.c2 = pe.Constraint(expr=m.y >= (m.x - m.p)**2)
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.y = pyo.Var()
+ >>> m.p = pyo.Param(mutable=True)
+ >>> m.obj = pyo.Objective(expr=m.x**2 + m.y**2)
+ >>> m.c1 = pyo.Constraint(expr=m.y >= pyo.exp(m.x))
+ >>> m.c2 = pyo.Constraint(expr=m.y >= (m.x - m.p)**2)
>>> opt = appsi.solvers.Ipopt()
>>> timer = HierarchicalTimer()
>>> for p_val in np.linspace(1, 10, 100):
@@ -43,6 +44,15 @@ example of using an APPSI solver interface.
>>> print(res.best_feasible_objective)
>>> print(timer)
+Alternatively, you can access the APPSI solvers through the classic
+``SolverFactory`` using the pattern ``appsi_solvername``.
+
+.. code-block:: python
+
+ >>> import pyomo.environ as pyo
+ >>> opt_ipopt = pyo.SolverFactory('appsi_ipopt')
+ >>> opt_highs = pyo.SolverFactory('appsi_highs')
+
Extra performance improvements can be made if you know exactly what
changes will be made in your model. In the example above, only
parameter values are changed, so we can setup the
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cbc.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cbc.rst
new file mode 100644
index 00000000000..6f3c3bb98d1
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cbc.rst
@@ -0,0 +1,7 @@
+Cbc
+===
+
+.. autosummary::
+
+ pyomo.contrib.appsi.solvers.cbc.CbcConfig
+ pyomo.contrib.appsi.solvers.cbc.Cbc
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cplex.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cplex.rst
new file mode 100644
index 00000000000..9d64260cb81
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.cplex.rst
@@ -0,0 +1,8 @@
+Cplex
+=====
+
+.. autosummary::
+
+ `pyomo.contrib.appsi.solvers.cplex.CplexConfig`
+ `pyomo.contrib.appsi.solvers.cplex.CplexResults`
+ `pyomo.contrib.appsi.solvers.cplex.Cplex`
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.gurobi.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.gurobi.rst
similarity index 87%
rename from doc/OnlineDocs/library_reference/appsi/appsi.solvers.gurobi.rst
rename to doc/OnlineDocs/reference/topical/appsi/appsi.solvers.gurobi.rst
index 9e0af041410..09cad20bbfa 100644
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.gurobi.rst
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.gurobi.rst
@@ -42,14 +42,7 @@ calls to
to unexpected errors.
-.. autoclass:: pyomo.contrib.appsi.solvers.gurobi.GurobiResults
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
-
-.. autoclass:: pyomo.contrib.appsi.solvers.gurobi.Gurobi
- :members:
- :inherited-members:
- :undoc-members:
- :show-inheritance:
+.. autosummary::
+
+ pyomo.contrib.appsi.solvers.gurobi.GurobiResults
+ pyomo.contrib.appsi.solvers.gurobi.Gurobi
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.highs.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.highs.rst
new file mode 100644
index 00000000000..dbd804664ef
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.highs.rst
@@ -0,0 +1,7 @@
+HiGHS
+=====
+
+.. autosummary::
+
+ pyomo.contrib.appsi.solvers.highs.HighsResults
+ pyomo.contrib.appsi.solvers.highs.Highs
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.ipopt.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.ipopt.rst
new file mode 100644
index 00000000000..0b48bbffb5f
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.ipopt.rst
@@ -0,0 +1,7 @@
+Ipopt
+=====
+
+.. autosummary::
+
+ pyomo.contrib.appsi.solvers.ipopt.IpoptConfig
+ pyomo.contrib.appsi.solvers.ipopt.Ipopt
diff --git a/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.maingo.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.maingo.rst
new file mode 100644
index 00000000000..fa85fd45ad5
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.maingo.rst
@@ -0,0 +1,7 @@
+MAiNGO
+======
+
+.. autosummary::
+
+ pyomo.contrib.appsi.solvers.maingo.MAiNGOConfig
+ pyomo.contrib.appsi.solvers.maingo.MAiNGO
diff --git a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.rst b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.rst
similarity index 76%
rename from doc/OnlineDocs/library_reference/appsi/appsi.solvers.rst
rename to doc/OnlineDocs/reference/topical/appsi/appsi.solvers.rst
index 1c598d95628..275e6cb4f74 100644
--- a/doc/OnlineDocs/library_reference/appsi/appsi.solvers.rst
+++ b/doc/OnlineDocs/reference/topical/appsi/appsi.solvers.rst
@@ -2,9 +2,7 @@ Solvers
=======
.. automodule:: pyomo.contrib.appsi.solvers
- :members:
- :show-inheritance:
- :undoc-members:
+ :noindex:
.. toctree::
@@ -13,3 +11,4 @@ Solvers
appsi.solvers.cplex
appsi.solvers.cbc
appsi.solvers.highs
+ appsi.solvers.maingo
diff --git a/doc/OnlineDocs/library_reference/data/index.rst b/doc/OnlineDocs/reference/topical/data/index.rst
similarity index 89%
rename from doc/OnlineDocs/library_reference/data/index.rst
rename to doc/OnlineDocs/reference/topical/data/index.rst
index fffb06240f8..778f797fa57 100644
--- a/doc/OnlineDocs/library_reference/data/index.rst
+++ b/doc/OnlineDocs/reference/topical/data/index.rst
@@ -2,10 +2,12 @@ Model Data Management
=====================
.. autoclass:: pyomo.dataportal.DataPortal.DataPortal
+ :noindex:
:members:
:special-members:
.. autoclass:: pyomo.dataportal.TableData.TableData
+ :noindex:
:members:
:special-members:
diff --git a/doc/OnlineDocs/reference/topical/expressions/building.rst b/doc/OnlineDocs/reference/topical/expressions/building.rst
new file mode 100644
index 00000000000..8335116e21f
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/expressions/building.rst
@@ -0,0 +1,12 @@
+
+Utilities to Build Expressions
+==============================
+
+.. autosummary::
+
+ pyomo.core.util.prod
+ pyomo.core.util.quicksum
+ pyomo.core.util.sum_product
+ pyomo.core.util.summation
+ pyomo.core.util.dot_product
+
diff --git a/doc/OnlineDocs/reference/topical/expressions/classes.rst b/doc/OnlineDocs/reference/topical/expressions/classes.rst
new file mode 100644
index 00000000000..786651be2a6
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/expressions/classes.rst
@@ -0,0 +1,53 @@
+Core Classes
+============
+
+.. currentmodule:: pyomo.core.expr.numeric_expr
+
+The following are the two core classes documented here:
+
+ * :class:`NumericValue`
+ * :class:`NumericExpression`
+
+The remaining classes are the public classes for expressions, which
+developers may need to know about. The methods for these classes are not
+documented because they are described in the
+:class:`NumericExpression` class.
+
+Sets with Expression Types
+--------------------------
+
+The following sets can be used to develop visitor patterns for
+Pyomo expressions.
+
+.. autosummary::
+
+ ~pyomo.common.numeric_types.native_numeric_types
+ ~pyomo.common.numeric_types.native_types
+ ~pyomo.common.numeric_types.nonpyomo_leaf_types
+
+NumericValue and NumericExpression
+----------------------------------
+
+.. autosummary::
+
+ NumericValue
+ NumericExpression
+
+Other Public Classes
+--------------------
+
+
+.. autosummary::
+
+ NegationExpression
+ AbsExpression
+ UnaryFunctionExpression
+ ProductExpression
+ DivisionExpression
+ SumExpression
+ Expr_ifExpression
+ ExternalFunctionExpression
+ pyomo.core.expr.relational_expr.EqualityExpression
+ pyomo.core.expr.relational_expr.InequalityExpression
+ pyomo.core.expr.relational_expr.RangedExpression
+ pyomo.core.expr.template_expr.GetItemExpression
diff --git a/doc/OnlineDocs/reference/topical/expressions/context_managers.rst b/doc/OnlineDocs/reference/topical/expressions/context_managers.rst
new file mode 100644
index 00000000000..e77a4933a01
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/expressions/context_managers.rst
@@ -0,0 +1,9 @@
+
+Context Managers
+================
+
+.. autosummary::
+
+ pyomo.core.expr.nonlinear_expression
+ pyomo.core.expr.linear_expression
+
diff --git a/doc/OnlineDocs/library_reference/expressions/index.rst b/doc/OnlineDocs/reference/topical/expressions/index.rst
similarity index 100%
rename from doc/OnlineDocs/library_reference/expressions/index.rst
rename to doc/OnlineDocs/reference/topical/expressions/index.rst
diff --git a/doc/OnlineDocs/reference/topical/expressions/managing.rst b/doc/OnlineDocs/reference/topical/expressions/managing.rst
new file mode 100644
index 00000000000..ba96f2a2907
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/expressions/managing.rst
@@ -0,0 +1,23 @@
+
+Utilities to Manage and Analyze Expressions
+===========================================
+
+Functions
+~~~~~~~~~
+
+.. autosummary::
+
+ pyomo.core.expr.expression_to_string
+ pyomo.core.expr.decompose_term
+ pyomo.core.expr.clone_expression
+ pyomo.core.expr.evaluate_expression
+ pyomo.core.expr.identify_components
+ pyomo.core.expr.identify_variables
+ pyomo.core.expr.differentiate
+
+Classes
+~~~~~~~
+
+.. autosummary::
+
+ pyomo.core.expr.symbol_map.SymbolMap
diff --git a/doc/OnlineDocs/reference/topical/expressions/visitors.rst b/doc/OnlineDocs/reference/topical/expressions/visitors.rst
new file mode 100644
index 00000000000..ef09c62c2ff
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/expressions/visitors.rst
@@ -0,0 +1,9 @@
+
+Visitor Classes
+===============
+
+.. autosummary::
+
+ pyomo.core.expr.StreamBasedExpressionVisitor
+ pyomo.core.expr.ExpressionValueVisitor
+ pyomo.core.expr.ExpressionReplacementVisitor
diff --git a/doc/OnlineDocs/library_reference/index.rst b/doc/OnlineDocs/reference/topical/index.rst
similarity index 94%
rename from doc/OnlineDocs/library_reference/index.rst
rename to doc/OnlineDocs/reference/topical/index.rst
index 35dd8d30307..919b68f647a 100644
--- a/doc/OnlineDocs/library_reference/index.rst
+++ b/doc/OnlineDocs/reference/topical/index.rst
@@ -1,4 +1,4 @@
-Library Reference
+Topical Reference
=================
Pyomo is being increasingly used as a library to support Python
@@ -10,7 +10,6 @@ Python scripts using Pyomo.
.. toctree::
:maxdepth: 1
- common/index.rst
aml/index.rst
expressions/index.rst
solvers/index.rst
diff --git a/doc/OnlineDocs/reference/topical/kernel/base.rst b/doc/OnlineDocs/reference/topical/kernel/base.rst
new file mode 100644
index 00000000000..884d40a47c2
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/base.rst
@@ -0,0 +1,6 @@
+Base Object Storage Interface
+=============================
+
+.. autosummary::
+
+ pyomo.core.kernel.base
diff --git a/doc/OnlineDocs/reference/topical/kernel/block.rst b/doc/OnlineDocs/reference/topical/kernel/block.rst
new file mode 100644
index 00000000000..0fae770c355
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/block.rst
@@ -0,0 +1,12 @@
+Blocks
+======
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.block.block
+ pyomo.core.kernel.block.block_tuple
+ pyomo.core.kernel.block.block_list
+ pyomo.core.kernel.block.block_dict
+
diff --git a/doc/OnlineDocs/library_reference/kernel/conic.rst b/doc/OnlineDocs/reference/topical/kernel/conic.rst
similarity index 54%
rename from doc/OnlineDocs/library_reference/kernel/conic.rst
rename to doc/OnlineDocs/reference/topical/kernel/conic.rst
index 34552013623..98bc474aee5 100644
--- a/doc/OnlineDocs/library_reference/kernel/conic.rst
+++ b/doc/OnlineDocs/reference/topical/kernel/conic.rst
@@ -19,24 +19,3 @@ Summary
pyomo.core.kernel.conic.primal_power
pyomo.core.kernel.conic.dual_exponential
pyomo.core.kernel.conic.dual_power
-
-Member Documentation
-~~~~~~~~~~~~~~~~~~~~
-.. autoclass:: pyomo.core.kernel.conic.quadratic
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.conic.rotated_quadratic
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.conic.primal_exponential
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.conic.primal_power
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.conic.dual_exponential
- :show-inheritance:
- :members:
-.. autoclass:: pyomo.core.kernel.conic.dual_power
- :show-inheritance:
- :members:
diff --git a/doc/OnlineDocs/reference/topical/kernel/constraint.rst b/doc/OnlineDocs/reference/topical/kernel/constraint.rst
new file mode 100644
index 00000000000..a4422bfb61d
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/constraint.rst
@@ -0,0 +1,13 @@
+Constraints
+===========
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.constraint.constraint
+ pyomo.core.kernel.constraint.linear_constraint
+ pyomo.core.kernel.constraint.constraint_tuple
+ pyomo.core.kernel.constraint.constraint_list
+ pyomo.core.kernel.constraint.constraint_dict
+ pyomo.core.kernel.matrix_constraint.matrix_constraint
diff --git a/doc/OnlineDocs/reference/topical/kernel/dict_container.rst b/doc/OnlineDocs/reference/topical/kernel/dict_container.rst
new file mode 100644
index 00000000000..923fe915b8e
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/dict_container.rst
@@ -0,0 +1,6 @@
+Dict-like Object Storage
+========================
+
+.. autosummary::
+
+ pyomo.core.kernel.dict_container.DictContainer
diff --git a/doc/OnlineDocs/reference/topical/kernel/expression.rst b/doc/OnlineDocs/reference/topical/kernel/expression.rst
new file mode 100644
index 00000000000..6ac32ecd7dd
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/expression.rst
@@ -0,0 +1,11 @@
+Expressions
+===========
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.expression.expression
+ pyomo.core.kernel.expression.expression_tuple
+ pyomo.core.kernel.expression.expression_list
+ pyomo.core.kernel.expression.expression_dict
diff --git a/doc/OnlineDocs/reference/topical/kernel/heterogeneous_container.rst b/doc/OnlineDocs/reference/topical/kernel/heterogeneous_container.rst
new file mode 100644
index 00000000000..158175af7f1
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/heterogeneous_container.rst
@@ -0,0 +1,6 @@
+Heterogeneous Object Containers
+===============================
+
+.. autosummary::
+
+ pyomo.core.kernel.heterogeneous_container
diff --git a/doc/OnlineDocs/reference/topical/kernel/homogeneous_container.rst b/doc/OnlineDocs/reference/topical/kernel/homogeneous_container.rst
new file mode 100644
index 00000000000..f6dc88b355a
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/homogeneous_container.rst
@@ -0,0 +1,6 @@
+Homogeneous Object Containers
+=============================
+
+.. autosummary::
+
+ pyomo.core.kernel.homogeneous_container
diff --git a/doc/OnlineDocs/reference/topical/kernel/index.rst b/doc/OnlineDocs/reference/topical/kernel/index.rst
new file mode 100644
index 00000000000..03df24215a8
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/index.rst
@@ -0,0 +1,52 @@
+.. role:: python(code)
+ :language: python
+
+.. warning::
+
+ The :python:`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 :python:`pyomo.kernel` components are not yet compatible with pyomo extension modules (e.g., :python:`PySP`, :python:`pyomo.dae`, :python:`pyomo.gdp`).
+
+The Kernel Library API Reference
+================================
+
+.. _kernel_modeling_components:
+
+Modeling Components:
+^^^^^^^^^^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ block.rst
+ variable.rst
+ constraint.rst
+ parameter.rst
+ objective.rst
+ expression.rst
+ sos.rst
+ suffix.rst
+ piecewise/index.rst
+ conic.rst
+
+Base API:
+^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ base.rst
+ homogeneous_container.rst
+ heterogeneous_container.rst
+
+Containers:
+^^^^^^^^^^^
+
+.. toctree::
+ :maxdepth: 1
+
+ tuple_container.rst
+ list_container.rst
+ dict_container.rst
diff --git a/doc/OnlineDocs/reference/topical/kernel/list_container.rst b/doc/OnlineDocs/reference/topical/kernel/list_container.rst
new file mode 100644
index 00000000000..acd6fe4fabb
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/list_container.rst
@@ -0,0 +1,6 @@
+List-like Object Storage
+========================
+
+.. autosummary::
+
+ pyomo.core.kernel.list_container.ListContainer
diff --git a/doc/OnlineDocs/reference/topical/kernel/objective.rst b/doc/OnlineDocs/reference/topical/kernel/objective.rst
new file mode 100644
index 00000000000..8f7a5422e9e
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/objective.rst
@@ -0,0 +1,11 @@
+Objectives
+==========
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.objective.objective
+ pyomo.core.kernel.objective.objective_tuple
+ pyomo.core.kernel.objective.objective_list
+ pyomo.core.kernel.objective.objective_dict
diff --git a/doc/OnlineDocs/reference/topical/kernel/parameter.rst b/doc/OnlineDocs/reference/topical/kernel/parameter.rst
new file mode 100644
index 00000000000..c09bd6262c3
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/parameter.rst
@@ -0,0 +1,12 @@
+Parameters
+==========
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.parameter.parameter
+ pyomo.core.kernel.parameter.functional_value
+ pyomo.core.kernel.parameter.parameter_tuple
+ pyomo.core.kernel.parameter.parameter_list
+ pyomo.core.kernel.parameter.parameter_dict
diff --git a/doc/OnlineDocs/library_reference/kernel/piecewise/index.rst b/doc/OnlineDocs/reference/topical/kernel/piecewise/index.rst
similarity index 100%
rename from doc/OnlineDocs/library_reference/kernel/piecewise/index.rst
rename to doc/OnlineDocs/reference/topical/kernel/piecewise/index.rst
diff --git a/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise.rst b/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise.rst
new file mode 100644
index 00000000000..4c67621426c
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise.rst
@@ -0,0 +1,19 @@
+Single-variate Piecewise Functions
+==================================
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.piecewise_library.transforms.piecewise
+ pyomo.core.kernel.piecewise_library.transforms.PiecewiseLinearFunction
+ pyomo.core.kernel.piecewise_library.transforms.TransformedPiecewiseLinearFunction
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_convex
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_sos2
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_dcc
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_cc
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_mc
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_inc
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_dlog
+ pyomo.core.kernel.piecewise_library.transforms.piecewise_log
+
diff --git a/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise_nd.rst b/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise_nd.rst
new file mode 100644
index 00000000000..057f3590a72
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/piecewise/piecewise_nd.rst
@@ -0,0 +1,12 @@
+Multi-variate Piecewise Functions
+=================================
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd
+ pyomo.core.kernel.piecewise_library.transforms_nd.PiecewiseLinearFunctionND
+ pyomo.core.kernel.piecewise_library.transforms_nd.TransformedPiecewiseLinearFunctionND
+ pyomo.core.kernel.piecewise_library.transforms_nd.piecewise_nd_cc
+
diff --git a/doc/OnlineDocs/reference/topical/kernel/piecewise/util.rst b/doc/OnlineDocs/reference/topical/kernel/piecewise/util.rst
new file mode 100644
index 00000000000..6b979ff42ff
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/piecewise/util.rst
@@ -0,0 +1,6 @@
+Utilities for Piecewise Functions
+=================================
+
+.. autosummary::
+
+ pyomo.core.kernel.piecewise_library.util
diff --git a/doc/OnlineDocs/reference/topical/kernel/sos.rst b/doc/OnlineDocs/reference/topical/kernel/sos.rst
new file mode 100644
index 00000000000..edb463ea1da
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/sos.rst
@@ -0,0 +1,14 @@
+Special Ordered Sets
+====================
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.sos.sos
+ pyomo.core.kernel.sos.sos1
+ pyomo.core.kernel.sos.sos2
+ pyomo.core.kernel.sos.sos_tuple
+ pyomo.core.kernel.sos.sos_list
+ pyomo.core.kernel.sos.sos_dict
+
diff --git a/doc/OnlineDocs/reference/topical/kernel/suffix.rst b/doc/OnlineDocs/reference/topical/kernel/suffix.rst
new file mode 100644
index 00000000000..f0f8f48a292
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/suffix.rst
@@ -0,0 +1,6 @@
+Suffixes
+========
+
+.. autosummary::
+
+ pyomo.core.kernel.suffix
diff --git a/doc/OnlineDocs/reference/topical/kernel/tuple_container.rst b/doc/OnlineDocs/reference/topical/kernel/tuple_container.rst
new file mode 100644
index 00000000000..eb052d9ffb6
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/tuple_container.rst
@@ -0,0 +1,6 @@
+Tuple-like Object Storage
+=========================
+
+.. autosummary::
+
+ pyomo.core.kernel.tuple_container.TupleContainer
diff --git a/doc/OnlineDocs/reference/topical/kernel/variable.rst b/doc/OnlineDocs/reference/topical/kernel/variable.rst
new file mode 100644
index 00000000000..937ebae45dc
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/kernel/variable.rst
@@ -0,0 +1,11 @@
+Variables
+=========
+
+Summary
+~~~~~~~
+.. autosummary::
+
+ pyomo.core.kernel.variable.variable
+ pyomo.core.kernel.variable.variable_tuple
+ pyomo.core.kernel.variable.variable_list
+ pyomo.core.kernel.variable.variable_dict
diff --git a/doc/OnlineDocs/reference/topical/solvers/cplex_persistent.rst b/doc/OnlineDocs/reference/topical/solvers/cplex_persistent.rst
new file mode 100644
index 00000000000..e0d34d0f51d
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/solvers/cplex_persistent.rst
@@ -0,0 +1,6 @@
+CPLEXPersistent
+================
+
+.. autosummary::
+
+ pyomo.solvers.plugins.solvers.cplex_persistent.CPLEXPersistent
diff --git a/doc/OnlineDocs/library_reference/solvers/gams.rst b/doc/OnlineDocs/reference/topical/solvers/gams.rst
similarity index 82%
rename from doc/OnlineDocs/library_reference/solvers/gams.rst
rename to doc/OnlineDocs/reference/topical/solvers/gams.rst
index f36de5d9e01..ca9a2a55d09 100644
--- a/doc/OnlineDocs/library_reference/solvers/gams.rst
+++ b/doc/OnlineDocs/reference/topical/solvers/gams.rst
@@ -8,28 +8,24 @@ GAMSShell Solver
.. autosummary::
+ GAMSShell
GAMSShell.available
GAMSShell.executable
GAMSShell.solve
GAMSShell.version
GAMSShell.warm_start_capable
-.. autoclass:: GAMSShell
- :members:
-
GAMSDirect Solver
-----------------
.. autosummary::
+ GAMSDirect
GAMSDirect.available
GAMSDirect.solve
GAMSDirect.version
GAMSDirect.warm_start_capable
-.. autoclass:: GAMSDirect
- :members:
-
.. currentmodule:: pyomo.repn.plugins.gams_writer
GAMS Writer
@@ -39,5 +35,6 @@ This class is most commonly accessed and called upon via
model.write("filename.gms", ...), but is also utilized
by the GAMS solver interfaces.
-.. autoclass:: ProblemWriter_gams
- :members: __call__
+.. autosummary::
+
+ ProblemWriter_gams
diff --git a/doc/OnlineDocs/library_reference/solvers/gurobi_direct.rst b/doc/OnlineDocs/reference/topical/solvers/gurobi_direct.rst
similarity index 73%
rename from doc/OnlineDocs/library_reference/solvers/gurobi_direct.rst
rename to doc/OnlineDocs/reference/topical/solvers/gurobi_direct.rst
index 21cb79e5531..bbb61143a94 100644
--- a/doc/OnlineDocs/library_reference/solvers/gurobi_direct.rst
+++ b/doc/OnlineDocs/reference/topical/solvers/gurobi_direct.rst
@@ -3,6 +3,14 @@ GurobiDirect
.. currentmodule:: pyomo.solvers.plugins.solvers.gurobi_direct
+
+Interface
+---------
+
+.. autosummary::
+
+ GurobiDirect
+
Methods
-------
@@ -14,5 +22,3 @@ Methods
GurobiDirect.solve
GurobiDirect.version
-.. autoclass:: GurobiDirect
- :members: available, close, close_global, solve, version
diff --git a/doc/OnlineDocs/library_reference/solvers/gurobi_persistent.rst b/doc/OnlineDocs/reference/topical/solvers/gurobi_persistent.rst
similarity index 91%
rename from doc/OnlineDocs/library_reference/solvers/gurobi_persistent.rst
rename to doc/OnlineDocs/reference/topical/solvers/gurobi_persistent.rst
index 2472599c1ed..5832c8f8b9f 100644
--- a/doc/OnlineDocs/library_reference/solvers/gurobi_persistent.rst
+++ b/doc/OnlineDocs/reference/topical/solvers/gurobi_persistent.rst
@@ -3,6 +3,13 @@ GurobiPersistent
.. currentmodule:: pyomo.solvers.plugins.solvers.gurobi_persistent
+Interface
+---------
+
+.. autosummary::
+
+ GurobiPersistent
+
Methods
-------
@@ -32,8 +39,3 @@ Methods
GurobiPersistent.update_var
GurobiPersistent.version
GurobiPersistent.write
-
-.. autoclass:: GurobiPersistent
- :members:
- :inherited-members:
- :show-inheritance:
diff --git a/doc/OnlineDocs/library_reference/solvers/index.rst b/doc/OnlineDocs/reference/topical/solvers/index.rst
similarity index 100%
rename from doc/OnlineDocs/library_reference/solvers/index.rst
rename to doc/OnlineDocs/reference/topical/solvers/index.rst
diff --git a/doc/OnlineDocs/reference/topical/solvers/xpress_persistent.rst b/doc/OnlineDocs/reference/topical/solvers/xpress_persistent.rst
new file mode 100644
index 00000000000..d8721a0931a
--- /dev/null
+++ b/doc/OnlineDocs/reference/topical/solvers/xpress_persistent.rst
@@ -0,0 +1,6 @@
+XpressPersistent
+================
+
+.. autosummary::
+
+ pyomo.solvers.plugins.solvers.xpress_persistent.XpressPersistent
diff --git a/doc/OnlineDocs/related_packages.rst b/doc/OnlineDocs/related_packages.rst
index 1861b98ba6e..f32c726e9d6 100644
--- a/doc/OnlineDocs/related_packages.rst
+++ b/doc/OnlineDocs/related_packages.rst
@@ -16,6 +16,9 @@ Modeling Extensions
| PAO | https://github.com/or-fusion/pao | Formulation and solution of multilevel |
| | | optimization problems |
+--------------------------+---------------------------------------------------------+---------------------------------------------+
+| OMLT | https://github.com/cog-imperial/OMLT | Represent machine learning models within |
+| | | an optimization formulation |
++--------------------------+---------------------------------------------------------+---------------------------------------------+
Solvers and Solution Strategies
diff --git a/doc/OnlineDocs/solving_pyomo_models.rst b/doc/OnlineDocs/solving_pyomo_models.rst
deleted file mode 100644
index e95c74b2cee..00000000000
--- a/doc/OnlineDocs/solving_pyomo_models.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-Solving Pyomo Models
-====================
-
-.. doctest::
- :hide:
-
- >>> import pyomo.environ as pyo
-
- >>> m = pyo.AbstractModel()
- >>> m.n = pyo.Param(default=4)
- >>> m.x = pyo.Var(pyo.RangeSet(m.n), within=pyo.Binary)
- >>> def o_rule(m):
- ... return pyo.summation(m.x)
- >>> m.o = pyo.Objective(rule=o_rule)
-
- >>> model = m.create_instance()
- >>> model.c = pyo.Constraint(expr=model.x[2]+model.x[3]>=1)
-
-
-Solving ConcreteModels
-----------------------
-
-If you have a ConcreteModel, add these lines at the bottom of your
-Python script to solve it
-
-.. doctest::
-
- >>> opt = pyo.SolverFactory('glpk')
- >>> opt.solve(model) # doctest: +SKIP
-
-Solving AbstractModels
-----------------------
-
-If you have an AbstractModel, you must create a concrete instance of
-your model before solving it using the same lines as above:
-
-.. doctest::
- :hide:
-
- >>> model = m
-
-.. doctest::
-
- >>> instance = model.create_instance()
- >>> opt = pyo.SolverFactory('glpk')
- >>> opt.solve(instance) # doctest: +SKIP
-
-``pyomo solve`` Command
------------------------
-
-To solve a ConcreteModel contained in the file ``my_model.py`` using the
-``pyomo`` command and the solver GLPK, use the following line in a
-terminal window::
-
- pyomo solve my_model.py --solver='glpk'
-
-To solve an AbstractModel contained in the file ``my_model.py`` with data
-in the file ``my_data.dat`` using the ``pyomo`` command and the solver GLPK,
-use the following line in a terminal window::
-
- pyomo solve my_model.py my_data.dat --solver='glpk'
-
-Supported Solvers
------------------
-
-Pyomo supports a wide variety of solvers. Pyomo has specialized
-interfaces to some solvers (for example, BARON, CBC, CPLEX, and Gurobi).
-It also has generic interfaces that support calling any solver that can
-read AMPL "``.nl``" and write "``.sol``" files and the ability to
-generate GAMS-format models and retrieve the results. You can get the
-current list of supported solvers using the ``pyomo`` command::
-
- pyomo help --solvers
diff --git a/doc/OnlineDocs/src/data/ABCD1.py b/doc/OnlineDocs/src/data/ABCD1.py
index aa2f46e71fa..35ad3abc670 100644
--- a/doc/OnlineDocs/src/data/ABCD1.py
+++ b/doc/OnlineDocs/src/data/ABCD1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,11 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=4)
+model.Z = pyo.Set(dimen=4)
instance = model.create_instance('ABCD1.dat')
diff --git a/doc/OnlineDocs/src/data/ABCD2.py b/doc/OnlineDocs/src/data/ABCD2.py
index ec0e7ccb15c..2c26d0e7098 100644
--- a/doc/OnlineDocs/src/data/ABCD2.py
+++ b/doc/OnlineDocs/src/data/ABCD2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(initialize=[('A1', 'B1', 1), ('A2', 'B2', 2), ('A3', 'B3', 3)])
-# model.Z = Set(dimen=3)
-model.D = Param(model.Z)
+model.Z = pyo.Set(initialize=[('A1', 'B1', 1), ('A2', 'B2', 2), ('A3', 'B3', 3)])
+# model.Z = pyo.Set(dimen=3)
+model.D = pyo.Param(model.Z)
instance = model.create_instance('ABCD2.dat')
print('Z ' + str(sorted(list(instance.Z.data()))))
print('D')
for key in sorted(instance.D.keys()):
- print(name(instance.D, key) + " " + str(value(instance.D[key])))
+ print(pyo.name(instance.D, key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD3.py b/doc/OnlineDocs/src/data/ABCD3.py
index ba55fd970cc..99a5a9ac4d7 100644
--- a/doc/OnlineDocs/src/data/ABCD3.py
+++ b/doc/OnlineDocs/src/data/ABCD3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.D = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.D = pyo.Param(model.Z)
instance = model.create_instance('ABCD3.dat')
print('Z ' + str(sorted(list(instance.Z.data()))))
print('D')
for key in sorted(instance.D.keys()):
- print(name(instance.D, key) + " " + str(value(instance.D[key])))
+ print(pyo.name(instance.D, key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD4.py b/doc/OnlineDocs/src/data/ABCD4.py
index 2fb397aa3b0..589cac0b0d1 100644
--- a/doc/OnlineDocs/src/data/ABCD4.py
+++ b/doc/OnlineDocs/src/data/ABCD4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.Y = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.Y = pyo.Param(model.Z)
instance = model.create_instance('ABCD4.dat')
print('Z ' + str(sorted(list(instance.Z.data()))))
print('Y')
for key in sorted(instance.Y.keys()):
- print(name(instance.Y, key) + " " + str(value(instance.Y[key])))
+ print(pyo.name(instance.Y, key) + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD5.py b/doc/OnlineDocs/src/data/ABCD5.py
index abc03505e96..67fa242e6c6 100644
--- a/doc/OnlineDocs/src/data/ABCD5.py
+++ b/doc/OnlineDocs/src/data/ABCD5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,14 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.Z = Set()
-model.Y = Param(model.Z)
-model.W = Param(model.Z)
+model.Z = pyo.Set()
+model.Y = pyo.Param(model.Z)
+model.W = pyo.Param(model.Z)
# @decl
instance = model.create_instance('ABCD5.dat')
@@ -24,7 +24,7 @@
print('Z ' + str(sorted(list(instance.Z.data()))))
print('Y')
for key in sorted(instance.Y.keys()):
- print(name(instance.Y, key) + " " + str(value(instance.Y[key])))
+ print(pyo.name(instance.Y, key) + " " + str(pyo.value(instance.Y[key])))
print('W')
for key in sorted(instance.W.keys()):
- print(name(instance.W, key) + " " + str(value(instance.W[key])))
+ print(pyo.name(instance.W, key) + " " + str(pyo.value(instance.W[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD6.py b/doc/OnlineDocs/src/data/ABCD6.py
index 59e0e8e98ae..15c80882872 100644
--- a/doc/OnlineDocs/src/data/ABCD6.py
+++ b/doc/OnlineDocs/src/data/ABCD6.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.D = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.D = pyo.Param(model.Z)
instance = model.create_instance('ABCD6.dat')
print('Z ' + str(sorted(list(instance.Z.data()))))
print('D')
for key in sorted(instance.D.keys()):
- print(name(instance.D, key) + " " + str(value(instance.D[key])))
+ print(pyo.name(instance.D, key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD7.py b/doc/OnlineDocs/src/data/ABCD7.py
index 1bfb4d1e3fb..ed14f1f343c 100644
--- a/doc/OnlineDocs/src/data/ABCD7.py
+++ b/doc/OnlineDocs/src/data/ABCD7.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,14 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import pyomo.common
import sys
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.Y = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.Y = pyo.Param(model.Z)
try:
instance = model.create_instance('ABCD7.dat')
@@ -27,4 +27,4 @@
print('Z ' + str(sorted(list(instance.Z.data()))))
print('Y')
for key in sorted(instance.Y.keys()):
- print(name(instance.Y, key) + " " + str(value(instance.Y[key])))
+ print(pyo.name(instance.Y, key) + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD8.py b/doc/OnlineDocs/src/data/ABCD8.py
index aa1ba0b4cf5..eecadddcd3b 100644
--- a/doc/OnlineDocs/src/data/ABCD8.py
+++ b/doc/OnlineDocs/src/data/ABCD8.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,14 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import pyomo.common
import sys
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.Y = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.Y = pyo.Param(model.Z)
try:
instance = model.create_instance('ABCD8.dat')
@@ -27,4 +27,4 @@
print('Z ' + str(sorted(list(instance.Z.data()))))
print('Y')
for key in sorted(instance.Y.keys()):
- print(name(instance.Y, key) + " " + str(value(instance.Y[key])))
+ print(pyo.name(instance.Y, key) + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/ABCD9.py b/doc/OnlineDocs/src/data/ABCD9.py
index 194c71486d9..37b7b5aaf66 100644
--- a/doc/OnlineDocs/src/data/ABCD9.py
+++ b/doc/OnlineDocs/src/data/ABCD9.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,14 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import pyomo.common
import sys
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=3)
-model.Y = Param(model.Z)
+model.Z = pyo.Set(dimen=3)
+model.Y = pyo.Param(model.Z)
try:
instance = model.create_instance('ABCD9.dat')
@@ -27,4 +27,4 @@
print('Z ' + str(sorted(list(instance.Z.data()))))
print('Y')
for key in sorted(instance.Y.keys()):
- print(instance.Y[key] + " " + str(value(instance.Y[key])))
+ print(instance.Y[key] + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/diet1.py b/doc/OnlineDocs/src/data/diet1.py
index 40582e16ba0..84545133bca 100644
--- a/doc/OnlineDocs/src/data/diet1.py
+++ b/doc/OnlineDocs/src/data/diet1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,30 +10,30 @@
# ___________________________________________________________________________
# diet1.py
-from pyomo.environ import *
+import pyomo.environ as pyo
infinity = float('inf')
MAX_FOOD_SUPPLY = 20.0 # There is a finite food supply
-model = AbstractModel()
+model = pyo.AbstractModel()
# --------------------------------------------------------
-model.FOOD = Set()
-model.cost = Param(model.FOOD, within=PositiveReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals, default=0.0)
+model.FOOD = pyo.Set()
+model.cost = pyo.Param(model.FOOD, within=pyo.PositiveReals)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals, default=0.0)
def f_max_validate(model, value, j):
return model.f_max[j] > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_validate, default=MAX_FOOD_SUPPLY)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_validate, default=MAX_FOOD_SUPPLY)
-model.NUTR = Set()
-model.n_min = Param(model.NUTR, within=NonNegativeReals, default=0.0)
-model.n_max = Param(model.NUTR, default=infinity)
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.NUTR = pyo.Set()
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals, default=0.0)
+model.n_max = pyo.Param(model.NUTR, default=infinity)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
# --------------------------------------------------------
@@ -42,7 +42,7 @@ def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds, within=NonNegativeIntegers)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds, within=pyo.NonNegativeIntegers)
# --------------------------------------------------------
@@ -51,7 +51,7 @@ def Total_Cost_rule(model):
return sum(model.cost[j] * model.Buy[j] for j in model.FOOD)
-model.Total_Cost = Objective(rule=Total_Cost_rule, sense=minimize)
+model.Total_Cost = pyo.Objective(rule=Total_Cost_rule, sense=pyo.minimize)
# --------------------------------------------------------
@@ -67,7 +67,7 @@ def Entree_rule(model):
return sum(model.Buy[e] for e in entrees) >= 1
-model.Entree = Constraint(rule=Entree_rule)
+model.Entree = pyo.Constraint(rule=Entree_rule)
def Side_rule(model):
@@ -75,7 +75,7 @@ def Side_rule(model):
return sum(model.Buy[s] for s in sides) >= 1
-model.Side = Constraint(rule=Side_rule)
+model.Side = pyo.Constraint(rule=Side_rule)
def Drink_rule(model):
@@ -83,4 +83,4 @@ def Drink_rule(model):
return sum(model.Buy[d] for d in drinks) >= 1
-model.Drink = Constraint(rule=Drink_rule)
+model.Drink = pyo.Constraint(rule=Drink_rule)
diff --git a/doc/OnlineDocs/src/data/ex.py b/doc/OnlineDocs/src/data/ex.py
index a66ee30b494..ef2260a0883 100644
--- a/doc/OnlineDocs/src/data/ex.py
+++ b/doc/OnlineDocs/src/data/ex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,14 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.z = Param()
+model.z = pyo.Param()
# @decl
instance = model.create_instance('ex.dat')
-print(value(instance.z))
+print(pyo.value(instance.z))
diff --git a/doc/OnlineDocs/src/data/import1.tab.py b/doc/OnlineDocs/src/data/import1.tab.py
index e160e4fdcde..0393f1d30fa 100644
--- a/doc/OnlineDocs/src/data/import1.tab.py
+++ b/doc/OnlineDocs/src/data/import1.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3', 'A4'])
-model.Y = Param(model.A)
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3', 'A4'])
+model.Y = pyo.Param(model.A)
instance = model.create_instance('import1.tab.dat')
print('Y')
keys = instance.Y.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.Y[key])))
+ print(str(key) + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/import2.tab.py b/doc/OnlineDocs/src/data/import2.tab.py
index 54339551279..057de057125 100644
--- a/doc/OnlineDocs/src/data/import2.tab.py
+++ b/doc/OnlineDocs/src/data/import2.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.Y = Param(model.A)
+model.A = pyo.Set()
+model.Y = pyo.Param(model.A)
instance = model.create_instance('import2.tab.dat')
@@ -22,4 +22,4 @@
print('Y')
keys = instance.Y.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.Y[key])))
+ print(str(key) + " " + str(pyo.value(instance.Y[key])))
diff --git a/doc/OnlineDocs/src/data/import3.tab.py b/doc/OnlineDocs/src/data/import3.tab.py
index 664151d1438..47ac85613d2 100644
--- a/doc/OnlineDocs/src/data/import3.tab.py
+++ b/doc/OnlineDocs/src/data/import3.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,11 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
+model.A = pyo.Set()
instance = model.create_instance('import3.tab.dat')
diff --git a/doc/OnlineDocs/src/data/import4.tab.py b/doc/OnlineDocs/src/data/import4.tab.py
index 91dd3f26a42..6a49abe9130 100644
--- a/doc/OnlineDocs/src/data/import4.tab.py
+++ b/doc/OnlineDocs/src/data/import4.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,11 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.C = Set(dimen=2)
+model.C = pyo.Set(dimen=2)
instance = model.create_instance('import4.tab.dat')
diff --git a/doc/OnlineDocs/src/data/import5.tab.py b/doc/OnlineDocs/src/data/import5.tab.py
index 263677c308c..50f23a96c38 100644
--- a/doc/OnlineDocs/src/data/import5.tab.py
+++ b/doc/OnlineDocs/src/data/import5.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,11 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.B = Set(dimen=2)
+model.B = pyo.Set(dimen=2)
instance = model.create_instance('import5.tab.dat')
diff --git a/doc/OnlineDocs/src/data/import6.tab.py b/doc/OnlineDocs/src/data/import6.tab.py
index 8f4824ad3fe..0b76dc52bff 100644
--- a/doc/OnlineDocs/src/data/import6.tab.py
+++ b/doc/OnlineDocs/src/data/import6.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.p = Param()
+model.p = pyo.Param()
instance = model.create_instance('import6.tab.dat')
-print('p ' + str(value(instance.p)))
+print('p ' + str(pyo.value(instance.p)))
diff --git a/doc/OnlineDocs/src/data/import7.tab.py b/doc/OnlineDocs/src/data/import7.tab.py
index 503f9224323..74af30e6618 100644
--- a/doc/OnlineDocs/src/data/import7.tab.py
+++ b/doc/OnlineDocs/src/data/import7.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.I = Set(initialize=['I1', 'I2', 'I3', 'I4'])
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.U = Param(model.I, model.A)
+model.I = pyo.Set(initialize=['I1', 'I2', 'I3', 'I4'])
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.U = pyo.Param(model.I, model.A)
# BUG: This should cause an error
-# model.U = Param(model.A,model.I)
+# model.U = pyo.Param(model.A,model.I)
instance = model.create_instance('import7.tab.dat')
@@ -25,4 +25,4 @@
print('A ' + str(sorted(list(instance.A.data()))))
print('U')
for key in sorted(instance.U.keys()):
- print(name(instance.U, key) + " " + str(value(instance.U[key])))
+ print(pyo.name(instance.U, key) + " " + str(pyo.value(instance.U[key])))
diff --git a/doc/OnlineDocs/src/data/import8.tab.py b/doc/OnlineDocs/src/data/import8.tab.py
index 02b8724fe45..f5ef022fe19 100644
--- a/doc/OnlineDocs/src/data/import8.tab.py
+++ b/doc/OnlineDocs/src/data/import8.tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.I = Set(initialize=['I1', 'I2', 'I3', 'I4'])
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.U = Param(model.A, model.I)
+model.I = pyo.Set(initialize=['I1', 'I2', 'I3', 'I4'])
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.U = pyo.Param(model.A, model.I)
instance = model.create_instance('import8.tab.dat')
@@ -23,4 +23,4 @@
print('I ' + str(sorted(list(instance.I.data()))))
print('U')
for key in sorted(instance.U.keys()):
- print(name(instance.U, key) + " " + str(value(instance.U[key])))
+ print(pyo.name(instance.U, key) + " " + str(pyo.value(instance.U[key])))
diff --git a/doc/OnlineDocs/src/data/param1.py b/doc/OnlineDocs/src/data/param1.py
index 336a04287b9..dc02a76e0be 100644
--- a/doc/OnlineDocs/src/data/param1.py
+++ b/doc/OnlineDocs/src/data/param1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Param()
-model.B = Param()
-model.C = Param()
-model.D = Param()
-model.E = Param()
+model.A = pyo.Param()
+model.B = pyo.Param()
+model.C = pyo.Param()
+model.D = pyo.Param()
+model.E = pyo.Param()
# @decl
instance = model.create_instance('param1.dat')
-print(value(instance.A))
-print(value(instance.B))
-print(value(instance.C))
-print(value(instance.D))
-print(value(instance.E))
+print(pyo.value(instance.A))
+print(pyo.value(instance.B))
+print(pyo.value(instance.C))
+print(pyo.value(instance.D))
+print(pyo.value(instance.E))
diff --git a/doc/OnlineDocs/src/data/param2.py b/doc/OnlineDocs/src/data/param2.py
index a7d0feafff9..615b8c10d04 100644
--- a/doc/OnlineDocs/src/data/param2.py
+++ b/doc/OnlineDocs/src/data/param2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param2.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param2a.py b/doc/OnlineDocs/src/data/param2a.py
index 42056793ffd..da4cea72b5c 100644
--- a/doc/OnlineDocs/src/data/param2a.py
+++ b/doc/OnlineDocs/src/data/param2a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param2a.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param3.py b/doc/OnlineDocs/src/data/param3.py
index 952f9a9b707..4719cd069c8 100644
--- a/doc/OnlineDocs/src/data/param3.py
+++ b/doc/OnlineDocs/src/data/param3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param3.dat')
@@ -25,12 +25,12 @@
print('B')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param3a.py b/doc/OnlineDocs/src/data/param3a.py
index 028e1d07296..399e61c357b 100644
--- a/doc/OnlineDocs/src/data/param3a.py
+++ b/doc/OnlineDocs/src/data/param3a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param3a.dat')
@@ -25,12 +25,12 @@
print('B')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param3b.py b/doc/OnlineDocs/src/data/param3b.py
index 97f8598610a..bf3a324f79f 100644
--- a/doc/OnlineDocs/src/data/param3b.py
+++ b/doc/OnlineDocs/src/data/param3b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param3b.dat')
@@ -25,12 +25,12 @@
print('B')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param3c.py b/doc/OnlineDocs/src/data/param3c.py
index 582b0f7db75..5ac54c697db 100644
--- a/doc/OnlineDocs/src/data/param3c.py
+++ b/doc/OnlineDocs/src/data/param3c.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param3c.dat')
@@ -25,12 +25,12 @@
print('B')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param4.py b/doc/OnlineDocs/src/data/param4.py
index 010c46fc9c5..545e01b2061 100644
--- a/doc/OnlineDocs/src/data/param4.py
+++ b/doc/OnlineDocs/src/data/param4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Param(model.A)
+model.A = pyo.Set()
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param4.dat')
@@ -23,4 +23,4 @@
print('B')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param5.py b/doc/OnlineDocs/src/data/param5.py
index 2db07f3f990..ec3224ecf98 100644
--- a/doc/OnlineDocs/src/data/param5.py
+++ b/doc/OnlineDocs/src/data/param5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param5.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param5a.py b/doc/OnlineDocs/src/data/param5a.py
index 32a53d24e9b..8f27a830bfd 100644
--- a/doc/OnlineDocs/src/data/param5a.py
+++ b/doc/OnlineDocs/src/data/param5a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param5a.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param6.py b/doc/OnlineDocs/src/data/param6.py
index e3364a933cf..134bc83bb65 100644
--- a/doc/OnlineDocs/src/data/param6.py
+++ b/doc/OnlineDocs/src/data/param6.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param6.dat')
@@ -25,12 +25,12 @@
keys = instance.B.keys()
print('B')
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param6a.py b/doc/OnlineDocs/src/data/param6a.py
index 3d2fa645411..632fdf166cc 100644
--- a/doc/OnlineDocs/src/data/param6a.py
+++ b/doc/OnlineDocs/src/data/param6a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
-model.C = Param(model.A)
-model.D = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
+model.C = pyo.Param(model.A)
+model.D = pyo.Param(model.A)
# @decl
instance = model.create_instance('param6a.dat')
@@ -25,12 +25,12 @@
keys = instance.B.keys()
print('B')
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
print('C')
keys = instance.C.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.C[key])))
+ print(str(key) + " " + str(pyo.value(instance.C[key])))
print('D')
keys = instance.D.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.D[key])))
+ print(str(key) + " " + str(pyo.value(instance.D[key])))
diff --git a/doc/OnlineDocs/src/data/param7a.py b/doc/OnlineDocs/src/data/param7a.py
index b3aba9ec23d..f1c2286466e 100644
--- a/doc/OnlineDocs/src/data/param7a.py
+++ b/doc/OnlineDocs/src/data/param7a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param7a.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param7b.py b/doc/OnlineDocs/src/data/param7b.py
index 8b022f399a8..105d37c2623 100644
--- a/doc/OnlineDocs/src/data/param7b.py
+++ b/doc/OnlineDocs/src/data/param7b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
-model.B = Param(model.A)
+model.A = pyo.Set(dimen=2)
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param7b.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/param8a.py b/doc/OnlineDocs/src/data/param8a.py
index abfa885ded4..7c85dd0ec1a 100644
--- a/doc/OnlineDocs/src/data/param8a.py
+++ b/doc/OnlineDocs/src/data/param8a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=4)
-model.B = Param(model.A)
+model.A = pyo.Set(dimen=4)
+model.B = pyo.Param(model.A)
# @decl
instance = model.create_instance('param8a.dat')
keys = instance.B.keys()
for key in sorted(keys):
- print(str(key) + " " + str(value(instance.B[key])))
+ print(str(key) + " " + str(pyo.value(instance.B[key])))
diff --git a/doc/OnlineDocs/src/data/set1.py b/doc/OnlineDocs/src/data/set1.py
index c84c1ef0819..c76a29eb9cb 100644
--- a/doc/OnlineDocs/src/data/set1.py
+++ b/doc/OnlineDocs/src/data/set1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.B = Set()
-model.C = Set()
+model.A = pyo.Set()
+model.B = pyo.Set()
+model.C = pyo.Set()
instance = model.create_instance('set1.dat')
diff --git a/doc/OnlineDocs/src/data/set2.py b/doc/OnlineDocs/src/data/set2.py
index 9048a49fecb..51565891edd 100644
--- a/doc/OnlineDocs/src/data/set2.py
+++ b/doc/OnlineDocs/src/data/set2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=3)
+model.A = pyo.Set(dimen=3)
# @decl
instance = model.create_instance('set2.dat')
diff --git a/doc/OnlineDocs/src/data/set2a.py b/doc/OnlineDocs/src/data/set2a.py
index f2fa4d71916..5a3c1fcbc29 100644
--- a/doc/OnlineDocs/src/data/set2a.py
+++ b/doc/OnlineDocs/src/data/set2a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=3)
+model.A = pyo.Set(dimen=3)
# @decl
instance = model.create_instance('set2a.dat')
diff --git a/doc/OnlineDocs/src/data/set3.py b/doc/OnlineDocs/src/data/set3.py
index 9cdacbe39e0..d08eb5f5d16 100644
--- a/doc/OnlineDocs/src/data/set3.py
+++ b/doc/OnlineDocs/src/data/set3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set()
-model.B = Set(model.A)
+model.A = pyo.Set()
+model.B = pyo.Set(model.A)
# @decl
-# model.C = Set(model.A,model.A)
+# model.C = pyo.Set(model.A,model.A)
instance = model.create_instance('set3.dat')
diff --git a/doc/OnlineDocs/src/data/set4.py b/doc/OnlineDocs/src/data/set4.py
index b3485638c6f..513f5e3a10d 100644
--- a/doc/OnlineDocs/src/data/set4.py
+++ b/doc/OnlineDocs/src/data/set4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=2)
+model.A = pyo.Set(dimen=2)
# @decl
instance = model.create_instance('set4.dat')
diff --git a/doc/OnlineDocs/src/data/set5.py b/doc/OnlineDocs/src/data/set5.py
index d745d8408d0..7d633fecba1 100644
--- a/doc/OnlineDocs/src/data/set5.py
+++ b/doc/OnlineDocs/src/data/set5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @decl
-model.A = Set(dimen=4)
+model.A = pyo.Set(dimen=4)
# @decl
instance = model.create_instance('set5.dat')
diff --git a/doc/OnlineDocs/src/data/table0.py b/doc/OnlineDocs/src/data/table0.py
index de0fae0c861..270519f8005 100644
--- a/doc/OnlineDocs/src/data/table0.py
+++ b/doc/OnlineDocs/src/data/table0.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.M = Param(model.A)
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.M = pyo.Param(model.A)
instance = model.create_instance('table0.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table0.ul.py b/doc/OnlineDocs/src/data/table0.ul.py
index 524c3756782..319b26901a5 100644
--- a/doc/OnlineDocs/src/data/table0.ul.py
+++ b/doc/OnlineDocs/src/data/table0.ul.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.M = Param(model.A)
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.M = pyo.Param(model.A)
instance = model.create_instance('table0.ul.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table1.py b/doc/OnlineDocs/src/data/table1.py
index f36714b8f1f..f49caeab59a 100644
--- a/doc/OnlineDocs/src/data/table1.py
+++ b/doc/OnlineDocs/src/data/table1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.M = Param(model.A)
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.M = pyo.Param(model.A)
instance = model.create_instance('table1.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table2.py b/doc/OnlineDocs/src/data/table2.py
index 03648a00f8c..d0071bf6eb1 100644
--- a/doc/OnlineDocs/src/data/table2.py
+++ b/doc/OnlineDocs/src/data/table2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.B = Set(initialize=['B1', 'B2', 'B3'])
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.B = pyo.Set(initialize=['B1', 'B2', 'B3'])
-model.M = Param(model.A)
-model.N = Param(model.A, model.B)
+model.M = pyo.Param(model.A)
+model.N = pyo.Param(model.A, model.B)
instance = model.create_instance('table2.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table3.py b/doc/OnlineDocs/src/data/table3.py
index 2c598f112df..6ef45369067 100644
--- a/doc/OnlineDocs/src/data/table3.py
+++ b/doc/OnlineDocs/src/data/table3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.B = Set(initialize=['B1', 'B2', 'B3'])
-model.Z = Set(dimen=2)
+model.A = pyo.Set()
+model.B = pyo.Set(initialize=['B1', 'B2', 'B3'])
+model.Z = pyo.Set(dimen=2)
-model.M = Param(model.A)
-model.N = Param(model.A, model.B)
+model.M = pyo.Param(model.A)
+model.N = pyo.Param(model.A, model.B)
instance = model.create_instance('table3.dat')
diff --git a/doc/OnlineDocs/src/data/table3.ul.py b/doc/OnlineDocs/src/data/table3.ul.py
index 18ced12b388..bb56e1f6586 100644
--- a/doc/OnlineDocs/src/data/table3.ul.py
+++ b/doc/OnlineDocs/src/data/table3.ul.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.B = Set(initialize=['B1', 'B2', 'B3'])
-model.Z = Set(dimen=2)
+model.A = pyo.Set()
+model.B = pyo.Set(initialize=['B1', 'B2', 'B3'])
+model.Z = pyo.Set(dimen=2)
-model.M = Param(model.A)
-model.N = Param(model.A, model.B)
+model.M = pyo.Param(model.A)
+model.N = pyo.Param(model.A, model.B)
instance = model.create_instance('table3.ul.dat')
diff --git a/doc/OnlineDocs/src/data/table4.py b/doc/OnlineDocs/src/data/table4.py
index bd20682b5a9..88ab7a5caf0 100644
--- a/doc/OnlineDocs/src/data/table4.py
+++ b/doc/OnlineDocs/src/data/table4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.Z = Set(dimen=2)
+model.A = pyo.Set()
+model.Z = pyo.Set(dimen=2)
-model.M = Param(model.A)
-model.N = Param(model.Z)
+model.M = pyo.Param(model.A)
+model.N = pyo.Param(model.Z)
instance = model.create_instance('table4.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table4.ul.py b/doc/OnlineDocs/src/data/table4.ul.py
index 9f16f21fe19..3dfb128c7fc 100644
--- a/doc/OnlineDocs/src/data/table4.ul.py
+++ b/doc/OnlineDocs/src/data/table4.ul.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set()
-model.Z = Set(dimen=2)
+model.A = pyo.Set()
+model.Z = pyo.Set(dimen=2)
-model.M = Param(model.A)
-model.N = Param(model.Z)
+model.M = pyo.Param(model.A)
+model.N = pyo.Param(model.Z)
instance = model.create_instance('table4.ul.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table5.py b/doc/OnlineDocs/src/data/table5.py
index a3cb01209a2..b64f1a6ba12 100644
--- a/doc/OnlineDocs/src/data/table5.py
+++ b/doc/OnlineDocs/src/data/table5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Z = Set(dimen=2)
-model.Y = Set(dimen=2)
+model.Z = pyo.Set(dimen=2)
+model.Y = pyo.Set(dimen=2)
instance = model.create_instance('table5.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table6.py b/doc/OnlineDocs/src/data/table6.py
index 1db0a764a23..2133a419f50 100644
--- a/doc/OnlineDocs/src/data/table6.py
+++ b/doc/OnlineDocs/src/data/table6.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,11 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.pi = Param()
+model.pi = pyo.Param()
instance = model.create_instance('table6.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/data/table7.py b/doc/OnlineDocs/src/data/table7.py
index 84a841aca86..e51c98b72a5 100644
--- a/doc/OnlineDocs/src/data/table7.py
+++ b/doc/OnlineDocs/src/data/table7.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.M = Param(model.A)
-model.Z = Set(dimen=2)
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.M = pyo.Param(model.A)
+model.Z = pyo.Set(dimen=2)
instance = model.create_instance('table7.dat')
instance.pprint()
diff --git a/doc/OnlineDocs/src/dataportal/PP_sqlite.py b/doc/OnlineDocs/src/dataportal/PP_sqlite.py
index 1592e820900..84c04db6402 100644
--- a/doc/OnlineDocs/src/dataportal/PP_sqlite.py
+++ b/doc/OnlineDocs/src/dataportal/PP_sqlite.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/dataportal/dataportal_tab.py b/doc/OnlineDocs/src/dataportal/dataportal_tab.py
index 655329d31de..23a43a5d462 100644
--- a/doc/OnlineDocs/src/dataportal/dataportal_tab.py
+++ b/doc/OnlineDocs/src/dataportal/dataportal_tab.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,40 +9,40 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# --------------------------------------------------
# @load
-model = AbstractModel()
-model.A = Set()
-data = DataPortal()
+model = pyo.AbstractModel()
+model.A = pyo.Set()
+data = pyo.DataPortal()
data.load(filename='A.tab', set=model.A)
instance = model.create_instance(data)
# @load
instance.pprint()
# --------------------------------------------------
# @set1
-model = AbstractModel()
-model.A = Set()
-data = DataPortal()
+model = pyo.AbstractModel()
+model.A = pyo.Set()
+data = pyo.DataPortal()
data.load(filename='A.tab', set=model.A)
instance = model.create_instance(data)
# @set1
instance.pprint()
# --------------------------------------------------
# @set2
-model = AbstractModel()
-model.C = Set(dimen=2)
-data = DataPortal()
+model = pyo.AbstractModel()
+model.C = pyo.Set(dimen=2)
+data = pyo.DataPortal()
data.load(filename='C.tab', set=model.C)
instance = model.create_instance(data)
# @set2
instance.pprint()
# --------------------------------------------------
# @set3
-model = AbstractModel()
-model.D = Set(dimen=2)
-data = DataPortal()
+model = pyo.AbstractModel()
+model.D = pyo.Set(dimen=2)
+data = pyo.DataPortal()
data.load(filename='D.tab', set=model.D, format='set_array')
instance = model.create_instance(data)
# @set3
@@ -50,139 +50,139 @@
# --------------------------------------------------
# @param1
-model = AbstractModel()
-data = DataPortal()
-model.z = Param()
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.z = pyo.Param()
data.load(filename='Z.tab', param=model.z)
instance = model.create_instance(data)
# @param1
instance.pprint()
# --------------------------------------------------
# @param2
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.y = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.y = pyo.Param(model.A)
data.load(filename='Y.tab', param=model.y)
instance = model.create_instance(data)
# @param2
instance.pprint()
# --------------------------------------------------
# @param4
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.x = Param(model.A)
-model.w = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.x = pyo.Param(model.A)
+model.w = pyo.Param(model.A)
data.load(filename='XW.tab', param=(model.x, model.w))
instance = model.create_instance(data)
# @param4
instance.pprint()
# --------------------------------------------------
# @param3
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.y = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.y = pyo.Param(model.A)
data.load(filename='Y.tab', param=model.y, index=model.A)
instance = model.create_instance(data)
# @param3
instance.pprint()
# --------------------------------------------------
# @param5
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.w = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.w = pyo.Param(model.A)
data.load(filename='XW.tab', select=('A', 'W'), param=model.w, index=model.A)
instance = model.create_instance(data)
# @param5
instance.pprint()
# --------------------------------------------------
# @param6
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.I = Set(initialize=['I1', 'I2', 'I3', 'I4'])
-model.u = Param(model.I, model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.I = pyo.Set(initialize=['I1', 'I2', 'I3', 'I4'])
+model.u = pyo.Param(model.I, model.A)
data.load(filename='U.tab', param=model.u, format='array')
instance = model.create_instance(data)
# @param6
instance.pprint()
# --------------------------------------------------
# @param7
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(initialize=['A1', 'A2', 'A3'])
-model.I = Set(initialize=['I1', 'I2', 'I3', 'I4'])
-model.t = Param(model.A, model.I)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3'])
+model.I = pyo.Set(initialize=['I1', 'I2', 'I3', 'I4'])
+model.t = pyo.Param(model.A, model.I)
data.load(filename='U.tab', param=model.t, format='transposed_array')
instance = model.create_instance(data)
# @param7
instance.pprint()
# --------------------------------------------------
# @param8
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.s = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.s = pyo.Param(model.A)
data.load(filename='S.tab', param=model.s, index=model.A)
instance = model.create_instance(data)
# @param8
instance.pprint()
# --------------------------------------------------
# @param9
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(initialize=['A1', 'A2', 'A3', 'A4'])
-model.y = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(initialize=['A1', 'A2', 'A3', 'A4'])
+model.y = pyo.Param(model.A)
data.load(filename='Y.tab', param=model.y)
instance = model.create_instance(data)
# @param9
instance.pprint()
# --------------------------------------------------
# @param10
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(dimen=2)
-model.p = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(dimen=2)
+model.p = pyo.Param(model.A)
data.load(filename='PP.tab', param=model.p, index=model.A)
instance = model.create_instance(data)
# @param10
instance.pprint()
# --------------------------------------------------
# @param11
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.B = Set()
-model.q = Param(model.A, model.B)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.B = pyo.Set()
+model.q = pyo.Param(model.A, model.B)
data.load(filename='PP.tab', param=model.q, index=(model.A, model.B))
# instance = model.create_instance(data)
# @param11
# --------------------------------------------------
# @concrete1
-data = DataPortal()
+data = pyo.DataPortal()
data.load(filename='A.tab', set="A", format="set")
-model = ConcreteModel()
-model.A = Set(initialize=data['A'])
+model = pyo.ConcreteModel()
+model.A = pyo.Set(initialize=data['A'])
# @concrete1
model.pprint()
# --------------------------------------------------
# @concrete2
-data = DataPortal()
+data = pyo.DataPortal()
data.load(filename='Z.tab', param="z", format="param")
data.load(filename='Y.tab', param="y", format="table")
-model = ConcreteModel()
-model.z = Param(initialize=data['z'])
-model.y = Param(['A1', 'A2', 'A3'], initialize=data['y'])
+model = pyo.ConcreteModel()
+model.z = pyo.Param(initialize=data['z'])
+model.y = pyo.Param(['A1', 'A2', 'A3'], initialize=data['y'])
# @concrete2
model.pprint()
# --------------------------------------------------
# @getitem
-data = DataPortal()
+data = pyo.DataPortal()
data.load(filename='A.tab', set="A", format="set")
print(data['A']) # ['A1', 'A2', 'A3']
@@ -195,20 +195,20 @@
# @getitem
# --------------------------------------------------
# @excel1
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(dimen=2)
-model.p = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(dimen=2)
+model.p = pyo.Param(model.A)
data.load(filename='excel.xls', range='PPtable', param=model.p, index=model.A)
instance = model.create_instance(data)
# @excel1
instance.pprint()
# --------------------------------------------------
# @excel2
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(dimen=2)
-model.p = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(dimen=2)
+model.p = pyo.Param(model.A)
# data.load(filename='excel.xls', range='AX2:AZ5',
# param=model.p, index=model.A)
instance = model.create_instance(data)
@@ -216,16 +216,16 @@
instance.pprint()
# --------------------------------------------------
# @db1
-model = AbstractModel()
-data = DataPortal()
-model.A = Set(dimen=2)
-model.p = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set(dimen=2)
+model.p = pyo.Param(model.A)
data.load(
filename='PP.sqlite', using='sqlite3', table='PPtable', param=model.p, index=model.A
)
instance = model.create_instance(data)
# @db1
-data = DataPortal()
+data = pyo.DataPortal()
data.load(
filename='PP.sqlite',
using='sqlite3',
@@ -238,10 +238,10 @@
instance.pprint()
# --------------------------------------------------
# @db2
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.p = Param(model.A)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.p = pyo.Param(model.A)
data.load(
filename='PP.sqlite',
using='sqlite3',
@@ -251,7 +251,7 @@
)
instance = model.create_instance(data)
# @db2
-data = DataPortal()
+data = pyo.DataPortal()
data.load(
filename='PP.sqlite',
using='sqlite3',
@@ -265,10 +265,10 @@
# --------------------------------------------------
# @db3
if False:
- model = AbstractModel()
- data = DataPortal()
- model.A = Set()
- model.p = Param(model.A)
+ model = pyo.AbstractModel()
+ data = pyo.DataPortal()
+ model.A = pyo.Set()
+ model.p = pyo.Param(model.A)
data.load(
filename="Driver={MySQL ODBC 5.2 UNICODE Driver}; Database=Pyomo; Server=localhost; User=pyomo;",
using='pypyodbc',
@@ -278,7 +278,7 @@
)
instance = model.create_instance(data)
# @db3
- data = DataPortal()
+ data = pyo.DataPortal()
data.load(
filename="Driver={MySQL ODBC 5.2 UNICODE Driver}; Database=Pyomo; Server=localhost; User=pyomo;",
using='pypyodbc',
@@ -291,30 +291,30 @@
instance.pprint()
# --------------------------------------------------
# @json1
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.B = Set(dimen=2)
-model.C = Set(model.A)
-model.p = Param()
-model.q = Param(model.A)
-model.r = Param(model.B)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.B = pyo.Set(dimen=2)
+model.C = pyo.Set(model.A)
+model.p = pyo.Param()
+model.q = pyo.Param(model.A)
+model.r = pyo.Param(model.B)
data.load(filename='T.json')
# @json1
-data = DataPortal()
+data = pyo.DataPortal()
data.load(filename='T.json', convert_unicode=True)
instance = model.create_instance(data)
instance.pprint()
# --------------------------------------------------
# @yaml1
-model = AbstractModel()
-data = DataPortal()
-model.A = Set()
-model.B = Set(dimen=2)
-model.C = Set(model.A)
-model.p = Param()
-model.q = Param(model.A)
-model.r = Param(model.B)
+model = pyo.AbstractModel()
+data = pyo.DataPortal()
+model.A = pyo.Set()
+model.B = pyo.Set(dimen=2)
+model.C = pyo.Set(model.A)
+model.p = pyo.Param()
+model.q = pyo.Param(model.A)
+model.r = pyo.Param(model.B)
data.load(filename='T.yaml')
# @yaml1
instance = model.create_instance(data)
@@ -322,9 +322,9 @@
# --------------------------------------------------
# @namespaces1
-model = AbstractModel()
-model.C = Set(dimen=2)
-data = DataPortal()
+model = pyo.AbstractModel()
+model.C = pyo.Set(dimen=2)
+data = pyo.DataPortal()
data.load(filename='C.tab', set=model.C, namespace='ns1')
data.load(filename='D.tab', set=model.C, namespace='ns2', format='set_array')
instance1 = model.create_instance(data, namespaces=['ns1'])
diff --git a/doc/OnlineDocs/src/dataportal/param_initialization.py b/doc/OnlineDocs/src/dataportal/param_initialization.py
index 7f9270b5fda..5536e4c4ab1 100644
--- a/doc/OnlineDocs/src/dataportal/param_initialization.py
+++ b/doc/OnlineDocs/src/dataportal/param_initialization.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,18 +9,18 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import numpy
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# @decl1
-model.a = Param(initialize=1.1)
+model.a = pyo.Param(initialize=1.1)
# @decl1
# Initialize with a dictionary
# @decl2
-model.b = Param([1, 2, 3], initialize={1: 1, 2: 2, 3: 3})
+model.b = pyo.Param([1, 2, 3], initialize={1: 1, 2: 2, 3: 3})
# @decl2
@@ -30,7 +30,7 @@ def c(model):
return {1: 1, 2: 2, 3: 3}
-model.c = Param([1, 2, 3], initialize=c)
+model.c = pyo.Param([1, 2, 3], initialize=c)
# @decl3
model.pprint(verbose=True)
diff --git a/doc/OnlineDocs/src/dataportal/set_initialization.py b/doc/OnlineDocs/src/dataportal/set_initialization.py
index a5ab03894e3..e3cb65c9919 100644
--- a/doc/OnlineDocs/src/dataportal/set_initialization.py
+++ b/doc/OnlineDocs/src/dataportal/set_initialization.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,28 +9,28 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import numpy
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# Initialize with a list, tuple or set
# @decl2
-model.A = Set(initialize=[2, 3, 5])
-model.B = Set(initialize=set([2, 3, 5]))
-model.C = Set(initialize=(2, 3, 5))
+model.A = pyo.Set(initialize=[2, 3, 5])
+model.B = pyo.Set(initialize=set([2, 3, 5]))
+model.C = pyo.Set(initialize=(2, 3, 5))
# @decl2
# Initialize with a generator
# @decl3
-model.D = Set(initialize=range(9))
-model.E = Set(initialize=(i for i in model.B if i % 2 == 0))
+model.D = pyo.Set(initialize=range(9))
+model.E = pyo.Set(initialize=(i for i in model.B if i % 2 == 0))
# @decl3
# Initialize with a numpy
# @decl4
f = numpy.array([2, 3, 5])
-model.F = Set(initialize=f)
+model.F = pyo.Set(initialize=f)
# @decl4
@@ -40,7 +40,7 @@ def g(model):
return [2, 3, 5]
-model.G = Set(initialize=g)
+model.G = pyo.Set(initialize=g)
# @decl5
# Initialize an indexed set with a dictionary
@@ -49,7 +49,7 @@ def g(model):
H_init[2] = [1, 3, 5]
H_init[3] = [2, 4, 6]
H_init[4] = [3, 5, 7]
-model.H = Set([2, 3, 4], initialize=H_init)
+model.H = pyo.Set([2, 3, 4], initialize=H_init)
# @decl6
model.pprint(verbose=True)
diff --git a/doc/OnlineDocs/src/expr/design.py b/doc/OnlineDocs/src/expr/design.py
index 647a4537ca4..0f2bd9b248a 100644
--- a/doc/OnlineDocs/src/expr/design.py
+++ b/doc/OnlineDocs/src/expr/design.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,40 +9,40 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# ---------------------------------------------
# @categories
-m = ConcreteModel()
-m.p = Param(default=10, mutable=False)
-m.q = Param(default=10, mutable=True)
-m.x = Var()
-m.y = Var(initialize=1)
+m = pyo.ConcreteModel()
+m.p = pyo.Param(default=10, mutable=False)
+m.q = pyo.Param(default=10, mutable=True)
+m.x = pyo.Var()
+m.y = pyo.Var(initialize=1)
m.y.fixed = True
# @categories
m.pprint()
# ---------------------------------------------
# @named_expression
-M = ConcreteModel()
-M.v = Var()
-M.w = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
+M.w = pyo.Var()
-M.e = Expression(expr=2 * M.v)
+M.e = pyo.Expression(expr=2 * M.v)
f = M.e + 3 # f == 2*v + 3
M.e += M.w # f == 2*v + 3 + w
# @named_expression
# ---------------------------------------------
# @cm1
-M = ConcreteModel()
-M.x = Var(range(5))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
s = 0
for i in range(5):
s += M.x[i]
-with linear_expression() as e:
+with pyo.linear_expression() as e:
for i in range(5):
e += M.x[i]
# @cm1
@@ -52,13 +52,13 @@
# ---------------------------------------------
# @cm2
-M = ConcreteModel()
-M.x = Var(range(5))
-M.y = Var(range(5))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
+M.y = pyo.Var(range(5))
-with linear_expression() as e:
- quicksum((M.x[i] for i in M.x), start=e)
- quicksum((M.y[i] for i in M.y), start=e)
+with pyo.linear_expression() as e:
+ pyo.quicksum((M.x[i] for i in M.x), start=e)
+ pyo.quicksum((M.y[i] for i in M.y), start=e)
# @cm2
print("cm2")
print(e)
diff --git a/doc/OnlineDocs/src/expr/index.py b/doc/OnlineDocs/src/expr/index.py
index fe5b03461c0..e2a9e0caab1 100644
--- a/doc/OnlineDocs/src/expr/index.py
+++ b/doc/OnlineDocs/src/expr/index.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# ---------------------------------------------
# @simple
-M = ConcreteModel()
-M.v = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
e = M.v * 2
# @simple
diff --git a/doc/OnlineDocs/src/expr/managing.py b/doc/OnlineDocs/src/expr/managing.py
index 00d521d16ab..8470dc9032e 100644
--- a/doc/OnlineDocs/src/expr/managing.py
+++ b/doc/OnlineDocs/src/expr/managing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
from math import isclose
import math
import copy
@@ -18,10 +18,10 @@
# @ex1
import pyomo.core.expr as EXPR
-M = ConcreteModel()
-M.x = Var()
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
-e = sin(M.x) + 2 * M.x
+e = pyo.sin(M.x) + 2 * M.x
# sin(x) + 2*x
print(EXPR.expression_to_string(e))
@@ -34,22 +34,22 @@
# @ex2
import pyomo.core.expr as EXPR
-M = ConcreteModel()
-M.x = Var()
-M.y = Var()
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
+M.y = pyo.Var()
-e = sin(M.x) + 2 * M.y
+e = pyo.sin(M.x) + 2 * M.y
# sin(x1) + 2*x2
-print(EXPR.expression_to_string(e, labeler=NumericLabeler('x')))
+print(EXPR.expression_to_string(e, labeler=pyo.NumericLabeler('x')))
# @ex2
# ---------------------------------------------
# @ex5
-M = ConcreteModel()
-M.x = Var()
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
M.x.value = math.pi / 2.0
-val = value(M.x)
+val = pyo.value(M.x)
assert isclose(val, math.pi / 2.0)
# @ex5
# @ex6
@@ -59,9 +59,9 @@
# ---------------------------------------------
# @ex7
-M = ConcreteModel()
-M.x = Var()
-val = value(M.x, exception=False)
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
+val = pyo.value(M.x, exception=False)
assert val is None
# @ex7
@@ -69,9 +69,9 @@
# @ex8
import pyomo.core.expr as EXPR
-M = ConcreteModel()
-M.x = Var()
-M.p = Param(mutable=True)
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
+M.p = pyo.Param(mutable=True)
e = M.p + M.x
s = set([type(M.p)])
@@ -82,9 +82,9 @@
# @ex9
import pyomo.core.expr as EXPR
-M = ConcreteModel()
-M.x = Var()
-M.y = Var()
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
+M.y = pyo.Var()
e = M.x + M.y
M.y.value = 1
@@ -101,17 +101,17 @@
import pyomo.core.expr as EXPR
-class SizeofVisitor(EXPR.SimpleExpressionVisitor):
- def __init__(self):
+class SizeofVisitor(EXPR.StreamBasedExpressionVisitor):
+ def initializeWalker(self, expr):
self.counter = 0
+ return True, expr
- def visit(self, node):
+ def exitNode(self, node, data):
self.counter += 1
- def finalize(self):
+ def finalizeResult(self, result):
return self.counter
-
- # @visitor1
+ # @visitor1
# ---------------------------------------------
@@ -122,12 +122,20 @@ def sizeof_expression(expr):
#
visitor = SizeofVisitor()
#
- # Compute the value using the :func:`xbfs` search method.
+ # Compute the value using the :func:`walk_expression` search method.
#
- return visitor.xbfs(expr)
+ return visitor.walk_expression(expr)
# @visitor2
+# Test:
+m = pyo.ConcreteModel()
+m.x = pyo.Var()
+m.p = pyo.Param(mutable=True)
+assert sizeof_expression(m.x) == 1
+assert sizeof_expression(m.x + m.p) == 3
+assert sizeof_expression(2 * m.x + m.p) == 5
+
# ---------------------------------------------
# @visitor3
import pyomo.core.expr as EXPR
@@ -147,7 +155,7 @@ def visiting_potential_leaf(self, node):
#
# Clone leaf nodes in the expression tree
#
- if node.__class__ in native_numeric_types or not node.is_expression_type():
+ if node.__class__ in pyo.native_numeric_types or not node.is_expression_type():
return True, copy.deepcopy(node, self.memo)
return False, None
@@ -170,9 +178,9 @@ def clone_expression(expr):
# Test:
-m = ConcreteModel()
-m.x = Var(range(2))
-m.p = Param(range(5), mutable=True)
+m = pyo.ConcreteModel()
+m.x = pyo.Var(range(2))
+m.p = pyo.Param(range(5), mutable=True)
e = m.x[0] + 5 * m.x[1]
ce = clone_expression(e)
print(e is not ce)
@@ -181,7 +189,7 @@ def clone_expression(expr):
# x[0] + 5*x[1]
print(str(ce))
# x[0] + 5*x[1]
-print(e.arg(0) is not ce.arg(0))
+print(e.arg(0) is ce.arg(0))
# True
print(e.arg(1) is not ce.arg(1))
# True
@@ -202,7 +210,7 @@ def beforeChild(self, node, child, child_idx):
# nodes that do not conform to the ExpressionBase API (i.e.,
# define is_variable_type)
#
- if child.__class__ in native_numeric_types:
+ if child.__class__ in pyo.native_numeric_types:
return False, child
#
# Replace leaf variables with scaled variables
@@ -233,15 +241,15 @@ def scale_expression(expr, scale):
# ---------------------------------------------
# @visitor7
-M = ConcreteModel()
-M.x = Var(range(5))
-M.p = Param(range(5), mutable=True)
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
+M.p = pyo.Param(range(5), mutable=True)
scale = {}
for i in M.x:
scale[id(M.x[i])] = M.p[i]
-e = quicksum(M.x[i] for i in M.x)
+e = pyo.quicksum(M.x[i] for i in M.x)
f = scale_expression(e, scale)
# p[0]*x[0] + p[1]*x[1] + p[2]*x[2] + p[3]*x[3] + p[4]*x[4]
diff --git a/doc/OnlineDocs/src/expr/overview.py b/doc/OnlineDocs/src/expr/overview.py
index d33725edb88..d8726d038b4 100644
--- a/doc/OnlineDocs/src/expr/overview.py
+++ b/doc/OnlineDocs/src/expr/overview.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# ---------------------------------------------
# @example1
-M = ConcreteModel()
-M.x = Var(range(100))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(100))
# This loop is fast.
e = 0
@@ -30,10 +30,10 @@
# ---------------------------------------------
# @example2
-M = ConcreteModel()
-M.p = Param(initialize=3)
+M = pyo.ConcreteModel()
+M.p = pyo.Param(initialize=3)
M.q = 1 / M.p
-M.x = Var(range(100))
+M.x = pyo.Var(range(100))
# The value M.q is cloned every time it is used.
e = 0
@@ -44,8 +44,8 @@
# ---------------------------------------------
# @tree1
-M = ConcreteModel()
-M.v = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
e = f = 2 * M.v
# @tree1
@@ -53,8 +53,8 @@
# ---------------------------------------------
# @tree2
-M = ConcreteModel()
-M.v = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
e = 2 * M.v
f = e + 3
@@ -64,8 +64,8 @@
# ---------------------------------------------
# @tree3
-M = ConcreteModel()
-M.v = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
e = 2 * M.v
f = e + 3
@@ -77,9 +77,9 @@
# ---------------------------------------------
# @tree4
-M = ConcreteModel()
-M.v = Var()
-M.w = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
+M.w = pyo.Var()
e = 2 * M.v
f = e + 3
@@ -91,11 +91,11 @@
# ---------------------------------------------
# @tree5
-M = ConcreteModel()
-M.v = Var()
-M.w = Var()
+M = pyo.ConcreteModel()
+M.v = pyo.Var()
+M.w = pyo.Var()
-M.e = Expression(expr=2 * M.v)
+M.e = pyo.Expression(expr=2 * M.v)
f = M.e + 3
M.e += M.w
diff --git a/doc/OnlineDocs/src/expr/performance.py b/doc/OnlineDocs/src/expr/performance.py
index 8936bd2ed8c..f7897be8384 100644
--- a/doc/OnlineDocs/src/expr/performance.py
+++ b/doc/OnlineDocs/src/expr/performance.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# ---------------------------------------------
# @loop1
-M = ConcreteModel()
-M.x = Var(range(5))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
s = 0
for i in range(5):
@@ -36,18 +36,18 @@
# ---------------------------------------------
# @prod
-M = ConcreteModel()
-M.x = Var(range(5))
-M.z = Var()
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
+M.z = pyo.Var()
# The product M.x[0] * M.x[1] * ... * M.x[4]
-e1 = prod(M.x[i] for i in M.x)
+e1 = pyo.prod(M.x[i] for i in M.x)
# The product M.x[0]*M.z
-e2 = prod([M.x[0], M.z])
+e2 = pyo.prod([M.x[0], M.z])
# The product M.z*(M.x[0] + ... + M.x[4])
-e3 = prod([sum(M.x[i] for i in M.x), M.z])
+e3 = pyo.prod([sum(M.x[i] for i in M.x), M.z])
# @prod
print(e1)
print(e2)
@@ -55,42 +55,42 @@
# ---------------------------------------------
# @quicksum
-M = ConcreteModel()
-M.x = Var(range(5))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
# Summation using the Python sum() function
e1 = sum(M.x[i] ** 2 for i in M.x)
# Summation using the Pyomo quicksum function
-e2 = quicksum(M.x[i] ** 2 for i in M.x)
+e2 = pyo.quicksum(M.x[i] ** 2 for i in M.x)
# @quicksum
print(e1)
print(e2)
# ---------------------------------------------
# @warning
-M = ConcreteModel()
-M.x = Var(range(5))
+M = pyo.ConcreteModel()
+M.x = pyo.Var(range(5))
-e = quicksum(M.x[i] ** 2 if i > 0 else M.x[i] for i in range(5))
+e = pyo.quicksum(M.x[i] ** 2 if i > 0 else M.x[i] for i in range(5))
# @warning
print(e)
# ---------------------------------------------
# @sum_product1
-M = ConcreteModel()
-M.z = RangeSet(5)
-M.x = Var(range(10))
-M.y = Var(range(10))
+M = pyo.ConcreteModel()
+M.z = pyo.RangeSet(5)
+M.x = pyo.Var(range(10))
+M.y = pyo.Var(range(10))
# Sum the elements of x
-e1 = sum_product(M.x)
+e1 = pyo.sum_product(M.x)
# Sum the product of elements in x and y
-e2 = sum_product(M.x, M.y)
+e2 = pyo.sum_product(M.x, M.y)
# Sum the product of elements in x and y, over the index set z
-e3 = sum_product(M.x, M.y, index=M.z)
+e3 = pyo.sum_product(M.x, M.y, index=M.z)
# @sum_product1
print(e1)
print(e2)
@@ -99,10 +99,10 @@
# ---------------------------------------------
# @sum_product2
# Sum the product of x_i/y_i
-e1 = sum_product(M.x, denom=M.y)
+e1 = pyo.sum_product(M.x, denom=M.y)
# Sum the product of 1/(x_i*y_i)
-e2 = sum_product(denom=(M.x, M.y))
+e2 = pyo.sum_product(denom=(M.x, M.y))
# @sum_product2
print(e1)
print(e2)
diff --git a/doc/OnlineDocs/src/expr/quicksum.py b/doc/OnlineDocs/src/expr/quicksum.py
index 1b6cd3f9909..3e02f160c02 100644
--- a/doc/OnlineDocs/src/expr/quicksum.py
+++ b/doc/OnlineDocs/src/expr/quicksum.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
from pyomo.repn import generate_standard_repn
import time
# @runtime
-M = ConcreteModel()
-M.A = RangeSet(100000)
-M.p = Param(M.A, mutable=True, initialize=1)
-M.x = Var(M.A)
+M = pyo.ConcreteModel()
+M.A = pyo.RangeSet(100000)
+M.p = pyo.Param(M.A, mutable=True, initialize=1)
+M.x = pyo.Var(M.A)
start = time.time()
e = sum((M.x[i] - 1) ** M.p[i] for i in M.A)
@@ -28,7 +28,7 @@
print("repn: %f" % (time.time() - start))
start = time.time()
-e = quicksum((M.x[i] - 1) ** M.p[i] for i in M.A)
+e = pyo.quicksum((M.x[i] - 1) ** M.p[i] for i in M.A)
print("quicksum: %f" % (time.time() - start))
start = time.time()
diff --git a/doc/OnlineDocs/src/kernel/examples.sh b/doc/OnlineDocs/src/kernel/examples.sh
index 0ac9e1a0fbf..1e5db3a6076 100755
--- a/doc/OnlineDocs/src/kernel/examples.sh
+++ b/doc/OnlineDocs/src/kernel/examples.sh
@@ -1,3 +1,4 @@
#! /bin/bash
-for file in `ls ../../library_reference/kernel/examples/*.py | sort`; do python $file; done;
+dir=`dirname $0`
+for file in `ls ${dir}/examples/*.py | sort`; do python $file; done;
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/aml_example.py b/doc/OnlineDocs/src/kernel/examples/aml_example.py
similarity index 99%
rename from doc/OnlineDocs/library_reference/kernel/examples/aml_example.py
rename to doc/OnlineDocs/src/kernel/examples/aml_example.py
index a640b94cc76..3f3c0c2e4c4 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/aml_example.py
+++ b/doc/OnlineDocs/src/kernel/examples/aml_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/conic.py b/doc/OnlineDocs/src/kernel/examples/conic.py
similarity index 97%
rename from doc/OnlineDocs/library_reference/kernel/examples/conic.py
rename to doc/OnlineDocs/src/kernel/examples/conic.py
index 0418d188722..70c1adefeda 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/conic.py
+++ b/doc/OnlineDocs/src/kernel/examples/conic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py b/doc/OnlineDocs/src/kernel/examples/kernel_containers.py
similarity index 96%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_containers.py
index 1931c6d9b56..9264562f095 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_containers.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py b/doc/OnlineDocs/src/kernel/examples/kernel_example.py
similarity index 99%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_example.py
index 1f80bce9788..6e184586d4c 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py b/doc/OnlineDocs/src/kernel/examples/kernel_solving.py
similarity index 96%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_solving.py
index 13d7efc052a..d0a96e16ca3 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_solving.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py b/doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
similarity index 98%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
index d6e38f6b0e0..3bb57febd8d 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/transformer.py b/doc/OnlineDocs/src/kernel/examples/transformer.py
similarity index 84%
rename from doc/OnlineDocs/library_reference/kernel/examples/transformer.py
rename to doc/OnlineDocs/src/kernel/examples/transformer.py
index 43a1d0675bf..c18504a8a54 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/transformer.py
+++ b/doc/OnlineDocs/src/kernel/examples/transformer.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-import pyomo.environ
+import pyomo.environ as pyo
import pyomo.kernel
import pympler.asizeof
@@ -53,11 +53,11 @@ def connect_v_out(self, v_out):
# @aml
def Transformer():
- b = pyomo.environ.Block(concrete=True)
- b._a = pyomo.environ.Param(mutable=True)
- b._v_in = pyomo.environ.Expression()
- b._v_out = pyomo.environ.Expression()
- b._c = pyomo.environ.Constraint(expr=b._a * b._v_out == b._v_in)
+ b = pyo.Block(concrete=True)
+ b._a = pyo.Param(mutable=True)
+ b._v_in = pyo.Expression()
+ b._v_out = pyo.Expression()
+ b._c = pyo.Constraint(expr=b._a * b._v_out == b._v_in)
return b
diff --git a/doc/OnlineDocs/src/scripting/AbstractSuffixes.py b/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
index 1c064042c6b..d600de64924 100644
--- a/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
+++ b/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,25 +9,25 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
-model.I = RangeSet(1, 4)
-model.x = Var(model.I)
+model = pyo.AbstractModel()
+model.I = pyo.RangeSet(1, 4)
+model.x = pyo.Var(model.I)
def c_rule(m, i):
return m.x[i] >= i
-model.c = Constraint(model.I, rule=c_rule)
+model.c = pyo.Constraint(model.I, rule=c_rule)
def foo_rule(m):
return ((m.x[i], 3.0 * i) for i in m.I)
-model.foo = Suffix(rule=foo_rule)
+model.foo = pyo.Suffix(rule=foo_rule)
# instantiate the model
inst = model.create_instance()
diff --git a/doc/OnlineDocs/src/scripting/Isinglebuild.py b/doc/OnlineDocs/src/scripting/Isinglebuild.py
index 344f8905a4a..7e7e4da4353 100644
--- a/doc/OnlineDocs/src/scripting/Isinglebuild.py
+++ b/doc/OnlineDocs/src/scripting/Isinglebuild.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,15 +11,15 @@
# Isinglebuild.py
# NodesIn and NodesOut are created by a build action using the Arcs
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Nodes = Set()
-model.Arcs = Set(dimen=2)
+model.Nodes = pyo.Set()
+model.Arcs = pyo.Set(dimen=2)
-model.NodesOut = Set(model.Nodes, within=model.Nodes, initialize=[])
-model.NodesIn = Set(model.Nodes, within=model.Nodes, initialize=[])
+model.NodesOut = pyo.Set(model.Nodes, within=model.Nodes, initialize=[])
+model.NodesIn = pyo.Set(model.Nodes, within=model.Nodes, initialize=[])
def Populate_In_and_Out(model):
@@ -29,20 +29,20 @@ def Populate_In_and_Out(model):
model.NodesOut[i].add(j)
-model.In_n_Out = BuildAction(rule=Populate_In_and_Out)
+model.In_n_Out = pyo.BuildAction(rule=Populate_In_and_Out)
-model.Flow = Var(model.Arcs, domain=NonNegativeReals)
-model.FlowCost = Param(model.Arcs)
+model.Flow = pyo.Var(model.Arcs, domain=pyo.NonNegativeReals)
+model.FlowCost = pyo.Param(model.Arcs)
-model.Demand = Param(model.Nodes)
-model.Supply = Param(model.Nodes)
+model.Demand = pyo.Param(model.Nodes)
+model.Supply = pyo.Param(model.Nodes)
def Obj_rule(model):
- return summation(model.FlowCost, model.Flow)
+ return pyo.summation(model.FlowCost, model.Flow)
-model.Obj = Objective(rule=Obj_rule, sense=minimize)
+model.Obj = pyo.Objective(rule=Obj_rule, sense=pyo.minimize)
def FlowBalance_rule(model, node):
@@ -55,4 +55,4 @@ def FlowBalance_rule(model, node):
)
-model.FlowBalance = Constraint(model.Nodes, rule=FlowBalance_rule)
+model.FlowBalance = pyo.Constraint(model.Nodes, rule=FlowBalance_rule)
diff --git a/doc/OnlineDocs/src/scripting/NodesIn_init.py b/doc/OnlineDocs/src/scripting/NodesIn_init.py
index c17b70150bc..efd039d4403 100644
--- a/doc/OnlineDocs/src/scripting/NodesIn_init.py
+++ b/doc/OnlineDocs/src/scripting/NodesIn_init.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/Z_init.py b/doc/OnlineDocs/src/scripting/Z_init.py
index 1dd2843f4f0..a97e0836101 100644
--- a/doc/OnlineDocs/src/scripting/Z_init.py
+++ b/doc/OnlineDocs/src/scripting/Z_init.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/abstract2.py b/doc/OnlineDocs/src/scripting/abstract2.py
index 544399a8a42..2ea43b834f0 100644
--- a/doc/OnlineDocs/src/scripting/abstract2.py
+++ b/doc/OnlineDocs/src/scripting/abstract2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,26 +12,26 @@
# abstract2.py
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.I = Set()
-model.J = Set()
+model.I = pyo.Set()
+model.J = pyo.Set()
-model.a = Param(model.I, model.J)
-model.b = Param(model.I)
-model.c = Param(model.J)
+model.a = pyo.Param(model.I, model.J)
+model.b = pyo.Param(model.I)
+model.c = pyo.Param(model.J)
# the next line declares a variable indexed by the set J
-model.x = Var(model.J, domain=NonNegativeReals)
+model.x = pyo.Var(model.J, domain=pyo.NonNegativeReals)
def obj_expression(model):
- return summation(model.c, model.x)
+ return pyo.summation(model.c, model.x)
-model.OBJ = Objective(rule=obj_expression)
+model.OBJ = pyo.Objective(rule=obj_expression)
def ax_constraint_rule(model, i):
@@ -40,4 +40,4 @@ def ax_constraint_rule(model, i):
# the next line creates one constraint for each member of the set model.I
-model.AxbConstraint = Constraint(model.I, rule=ax_constraint_rule)
+model.AxbConstraint = pyo.Constraint(model.I, rule=ax_constraint_rule)
diff --git a/doc/OnlineDocs/src/scripting/abstract2piece.py b/doc/OnlineDocs/src/scripting/abstract2piece.py
index 03c5139004e..d302c5b928e 100644
--- a/doc/OnlineDocs/src/scripting/abstract2piece.py
+++ b/doc/OnlineDocs/src/scripting/abstract2piece.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,22 +12,22 @@
# abstract2piece.py
# Similar to abstract2.py, but the objective is now c times x to the fourth power
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.I = Set()
-model.J = Set()
+model.I = pyo.Set()
+model.J = pyo.Set()
Topx = 6.1 # range of x variables
-model.a = Param(model.I, model.J)
-model.b = Param(model.I)
-model.c = Param(model.J)
+model.a = pyo.Param(model.I, model.J)
+model.b = pyo.Param(model.I)
+model.c = pyo.Param(model.J)
# the next line declares a variable indexed by the set J
-model.x = Var(model.J, domain=NonNegativeReals, bounds=(0, Topx))
-model.y = Var(model.J, domain=NonNegativeReals)
+model.x = pyo.Var(model.J, domain=pyo.NonNegativeReals, bounds=(0, Topx))
+model.y = pyo.Var(model.J, domain=pyo.NonNegativeReals)
# to avoid warnings, we set breakpoints at or beyond the bounds
PieceCnt = 100
@@ -41,16 +41,16 @@ def f4(model, j, xp):
return xp**4
-model.ComputeObj = Piecewise(
+model.ComputeObj = pyo.Piecewise(
model.J, model.y, model.x, pw_pts=bpts, pw_constr_type='EQ', f_rule=f4
)
def obj_expression(model):
- return summation(model.c, model.y)
+ return pyo.summation(model.c, model.y)
-model.OBJ = Objective(rule=obj_expression)
+model.OBJ = pyo.Objective(rule=obj_expression)
def ax_constraint_rule(model, i):
@@ -59,4 +59,4 @@ def ax_constraint_rule(model, i):
# the next line creates one constraint for each member of the set model.I
-model.AxbConstraint = Constraint(model.I, rule=ax_constraint_rule)
+model.AxbConstraint = pyo.Constraint(model.I, rule=ax_constraint_rule)
diff --git a/doc/OnlineDocs/src/scripting/abstract2piecebuild.py b/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
index d454d7fbc79..f48c73ef47b 100644
--- a/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
+++ b/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,23 +12,23 @@
# abstract2piecebuild.py
# Similar to abstract2piece.py, but the breakpoints are created using a build action
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.I = Set()
-model.J = Set()
+model.I = pyo.Set()
+model.J = pyo.Set()
-model.a = Param(model.I, model.J)
-model.b = Param(model.I)
-model.c = Param(model.J)
+model.a = pyo.Param(model.I, model.J)
+model.b = pyo.Param(model.I)
+model.c = pyo.Param(model.J)
-model.Topx = Param(default=6.1) # range of x variables
-model.PieceCnt = Param(default=100)
+model.Topx = pyo.Param(default=6.1) # range of x variables
+model.PieceCnt = pyo.Param(default=100)
# the next line declares a variable indexed by the set J
-model.x = Var(model.J, domain=NonNegativeReals, bounds=(0, model.Topx))
-model.y = Var(model.J, domain=NonNegativeReals)
+model.x = pyo.Var(model.J, domain=pyo.NonNegativeReals, bounds=(0, model.Topx))
+model.y = pyo.Var(model.J, domain=pyo.NonNegativeReals)
# to avoid warnings, we set breakpoints beyond the bounds
# we are using a dictionary so that we can have different
@@ -47,7 +47,7 @@ def bpts_build(model, j):
# The object model.BuildBpts is not referred to again;
# the only goal is to trigger the action at build time
# @BuildAction_example
-model.BuildBpts = BuildAction(model.J, rule=bpts_build)
+model.BuildBpts = pyo.BuildAction(model.J, rule=bpts_build)
# @BuildAction_example
@@ -56,16 +56,16 @@ def f4(model, j, xp):
return xp**4
-model.ComputePieces = Piecewise(
+model.ComputePieces = pyo.Piecewise(
model.J, model.y, model.x, pw_pts=model.bpts, pw_constr_type='EQ', f_rule=f4
)
def obj_expression(model):
- return summation(model.c, model.y)
+ return pyo.summation(model.c, model.y)
-model.OBJ = Objective(rule=obj_expression)
+model.OBJ = pyo.Objective(rule=obj_expression)
def ax_constraint_rule(model, i):
@@ -74,4 +74,4 @@ def ax_constraint_rule(model, i):
# the next line creates one constraint for each member of the set model.I
-model.AxbConstraint = Constraint(model.I, rule=ax_constraint_rule)
+model.AxbConstraint = pyo.Constraint(model.I, rule=ax_constraint_rule)
diff --git a/doc/OnlineDocs/src/scripting/block_iter_example.py b/doc/OnlineDocs/src/scripting/block_iter_example.py
index 10c8a4ea43d..d2d56cd6e76 100644
--- a/doc/OnlineDocs/src/scripting/block_iter_example.py
+++ b/doc/OnlineDocs/src/scripting/block_iter_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
# written by jds, adapted for doc by dlw
-from pyomo.environ import *
+import pyomo.environ as pyo
# simple way to get arbitrary, unique values for each thing
val_iter = 0
@@ -22,30 +22,30 @@ def get_val(*args, **kwds):
return val_iter
-model = ConcreteModel()
-model.I = RangeSet(3)
-model.x = Var(initialize=get_val)
-model.y = Var(model.I, initialize=get_val)
+model = pyo.ConcreteModel()
+model.I = pyo.RangeSet(3)
+model.x = pyo.Var(initialize=get_val)
+model.y = pyo.Var(model.I, initialize=get_val)
-model.b = Block()
-model.b.a = Var(initialize=get_val)
-model.b.b = Var(model.I, initialize=get_val)
+model.b = pyo.Block()
+model.b.a = pyo.Var(initialize=get_val)
+model.b.b = pyo.Var(model.I, initialize=get_val)
def c_rule(b, i):
- b.c = Var(initialize=get_val)
- b.d = Var(b.model().I, initialize=get_val)
+ b.c = pyo.Var(initialize=get_val)
+ b.d = pyo.Var(b.model().I, initialize=get_val)
-model.c = Block([1, 2], rule=c_rule)
+model.c = pyo.Block([1, 2], rule=c_rule)
model.pprint()
# @compprintloop
-for v in model.component_objects(Var, descend_into=True):
+for v in model.component_objects(pyo.Var, descend_into=True):
print("FOUND VAR:" + v.name)
v.pprint()
-for v_data in model.component_data_objects(Var, descend_into=True):
- print("Found: " + v_data.name + ", value = " + str(value(v_data)))
+for v_data in model.component_data_objects(pyo.Var, descend_into=True):
+ print("Found: " + v_data.name + ", value = " + str(pyo.value(v_data)))
# @compprintloop
diff --git a/doc/OnlineDocs/src/scripting/concrete1.py b/doc/OnlineDocs/src/scripting/concrete1.py
index 399715efde6..8c47e21f577 100644
--- a/doc/OnlineDocs/src/scripting/concrete1.py
+++ b/doc/OnlineDocs/src/scripting/concrete1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.x = Var([1, 2], domain=NonNegativeReals)
+model.x = pyo.Var([1, 2], domain=pyo.NonNegativeReals)
-model.OBJ = Objective(expr=2 * model.x[1] + 3 * model.x[2])
+model.OBJ = pyo.Objective(expr=2 * model.x[1] + 3 * model.x[2])
-model.Constraint1 = Constraint(expr=3 * model.x[1] + 4 * model.x[2] >= 1)
+model.Constraint1 = pyo.Constraint(expr=3 * model.x[1] + 4 * model.x[2] >= 1)
diff --git a/doc/OnlineDocs/src/scripting/doubleA.py b/doc/OnlineDocs/src/scripting/doubleA.py
index abf35979a05..c029f2a892f 100644
--- a/doc/OnlineDocs/src/scripting/doubleA.py
+++ b/doc/OnlineDocs/src/scripting/doubleA.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/driveabs2.py b/doc/OnlineDocs/src/scripting/driveabs2.py
index f8f972460b1..f63b2d1c004 100644
--- a/doc/OnlineDocs/src/scripting/driveabs2.py
+++ b/doc/OnlineDocs/src/scripting/driveabs2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/driveconc1.py b/doc/OnlineDocs/src/scripting/driveconc1.py
index 49b92f32d09..cf17002dcd0 100644
--- a/doc/OnlineDocs/src/scripting/driveconc1.py
+++ b/doc/OnlineDocs/src/scripting/driveconc1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/iterative1.py b/doc/OnlineDocs/src/scripting/iterative1.py
index 939120e834f..fb43e8e9743 100644
--- a/doc/OnlineDocs/src/scripting/iterative1.py
+++ b/doc/OnlineDocs/src/scripting/iterative1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/iterative2.py b/doc/OnlineDocs/src/scripting/iterative2.py
index 7506337a491..01ff74c9759 100644
--- a/doc/OnlineDocs/src/scripting/iterative2.py
+++ b/doc/OnlineDocs/src/scripting/iterative2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,6 @@
# iterative2.py
import pyomo.environ as pyo
-from pyomo.opt import SolverFactory
# Create a solver
opt = pyo.SolverFactory('cplex')
diff --git a/doc/OnlineDocs/src/scripting/noiteration1.py b/doc/OnlineDocs/src/scripting/noiteration1.py
index c7a86e9d1e9..ef4684e0572 100644
--- a/doc/OnlineDocs/src/scripting/noiteration1.py
+++ b/doc/OnlineDocs/src/scripting/noiteration1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/parallel.py b/doc/OnlineDocs/src/scripting/parallel.py
index e6cfa002780..e1b277e62ed 100644
--- a/doc/OnlineDocs/src/scripting/parallel.py
+++ b/doc/OnlineDocs/src/scripting/parallel.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/scripting/spy4Constraints.py b/doc/OnlineDocs/src/scripting/spy4Constraints.py
index 66f82802402..c6db6cc4699 100644
--- a/doc/OnlineDocs/src/scripting/spy4Constraints.py
+++ b/doc/OnlineDocs/src/scripting/spy4Constraints.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,30 +14,30 @@
Code snippets for Constraints.rst in testable form
"""
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# @Inequality_constraints_2expressions
-model.x = Var()
+model.x = pyo.Var()
def aRule(model):
return model.x >= 2
-model.Boundx = Constraint(rule=aRule)
+model.Boundx = pyo.Constraint(rule=aRule)
def bRule(model):
return (2, model.x, None)
-model.boundx = Constraint(rule=bRule)
+model.boundx = pyo.Constraint(rule=bRule)
# @Inequality_constraints_2expressions
-model = ConcreteModel()
-model.J = Set(initialize=['butter', 'scones'])
-model.x = Var(model.J)
+model = pyo.ConcreteModel()
+model.J = pyo.Set(initialize=['butter', 'scones'])
+model.x = pyo.Var(model.J)
# @Constraint_example
@@ -45,18 +45,18 @@ def teaOKrule(model):
return model.x['butter'] + model.x['scones'] == 3
-model.TeaConst = Constraint(rule=teaOKrule)
+model.TeaConst = pyo.Constraint(rule=teaOKrule)
# @Constraint_example
# @Passing_elements_crossproduct
-model.A = RangeSet(1, 10)
-model.a = Param(model.A, within=PositiveReals)
-model.ToBuy = Var(model.A)
+model.A = pyo.RangeSet(1, 10)
+model.a = pyo.Param(model.A, within=pyo.PositiveReals)
+model.ToBuy = pyo.Var(model.A)
def bud_rule(model, i):
return model.a[i] * model.ToBuy[i] <= i
-aBudget = Constraint(model.A, rule=bud_rule)
+aBudget = pyo.Constraint(model.A, rule=bud_rule)
# @Passing_elements_crossproduct
diff --git a/doc/OnlineDocs/src/scripting/spy4Expressions.py b/doc/OnlineDocs/src/scripting/spy4Expressions.py
index cf7ed1f112f..1160fbfb7bd 100644
--- a/doc/OnlineDocs/src/scripting/spy4Expressions.py
+++ b/doc/OnlineDocs/src/scripting/spy4Expressions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,44 +14,44 @@
Code snippets for Expressions.rst in testable form
"""
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# @Buildup_expression_switch
switch = 3
-model.A = RangeSet(1, 10)
-model.c = Param(model.A)
-model.d = Param()
-model.x = Var(model.A, domain=Boolean)
+model.A = pyo.RangeSet(1, 10)
+model.c = pyo.Param(model.A)
+model.d = pyo.Param()
+model.x = pyo.Var(model.A, domain=pyo.Boolean)
def pi_rule(model):
- accexpr = summation(model.c, model.x)
+ accexpr = pyo.summation(model.c, model.x)
if switch >= 2:
accexpr = accexpr - model.d
return accexpr >= 0.5
-PieSlice = Constraint(rule=pi_rule)
+PieSlice = pyo.Constraint(rule=pi_rule)
# @Buildup_expression_switch
# @Abstract_wrong_usage
-model.A = RangeSet(1, 10)
-model.c = Param(model.A)
-model.d = Param()
-model.x = Var(model.A, domain=Boolean)
+model.A = pyo.RangeSet(1, 10)
+model.c = pyo.Param(model.A)
+model.d = pyo.Param()
+model.x = pyo.Var(model.A, domain=pyo.Boolean)
def pi_rule(model):
- accexpr = summation(model.c, model.x)
+ accexpr = pyo.summation(model.c, model.x)
if model.d >= 2: # NOT in an abstract model!!
accexpr = accexpr - model.d
return accexpr >= 0.5
-PieSlice = Constraint(rule=pi_rule)
+PieSlice = pyo.Constraint(rule=pi_rule)
# @Abstract_wrong_usage
# @Declare_piecewise_constraints
@@ -70,30 +70,35 @@ def f(model, j, x):
# A nonlinear function
-f = lambda model, x: exp(x) + value(model.p)
+f = lambda model, x: pyo.exp(x) + pyo.value(model.p)
# A step function
f = [0, 0, 1, 1, 2, 2]
# @f_rule_Function_examples
# @Keyword_assignment_example
-kwds = {'pw_constr_type': 'EQ', 'pw_repn': 'SOS2', 'sense': maximize, 'force_pw': True}
+kwds = {
+ 'pw_constr_type': 'EQ',
+ 'pw_repn': 'SOS2',
+ 'sense': pyo.maximize,
+ 'force_pw': True,
+}
# @Keyword_assignment_example
# @Expression_objects_illustration
-model = ConcreteModel()
-model.x = Var(initialize=1.0)
+model = pyo.ConcreteModel()
+model.x = pyo.Var(initialize=1.0)
def _e(m, i):
return m.x * i
-model.e = Expression([1, 2, 3], rule=_e)
+model.e = pyo.Expression([1, 2, 3], rule=_e)
instance = model.create_instance()
-print(value(instance.e[1])) # -> 1.0
+print(pyo.value(instance.e[1])) # -> 1.0
print(instance.e[1]()) # -> 1.0
print(instance.e[1].value) # -> a pyomo expression object
@@ -104,7 +109,7 @@ def _e(m, i):
# ... load results
# print the value of the expression given the loaded optimal solution
-print(value(instance.e[1]))
+print(pyo.value(instance.e[1]))
# @Expression_objects_illustration
@@ -116,8 +121,8 @@ def f(x, p):
# @Define_python_function
# @Generate_new_expression
-model = ConcreteModel()
-model.x = Var()
+model = pyo.ConcreteModel()
+model.x = pyo.Var()
# create a Pyomo expression
e1 = model.x + 5
diff --git a/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py b/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
index 9f6698d63c9..e136fb208e2 100644
--- a/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
+++ b/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,14 +14,14 @@
Code snippets for PyomoCommand.rst in testable form
"""
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
-model.I = RangeSet(3)
-model.J = RangeSet(3)
-model.a = Param(model.I, model.J, default=1.0)
-model.x = Var(model.J)
-model.b = Param(model.I, default=1.0)
+model = pyo.ConcreteModel()
+model.I = pyo.RangeSet(3)
+model.J = pyo.RangeSet(3)
+model.a = pyo.Param(model.I, model.J, default=1.0)
+model.x = pyo.Var(model.J)
+model.b = pyo.Param(model.I, default=1.0)
# @Troubleshooting_printed_command
@@ -32,5 +32,5 @@ def ax_constraint_rule(model, i):
# the next line creates one constraint for each member of the set model.I
-model.AxbConstraint = Constraint(model.I, rule=ax_constraint_rule)
+model.AxbConstraint = pyo.Constraint(model.I, rule=ax_constraint_rule)
# @Troubleshooting_printed_command
diff --git a/doc/OnlineDocs/src/scripting/spy4Variables.py b/doc/OnlineDocs/src/scripting/spy4Variables.py
index 1bc2dc9f1ef..d9fa4d495e0 100644
--- a/doc/OnlineDocs/src/scripting/spy4Variables.py
+++ b/doc/OnlineDocs/src/scripting/spy4Variables.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,11 +14,11 @@
Code snippets for Variables.rst in testable form
"""
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# @Declare_singleton_variable
-model.LumberJack = Var(within=NonNegativeReals, bounds=(0, 6), initialize=1.5)
+model.LumberJack = pyo.Var(within=pyo.NonNegativeReals, bounds=(0, 6), initialize=1.5)
# @Declare_singleton_variable
# @Assign_value
@@ -26,7 +26,7 @@
# @Assign_value
# @Declare_bounds
-model.A = Set(initialize=['Scones', 'Tea'])
+model.A = pyo.Set(initialize=['Scones', 'Tea'])
lb = {'Scones': 2, 'Tea': 4}
ub = {'Scones': 5, 'Tea': 7}
@@ -35,5 +35,5 @@ def fb(model, i):
return (lb[i], ub[i])
-model.PriceToCharge = Var(model.A, domain=PositiveIntegers, bounds=fb)
+model.PriceToCharge = pyo.Var(model.A, domain=pyo.PositiveIntegers, bounds=fb)
# @Declare_bounds
diff --git a/doc/OnlineDocs/src/scripting/spy4scripts.py b/doc/OnlineDocs/src/scripting/spy4scripts.py
index f71a1b67b11..cd9b05ea43e 100644
--- a/doc/OnlineDocs/src/scripting/spy4scripts.py
+++ b/doc/OnlineDocs/src/scripting/spy4scripts.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -56,7 +56,7 @@
instance.y.fixed = True
# @Equivalent_form_of_instance.x.fix(2)
-model = ConcreteModel()
+model = pyo.ConcreteModel()
model.obj1 = pyo.Objective(expr=0)
model.obj2 = pyo.Objective(expr=0)
diff --git a/doc/OnlineDocs/src/strip_examples.py b/doc/OnlineDocs/src/strip_examples.py
index 2fd03256499..8a8aa052e66 100644
--- a/doc/OnlineDocs/src/strip_examples.py
+++ b/doc/OnlineDocs/src/strip_examples.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/src/test_examples.py b/doc/OnlineDocs/src/test_examples.py
index c5c9a135ee9..24aa7088048 100644
--- a/doc/OnlineDocs/src/test_examples.py
+++ b/doc/OnlineDocs/src/test_examples.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/doc/OnlineDocs/tutorial_examples.rst b/doc/OnlineDocs/tutorial_examples.rst
deleted file mode 100644
index dc58b6a6f59..00000000000
--- a/doc/OnlineDocs/tutorial_examples.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-Pyomo Tutorial Examples
-=======================
-
-Additional Pyomo tutorials and examples can be found at the following links:
-
-`Pyomo Workshop Slides and Exercises
-`_
-
-`Prof. Jeffrey Kantor's Pyomo Cookbook
-`_
-
-`Pyomo Gallery
-`_
-
-
diff --git a/examples/dae/Heat_Conduction.py b/examples/dae/Heat_Conduction.py
index 7e11ec59263..78662ec27c1 100644
--- a/examples/dae/Heat_Conduction.py
+++ b/examples/dae/Heat_Conduction.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,19 +11,19 @@
# Heat Conduction Model
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
+m = pyo.ConcreteModel()
m.time = ContinuousSet(bounds=(0, 1))
m.x = ContinuousSet(bounds=(0, 10))
m.y = ContinuousSet(bounds=(0, 5))
-m.T = Var(m.x, m.y, m.time)
-m.u = Var(m.x, m.y, m.time)
-m.T0 = Param(initialize=5)
-m.TD = Param(m.x, m.y, initialize=25)
-m.Ux0 = Param(initialize=10)
-m.Uy5 = Param(initialize=15)
+m.T = pyo.Var(m.x, m.y, m.time)
+m.u = pyo.Var(m.x, m.y, m.time)
+m.T0 = pyo.Param(initialize=5)
+m.TD = pyo.Param(m.x, m.y, initialize=25)
+m.Ux0 = pyo.Param(initialize=10)
+m.Uy5 = pyo.Param(initialize=15)
m.dTdx = DerivativeVar(m.T, wrt=m.x)
m.d2Tdx2 = DerivativeVar(m.T, wrt=(m.x, m.x))
@@ -36,28 +36,28 @@ def _heateq(m, i, j, k):
return m.d2Tdx2[i, j, k] + m.d2Tdy2[i, j, k] + m.u[i, j, k] == m.dTdt[i, j, k]
-m.heateq = Constraint(m.x, m.y, m.time, rule=_heateq)
+m.heateq = pyo.Constraint(m.x, m.y, m.time, rule=_heateq)
def _initT(m, i, j):
return m.T[i, j, 0] == m.T0
-m.initT = Constraint(m.x, m.y, rule=_initT)
+m.initT = pyo.Constraint(m.x, m.y, rule=_initT)
def _xbound(m, j, k):
return m.dTdx[0, j, k] == m.Ux0
-m.xbound = Constraint(m.y, m.time, rule=_xbound)
+m.xbound = pyo.Constraint(m.y, m.time, rule=_xbound)
def _ybound(m, i, k):
return m.dTdy[i, 5, k] == m.Uy5
-m.ybound = Constraint(m.x, m.time, rule=_ybound)
+m.ybound = pyo.Constraint(m.x, m.time, rule=_ybound)
# def _intExp(m,i,j):
# return m.T[i,j,1] - m.TD[i,j]
@@ -66,4 +66,4 @@ def _ybound(m, i, k):
# def _obj(m):
# return Integral(Integral(expr=m.intExp,wrt=m.x,bounds=(0,10)),
# wrt=m.y,bounds=(0,5))
-# m.obj = Objective(rule=_obj)
+# m.obj = pyo.Objective(rule=_obj)
diff --git a/examples/dae/Optimal_Control.py b/examples/dae/Optimal_Control.py
index 676c95271f2..82eca417e29 100644
--- a/examples/dae/Optimal_Control.py
+++ b/examples/dae/Optimal_Control.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -16,45 +16,45 @@
# X2_dot = X1^2 + u^2 X2(0) = 0
# tf = 1
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
+m = pyo.ConcreteModel()
m.t = ContinuousSet(bounds=(0, 1))
-m.x1 = Var(m.t, bounds=(0, 1))
-m.x2 = Var(m.t, bounds=(0, 1))
-m.u = Var(m.t, initialize=0)
+m.x1 = pyo.Var(m.t, bounds=(0, 1))
+m.x2 = pyo.Var(m.t, bounds=(0, 1))
+m.u = pyo.Var(m.t, initialize=0)
m.x1dot = DerivativeVar(m.x1)
m.x2dot = DerivativeVar(m.x2)
-m.obj = Objective(expr=m.x2[1])
+m.obj = pyo.Objective(expr=m.x2[1])
def _x1dot(M, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return M.x1dot[i] == M.u[i]
-m.x1dotcon = Constraint(m.t, rule=_x1dot)
+m.x1dotcon = pyo.Constraint(m.t, rule=_x1dot)
def _x2dot(M, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return M.x2dot[i] == M.x1[i] ** 2 + M.u[i] ** 2
-m.x2dotcon = Constraint(m.t, rule=_x2dot)
+m.x2dotcon = pyo.Constraint(m.t, rule=_x2dot)
def _init(M):
yield M.x1[0] == 1
yield M.x2[0] == 0
- yield ConstraintList.End
+ yield pyo.ConstraintList.End
-m.init_conditions = ConstraintList(rule=_init)
+m.init_conditions = pyo.ConstraintList(rule=_init)
diff --git a/examples/dae/PDE_example.py b/examples/dae/PDE_example.py
index 0aea173415b..dcafc52b05e 100644
--- a/examples/dae/PDE_example.py
+++ b/examples/dae/PDE_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,14 +11,14 @@
# Example 1 from http://www.mathworks.com/help/matlab/ref/pdepe.html
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
-m.pi = Param(initialize=3.1416)
+m = pyo.ConcreteModel()
+m.pi = pyo.Param(initialize=3.1416)
m.t = ContinuousSet(bounds=(0, 2))
m.x = ContinuousSet(bounds=(0, 1))
-m.u = Var(m.x, m.t)
+m.u = pyo.Var(m.x, m.t)
m.dudx = DerivativeVar(m.u, wrt=m.x)
m.dudx2 = DerivativeVar(m.u, wrt=(m.x, m.x))
@@ -27,54 +27,54 @@
def _pde(m, i, j):
if i == 0 or i == 1 or j == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.pi**2 * m.dudt[i, j] == m.dudx2[i, j]
-m.pde = Constraint(m.x, m.t, rule=_pde)
+m.pde = pyo.Constraint(m.x, m.t, rule=_pde)
def _initcon(m, i):
if i == 0 or i == 1:
- return Constraint.Skip
- return m.u[i, 0] == sin(m.pi * i)
+ return pyo.Constraint.Skip
+ return m.u[i, 0] == pyo.sin(m.pi * i)
-m.initcon = Constraint(m.x, rule=_initcon)
+m.initcon = pyo.Constraint(m.x, rule=_initcon)
def _lowerbound(m, j):
return m.u[0, j] == 0
-m.lowerbound = Constraint(m.t, rule=_lowerbound)
+m.lowerbound = pyo.Constraint(m.t, rule=_lowerbound)
def _upperbound(m, j):
- return m.pi * exp(-j) + m.dudx[1, j] == 0
+ return m.pi * pyo.exp(-j) + m.dudx[1, j] == 0
-m.upperbound = Constraint(m.t, rule=_upperbound)
+m.upperbound = pyo.Constraint(m.t, rule=_upperbound)
-m.obj = Objective(expr=1)
+m.obj = pyo.Objective(expr=1)
# Discretize using Orthogonal Collocation
-# discretizer = TransformationFactory('dae.collocation')
+# discretizer = pyo.TransformationFactory('dae.collocation')
# discretizer.apply_to(m,nfe=10,ncp=3,wrt=m.x)
# discretizer.apply_to(m,nfe=20,ncp=3,wrt=m.t)
# Discretize using Finite Difference and Collocation
-discretizer = TransformationFactory('dae.finite_difference')
-discretizer2 = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
+discretizer2 = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=25, wrt=m.x, scheme='BACKWARD')
discretizer2.apply_to(m, nfe=20, ncp=3, wrt=m.t)
# Discretize using Finite Difference Method
-# discretizer = TransformationFactory('dae.finite_difference')
+# discretizer = pyo.TransformationFactory('dae.finite_difference')
# discretizer.apply_to(m,nfe=25,wrt=m.x,scheme='BACKWARD')
# discretizer.apply_to(m,nfe=20,wrt=m.t,scheme='BACKWARD')
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(m, tee=True)
x = []
@@ -86,7 +86,7 @@ def _upperbound(m, j):
tempx = []
for j in sorted(m.t):
tempx.append(i)
- temp.append(value(m.u[i, j]))
+ temp.append(pyo.value(m.u[i, j]))
x.append(tempx)
t.append(sorted(m.t))
u.append(temp)
diff --git a/examples/dae/Parameter_Estimation.py b/examples/dae/Parameter_Estimation.py
index 332a21d93dc..8a244715f2c 100644
--- a/examples/dae/Parameter_Estimation.py
+++ b/examples/dae/Parameter_Estimation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -19,19 +19,19 @@
# tf = 6
#
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-model = AbstractModel()
+model = pyo.AbstractModel()
model.t = ContinuousSet()
-model.MEAS_t = Set(within=model.t) # Measurement times, must be subset of t
-model.x1_meas = Param(model.MEAS_t)
+model.MEAS_t = pyo.Set(within=model.t) # Measurement times, must be subset of t
+model.x1_meas = pyo.Param(model.MEAS_t)
-model.x1 = Var(model.t)
-model.x2 = Var(model.t)
+model.x1 = pyo.Var(model.t)
+model.x2 = pyo.Var(model.t)
-model.p1 = Var(bounds=(-1.5, 1.5))
-model.p2 = Var(bounds=(-1.5, 1.5))
+model.p1 = pyo.Var(bounds=(-1.5, 1.5))
+model.p2 = pyo.Var(bounds=(-1.5, 1.5))
model.x1dot = DerivativeVar(model.x1, wrt=model.t)
model.x2dot = DerivativeVar(model.x2)
@@ -42,34 +42,34 @@ def _init_conditions(model):
yield model.x2[0] == model.p2
-model.init_conditions = ConstraintList(rule=_init_conditions)
+model.init_conditions = pyo.ConstraintList(rule=_init_conditions)
# Alternate way to declare initial conditions
# def _initx1(model):
# return model.x1[0] == model.p1
-# model.initx1 = Constraint(rule=_initx1)
+# model.initx1 = pyo.Constraint(rule=_initx1)
# def _initx2(model):
# return model.x2[0] == model.p2
-# model.initx2 = Constraint(rule=_initx2)
+# model.initx2 = pyo.Constraint(rule=_initx2)
def _x1dot(model, i):
return model.x1dot[i] == model.x2[i]
-model.x1dotcon = Constraint(model.t, rule=_x1dot)
+model.x1dotcon = pyo.Constraint(model.t, rule=_x1dot)
def _x2dot(model, i):
return model.x2dot[i] == 1 - 2 * model.x2[i] - model.x1[i]
-model.x2dotcon = Constraint(model.t, rule=_x2dot)
+model.x2dotcon = pyo.Constraint(model.t, rule=_x2dot)
def _obj(model):
return sum((model.x1[i] - model.x1_meas[i]) ** 2 for i in model.MEAS_t)
-model.obj = Objective(rule=_obj)
+model.obj = pyo.Objective(rule=_obj)
diff --git a/examples/dae/Path_Constraint.py b/examples/dae/Path_Constraint.py
index 69f31980c63..8c4adfffc27 100644
--- a/examples/dae/Path_Constraint.py
+++ b/examples/dae/Path_Constraint.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -20,59 +20,59 @@
# tf = 1
#
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
-m.tf = Param(initialize=1)
+m = pyo.ConcreteModel()
+m.tf = pyo.Param(initialize=1)
m.t = ContinuousSet(bounds=(0, m.tf))
-m.u = Var(m.t, initialize=0)
-m.x1 = Var(m.t)
-m.x2 = Var(m.t)
-m.x3 = Var(m.t)
+m.u = pyo.Var(m.t, initialize=0)
+m.x1 = pyo.Var(m.t)
+m.x2 = pyo.Var(m.t)
+m.x3 = pyo.Var(m.t)
m.dx1 = DerivativeVar(m.x1, wrt=m.t)
m.dx2 = DerivativeVar(m.x2, wrt=m.t)
m.dx3 = DerivativeVar(m.x3, wrt=m.t)
-m.obj = Objective(expr=m.x3[m.tf])
+m.obj = pyo.Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
if t == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dx1[t] == m.x2[t]
-m.x1dotcon = Constraint(m.t, rule=_x1dot)
+m.x1dotcon = pyo.Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
if t == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dx2[t] == -m.x2[t] + m.u[t]
-m.x2dotcon = Constraint(m.t, rule=_x2dot)
+m.x2dotcon = pyo.Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
if t == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dx3[t] == m.x1[t] ** 2 + m.x2[t] ** 2 + 0.005 * m.u[t] ** 2
-m.x3dotcon = Constraint(m.t, rule=_x3dot)
+m.x3dotcon = pyo.Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8 * (t - 0.5) ** 2 + 0.5 <= 0
-m.con = Constraint(m.t, rule=_con)
+m.con = pyo.Constraint(m.t, rule=_con)
def _init(m):
@@ -81,4 +81,4 @@ def _init(m):
yield m.x3[0] == 0
-m.init_conditions = ConstraintList(rule=_init)
+m.init_conditions = pyo.ConstraintList(rule=_init)
diff --git a/examples/dae/ReactionKinetics.py b/examples/dae/ReactionKinetics.py
index fa747cf8b21..0786a19e2c8 100644
--- a/examples/dae/ReactionKinetics.py
+++ b/examples/dae/ReactionKinetics.py
@@ -2,7 +2,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -15,17 +15,17 @@
# reaction models based on "mass action kinetics".
#
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
try:
import matplotlib.pyplot as plt
except ImportError:
plt = None
-fdiff = TransformationFactory('dae.finite_difference')
-colloc = TransformationFactory('dae.collocation')
-solver = SolverFactory('ipopt')
+fdiff = pyo.TransformationFactory('dae.finite_difference')
+colloc = pyo.TransformationFactory('dae.collocation')
+solver = pyo.SolverFactory('ipopt')
class Reaction(object):
@@ -127,12 +127,12 @@ def create_kinetic_model(rxnNet, time):
"""Generate the kinetic model for the specified reaction network on
the time interval of [0, max(time)]. If time is a list, all time
points in the list will be used as finite element boundaries."""
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
model.rxnNetwork = rxnNet
- model.SPECIES = Set(initialize=rxnNet.species())
- model.REACTIONS = Set(initialize=rxnNet.reactions.keys())
+ model.SPECIES = pyo.Set(initialize=rxnNet.species())
+ model.REACTIONS = pyo.Set(initialize=rxnNet.reactions.keys())
try:
maxTime = max(time)
times = time
@@ -141,11 +141,11 @@ def create_kinetic_model(rxnNet, time):
times = [time]
model.TIME = ContinuousSet(bounds=(0, maxTime), initialize=times)
- model.c = Var(model.TIME, model.SPECIES, bounds=(0, None))
+ model.c = pyo.Var(model.TIME, model.SPECIES, bounds=(0, None))
model.dcdt = DerivativeVar(model.c, wrt=model.TIME)
- model.k = Var(model.REACTIONS, bounds=(0, None))
- model.rate = Var(model.TIME, model.REACTIONS)
+ model.k = pyo.Var(model.REACTIONS, bounds=(0, None))
+ model.rate = pyo.Var(model.TIME, model.REACTIONS)
def reaction_rate(m, t, r):
rhs = m.k[r]
@@ -153,7 +153,9 @@ def reaction_rate(m, t, r):
rhs *= m.c[t, s] ** coef
return m.rate[t, r] == rhs
- model.reaction_rate = Constraint(model.TIME, model.REACTIONS, rule=reaction_rate)
+ model.reaction_rate = pyo.Constraint(
+ model.TIME, model.REACTIONS, rule=reaction_rate
+ )
def stoichiometry(m, t, s):
rhs = 0
@@ -164,7 +166,7 @@ def stoichiometry(m, t, s):
rhs += m.rate[t, r] * m.rxnNetwork.reactions[r].products[s]
return m.dcdt[t, s] == rhs
- model.stoichiometry = Constraint(model.TIME, model.SPECIES, rule=stoichiometry)
+ model.stoichiometry = pyo.Constraint(model.TIME, model.SPECIES, rule=stoichiometry)
return model
@@ -193,8 +195,8 @@ def simple_simulation_model():
R = 8.314 # J / K*mol
T = 330 # K
- model.k['AtoB'].fix(A1 * exp(-Ea1 / (R * T)))
- model.k['BtoC'].fix(A2 * exp(-Ea2 / (R * T)))
+ model.k['AtoB'].fix(A1 * pyo.exp(-Ea1 / (R * T)))
+ model.k['BtoC'].fix(A2 * pyo.exp(-Ea2 / (R * T)))
model.c[0, 'A'].fix(1)
model.c[0, 'B'].fix(0)
@@ -209,7 +211,7 @@ def simple_simulation_model():
for _i, _x in enumerate('ABC'):
plt.plot(
[x[0][0] for x in _tmp if x[0][1] == _x],
- [value(x[1]) for x in _tmp if x[0][1] == _x],
+ [pyo.value(x[1]) for x in _tmp if x[0][1] == _x],
'bgr'[_i] + '*',
label=_x,
)
@@ -240,13 +242,13 @@ def simple_optimization_model():
Ea1 = 140000 # J/mol
Ea2 = 100000 # J/mol
R = 8.314 # J / K*mol
- model.T = Var(bounds=(0, None), initialize=330) # K
+ model.T = pyo.Var(bounds=(0, None), initialize=330) # K
def compute_k(m):
- yield m.k['AtoB'] == A1 * exp(-Ea1 / (R * m.T))
- yield m.k['BtoC'] == A2 * exp(-Ea2 / (R * m.T))
+ yield m.k['AtoB'] == A1 * pyo.exp(-Ea1 / (R * m.T))
+ yield m.k['BtoC'] == A2 * pyo.exp(-Ea2 / (R * m.T))
- model.compute_k = ConstraintList(rule=compute_k)
+ model.compute_k = pyo.ConstraintList(rule=compute_k)
# initial conditions
model.c[0, 'A'].fix(1)
@@ -255,7 +257,7 @@ def compute_k(m):
fdiff.apply_to(model, nfe=100)
- model.obj = Objective(sense=maximize, expr=model.c[max(model.TIME), 'B'])
+ model.obj = pyo.Objective(sense=pyo.maximize, expr=model.c[max(model.TIME), 'B'])
results = solver.solve(model, tee=True)
@@ -263,7 +265,7 @@ def compute_k(m):
for _i, _x in enumerate('ABC'):
plt.plot(
[x.index()[0] for x in model.c[:, _x]],
- [value(x) for x in model.c[:, _x]],
+ [pyo.value(x) for x in model.c[:, _x]],
'bgr'[_i] + '*',
label=_x,
)
@@ -282,10 +284,10 @@ def create_regression_model(b, t):
model = create_kinetic_model(rxns, data.keys())
- model.T = Param(initialize=t)
- model.error = Var(bounds=(0, None))
+ model.T = pyo.Param(initialize=t)
+ model.error = pyo.Var(bounds=(0, None))
- model.compute_error = Constraint(
+ model.compute_error = pyo.Constraint(
expr=model.error
== sum(
((model.c[t, key[i]] - x) / max(data[_t][i] for _t in data)) ** 2
@@ -304,9 +306,12 @@ def regression_model():
# Model & data from:
#
- # http://www.doiserbia.nb.rs/img/doi/0367-598X/2014/0367-598X1300037A.pdf
+ # Almagrbi, A. M., Hatami, T., Glišić, S., & Orlović,
+ # A. Determination of kinetic parameters for complex
+ # transesterification reaction by standard optimisation methods.
+ # Hem. Ind. 68(2) 149–159 (2014). doi:10.2298/HEMIND130118037A
#
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
model.key = key = ('MeOH', 'TG', 'DG', 'MG', 'FAME', 'Glycerol')
model.data = data = {
@@ -341,10 +346,10 @@ def regression_model():
},
}
- model.experiment = Block(data.keys(), rule=create_regression_model)
+ model.experiment = pyo.Block(data.keys(), rule=create_regression_model)
- model.obj = Objective(
- sense=minimize, expr=sum(b.error for b in model.experiment[:])
+ model.obj = pyo.Objective(
+ sense=pyo.minimize, expr=sum(b.error for b in model.experiment[:])
)
_experiments = list(model.experiment.values())
@@ -370,20 +375,20 @@ def regression_model():
# independent regression as the starting point)
regress_Ea = True
if regress_Ea:
- model.Kset = Set(initialize=['k_1', 'k_2', 'k_3'])
- model.Ea = Var(model.Kset, bounds=(0, None), initialize=0)
- model.A = Var(model.Kset, bounds=(0, None), initialize=0)
- model.R = Param(initialize=8.314)
+ model.Kset = pyo.Set(initialize=['k_1', 'k_2', 'k_3'])
+ model.Ea = pyo.Var(model.Kset, bounds=(0, None), initialize=0)
+ model.A = pyo.Var(model.Kset, bounds=(0, None), initialize=0)
+ model.R = pyo.Param(initialize=8.314)
for _e in _experiments:
_e.k.fix()
def compute_k(e, _k):
m = e.model()
# k11' == k_mt + k_11 * (C_DG + C_MG) / C_TG_0
- # return e.k[_k] == m.A[_k] * exp( -m.Ea[_k] / ( m.R * e.T ) )
- return log(e.k[_k]) == log(m.A[_k]) - m.Ea[_k] / (m.R * e.T)
+ # return e.k[_k] == m.A[_k] * pyo.exp( -m.Ea[_k] / ( m.R * e.T ) )
+ return pyo.log(e.k[_k]) == pyo.log(m.A[_k]) - m.Ea[_k] / (m.R * e.T)
- _e.compute_k = Constraint(model.Kset, rule=compute_k)
+ _e.compute_k = pyo.Constraint(model.Kset, rule=compute_k)
solver.solve(model, tee=True)
for _e in _experiments:
@@ -408,7 +413,7 @@ def compute_k(e, _k):
_ax = ax2 if _x == 'MeOH' else ax
_ax.plot(
[x.index()[0] for x in model.experiment[T].c[:, _x]],
- [value(x) for x in model.experiment[T].c[:, _x]],
+ [pyo.value(x) for x in model.experiment[T].c[:, _x]],
'mkrgbc'[_i] + '-',
)
plt.show()
diff --git a/examples/dae/car_example.py b/examples/dae/car_example.py
index b6ca2203860..a517ff432b6 100644
--- a/examples/dae/car_example.py
+++ b/examples/dae/car_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -22,53 +22,53 @@
# v(0)=0; v(tf)=0
# -3<=a<=1
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
+m = pyo.ConcreteModel()
-m.R = Param(initialize=0.001) # Friction factor
-m.L = Param(initialize=100.0) # Final position
+m.R = pyo.Param(initialize=0.001) # Friction factor
+m.L = pyo.Param(initialize=100.0) # Final position
m.tau = ContinuousSet(bounds=(0, 1)) # Unscaled time
-m.time = Var(m.tau) # Scaled time
-m.tf = Var()
-m.x = Var(m.tau, bounds=(0, m.L + 50))
-m.v = Var(m.tau, bounds=(0, None))
-m.a = Var(m.tau, bounds=(-3.0, 1.0), initialize=0)
+m.time = pyo.Var(m.tau) # Scaled time
+m.tf = pyo.Var()
+m.x = pyo.Var(m.tau, bounds=(0, m.L + 50))
+m.v = pyo.Var(m.tau, bounds=(0, None))
+m.a = pyo.Var(m.tau, bounds=(-3.0, 1.0), initialize=0)
m.dtime = DerivativeVar(m.time)
m.dx = DerivativeVar(m.x)
m.dv = DerivativeVar(m.v)
-m.obj = Objective(expr=m.tf)
+m.obj = pyo.Objective(expr=m.tf)
def _ode1(m, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dx[i] == m.tf * m.v[i]
-m.ode1 = Constraint(m.tau, rule=_ode1)
+m.ode1 = pyo.Constraint(m.tau, rule=_ode1)
def _ode2(m, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dv[i] == m.tf * (m.a[i] - m.R * m.v[i] ** 2)
-m.ode2 = Constraint(m.tau, rule=_ode2)
+m.ode2 = pyo.Constraint(m.tau, rule=_ode2)
def _ode3(m, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dtime[i] == m.tf
-m.ode3 = Constraint(m.tau, rule=_ode3)
+m.ode3 = pyo.Constraint(m.tau, rule=_ode3)
def _init(m):
@@ -79,15 +79,15 @@ def _init(m):
yield m.time[0] == 0
-m.initcon = ConstraintList(rule=_init)
+m.initcon = pyo.ConstraintList(rule=_init)
-discretizer = TransformationFactory('dae.finite_difference')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
discretizer.apply_to(m, nfe=15, scheme='BACKWARD')
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
solver.solve(m, tee=True)
-print("final time = %6.2f" % (value(m.tf)))
+print("final time = %6.2f" % (pyo.value(m.tf)))
x = []
v = []
@@ -95,10 +95,10 @@ def _init(m):
time = []
for i in m.tau:
- time.append(value(m.time[i]))
- x.append(value(m.x[i]))
- v.append(value(m.v[i]))
- a.append(value(m.a[i]))
+ time.append(pyo.value(m.time[i]))
+ x.append(pyo.value(m.x[i]))
+ v.append(pyo.value(m.v[i]))
+ a.append(pyo.value(m.a[i]))
import matplotlib.pyplot as plt
diff --git a/examples/dae/disease_DAE.py b/examples/dae/disease_DAE.py
index bfeb2530fc9..399a0de2c7e 100644
--- a/examples/dae/disease_DAE.py
+++ b/examples/dae/disease_DAE.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,8 +14,8 @@
###
# Scaling in Continuous Set
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
years = 20
beta_py = 26
@@ -23,23 +23,23 @@
fepy = beta_py * fepr
fe = fepy * years
step = 365.0 / fepy
-model = AbstractModel()
+model = pyo.AbstractModel()
# Define unindexed parameters
-model.P_GAMMA = Param(default=1.0 / 14.0)
-model.P_NUM_BETA = Param(default=beta_py)
-model.P_FEPY = Param(default=fepy)
-model.P_FE = Param(default=fe)
-model.P_STEP = Param(default=step)
-model.P_TRI = Param(default=beta_py * years)
-model.P_FEPR = Param(default=fepr)
+model.P_GAMMA = pyo.Param(default=1.0 / 14.0)
+model.P_NUM_BETA = pyo.Param(default=beta_py)
+model.P_FEPY = pyo.Param(default=fepy)
+model.P_FE = pyo.Param(default=fe)
+model.P_STEP = pyo.Param(default=step)
+model.P_TRI = pyo.Param(default=beta_py * years)
+model.P_FEPR = pyo.Param(default=fepr)
-model.I_OBJ_WT = Param(default=0.995)
-model.PHI_OBJ_WT = Param(default=0.005)
+model.I_OBJ_WT = pyo.Param(default=0.995)
+model.PHI_OBJ_WT = pyo.Param(default=0.005)
# Define sets
-model.S_BETA = RangeSet(1, model.P_NUM_BETA)
-model.S_FE = RangeSet(1, model.P_FE)
+model.S_BETA = pyo.RangeSet(1, model.P_NUM_BETA)
+model.S_FE = pyo.RangeSet(1, model.P_FE)
def _TIME_init(model):
@@ -48,7 +48,7 @@ def _TIME_init(model):
model.TIME = ContinuousSet(initialize=_TIME_init, bounds=(0, None))
-model.S_TRI = RangeSet(1, model.P_TRI)
+model.S_TRI = pyo.RangeSet(1, model.P_TRI)
# Define indexed parameters
beta_ndx = {}
@@ -58,35 +58,35 @@ def _TIME_init(model):
else:
for i in range(1, fe + 1):
beta_ndx[i] = ((i - 1) % beta_py) + 1
-model.P_BETA_NDX = Param(model.S_FE, initialize=beta_ndx, default=1.0)
+model.P_BETA_NDX = pyo.Param(model.S_FE, initialize=beta_ndx, default=1.0)
-model.P_POP = Param(default=1.0e6)
-model.P_REP_FRAC = Param(model.S_TRI, default=0.4)
-model.P_REP_CASES = Param(model.S_TRI, default=10.0)
-model.P_BIRTHS = Param(model.S_FE, default=100.0)
-model.P_DATA_WTS = Param(model.S_TRI, default=1.0)
-model.P_ALL_CASES = Param(model.S_TRI, default=10.0)
+model.P_POP = pyo.Param(default=1.0e6)
+model.P_REP_FRAC = pyo.Param(model.S_TRI, default=0.4)
+model.P_REP_CASES = pyo.Param(model.S_TRI, default=10.0)
+model.P_BIRTHS = pyo.Param(model.S_FE, default=100.0)
+model.P_DATA_WTS = pyo.Param(model.S_TRI, default=1.0)
+model.P_ALL_CASES = pyo.Param(model.S_TRI, default=10.0)
# Define initialization parameters and rules
-model.init_S_bar = Param(default=1.0e5)
-model.init_beta_bar = Param(default=1.0)
-model.init_I_init = Param(default=10.0)
-model.init_S_init = Param(default=1000.0)
-model.init_beta = Param(model.S_BETA, default=1.0)
-model.init_beta_pos = Param(model.S_BETA, default=0.0)
-model.init_beta_neg = Param(model.S_BETA, default=0.0)
-model.init_eps_I = Param(model.S_FE, default=0.0)
-model.init_eps_phi = Param(model.S_TRI, default=0.0)
-
-model.init_S = Param(model.S_FE, default=100.0)
-model.init_I = Param(model.S_FE, default=10.0)
-model.init_phi = Param(model.S_FE, default=0.0)
-model.init_Sdot = Param(model.S_FE, default=1.0)
-model.init_Idot = Param(model.S_FE, default=1.0)
-model.init_phidot = Param(model.S_FE, default=1.0)
-
-model.init_beta_patt = Param(model.S_BETA, default=0.0)
-model.init_beta_int = Param(default=1.0)
+model.init_S_bar = pyo.Param(default=1.0e5)
+model.init_beta_bar = pyo.Param(default=1.0)
+model.init_I_init = pyo.Param(default=10.0)
+model.init_S_init = pyo.Param(default=1000.0)
+model.init_beta = pyo.Param(model.S_BETA, default=1.0)
+model.init_beta_pos = pyo.Param(model.S_BETA, default=0.0)
+model.init_beta_neg = pyo.Param(model.S_BETA, default=0.0)
+model.init_eps_I = pyo.Param(model.S_FE, default=0.0)
+model.init_eps_phi = pyo.Param(model.S_TRI, default=0.0)
+
+model.init_S = pyo.Param(model.S_FE, default=100.0)
+model.init_I = pyo.Param(model.S_FE, default=10.0)
+model.init_phi = pyo.Param(model.S_FE, default=0.0)
+model.init_Sdot = pyo.Param(model.S_FE, default=1.0)
+model.init_Idot = pyo.Param(model.S_FE, default=1.0)
+model.init_phidot = pyo.Param(model.S_FE, default=1.0)
+
+model.init_beta_patt = pyo.Param(model.S_BETA, default=0.0)
+model.init_beta_int = pyo.Param(default=1.0)
def _init_S_bar(model):
@@ -190,28 +190,28 @@ def _init_people_bounds(model):
# Define unindexed variables
-model.S_bar = Var(initialize=_init_S_bar, bounds=(0, None))
-model.beta_bar = Var(initialize=_init_beta_bar, bounds=(0.05, 5))
-model.I_init = Var(initialize=_init_I_init, bounds=_init_people_bounds)
-model.S_init = Var(initialize=_init_S_init, bounds=_init_people_bounds)
-model.phi_init = Param(default=0.0)
+model.S_bar = pyo.Var(initialize=_init_S_bar, bounds=(0, None))
+model.beta_bar = pyo.Var(initialize=_init_beta_bar, bounds=(0.05, 5))
+model.I_init = pyo.Var(initialize=_init_I_init, bounds=_init_people_bounds)
+model.S_init = pyo.Var(initialize=_init_S_init, bounds=_init_people_bounds)
+model.phi_init = pyo.Param(default=0.0)
# Define indexed variables
-model.beta = Var(model.S_BETA, initialize=_init_beta, bounds=(0.01, 5))
+model.beta = pyo.Var(model.S_BETA, initialize=_init_beta, bounds=(0.01, 5))
-model.beta_pos = Var(model.S_BETA, initialize=_init_beta_pos, bounds=(0, None))
-model.beta_neg = Var(model.S_BETA, initialize=_init_beta_neg, bounds=(0, None))
-model.beta_patt = Var(model.S_BETA, initialize=_init_beta_patt, bounds=(-5, 5))
-model.beta_int = Var(initialize=_init_beta_int, bounds=(0.01, 5.0))
-model.beta_c = Var(initialize=1.0)
-model.alpha = Var(initialize=0.05, bounds=(-1.0, 1.0))
+model.beta_pos = pyo.Var(model.S_BETA, initialize=_init_beta_pos, bounds=(0, None))
+model.beta_neg = pyo.Var(model.S_BETA, initialize=_init_beta_neg, bounds=(0, None))
+model.beta_patt = pyo.Var(model.S_BETA, initialize=_init_beta_patt, bounds=(-5, 5))
+model.beta_int = pyo.Var(initialize=_init_beta_int, bounds=(0.01, 5.0))
+model.beta_c = pyo.Var(initialize=1.0)
+model.alpha = pyo.Var(initialize=0.05, bounds=(-1.0, 1.0))
-model.eps_I = Var(model.S_FE, initialize=_init_eps_I)
-model.eps_phi = Var(model.S_TRI, initialize=_init_eps_phi)
+model.eps_I = pyo.Var(model.S_FE, initialize=_init_eps_I)
+model.eps_phi = pyo.Var(model.S_TRI, initialize=_init_eps_phi)
-model.S = Var(model.TIME, initialize=_init_S, bounds=_people_bounds)
-model.I = Var(model.TIME, initialize=_init_I, bounds=_people_bounds)
-model.phi = Var(model.TIME, initialize=_init_phi, bounds=(0, None))
+model.S = pyo.Var(model.TIME, initialize=_init_S, bounds=_people_bounds)
+model.I = pyo.Var(model.TIME, initialize=_init_I, bounds=_people_bounds)
+model.phi = pyo.Var(model.TIME, initialize=_init_phi, bounds=(0, None))
model.Sdot = DerivativeVar(model.S, initialize=_init_Sdot)
model.Idot = DerivativeVar(model.I, initialize=_init_Idot)
model.phidot = DerivativeVar(model.phi, initialize=_init_phidot, bounds=(-10, None))
@@ -225,7 +225,7 @@ def _obj_rule(model):
)
-model.obj = Objective(rule=_obj_rule)
+model.obj = pyo.Objective(rule=_obj_rule)
########################
@@ -237,7 +237,7 @@ def _init_conditions(model):
yield model.phi[0] == model.phi_init
-model.init_conditions = ConstraintList(rule=_init_conditions)
+model.init_conditions = pyo.ConstraintList(rule=_init_conditions)
def _reported_cases(model, i):
@@ -250,7 +250,7 @@ def _reported_cases(model, i):
+ model.eps_phi[i]
)
else:
- return Constraint.Skip
+ return pyo.Constraint.Skip
else:
if model.P_DATA_WTS[i] > 0.1:
return (
@@ -263,10 +263,10 @@ def _reported_cases(model, i):
+ model.eps_phi[i]
)
else:
- return Constraint.Skip
+ return pyo.Constraint.Skip
-model.con_reported_cases = Constraint(model.S_TRI, rule=_reported_cases)
+model.con_reported_cases = pyo.Constraint(model.S_TRI, rule=_reported_cases)
def _beta_bar(model):
@@ -276,12 +276,12 @@ def _beta_bar(model):
)
-model.con_beta_bar = Constraint(rule=_beta_bar)
+model.con_beta_bar = pyo.Constraint(rule=_beta_bar)
def _phidot_eq(model, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
fe = model.TIME.get_upper_element_boundary(i)
j = model.TIME._fe.index(fe)
return (
@@ -291,45 +291,45 @@ def _phidot_eq(model, i):
)
-model.phidot_eq = Constraint(model.TIME, rule=_phidot_eq)
+model.phidot_eq = pyo.Constraint(model.TIME, rule=_phidot_eq)
def _Idot_eq(model, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return model.Idot[i] == model.phidot[i] - model.P_GAMMA * model.I[i]
-model.Idot_eq = Constraint(model.TIME, rule=_Idot_eq)
+model.Idot_eq = pyo.Constraint(model.TIME, rule=_Idot_eq)
def _Sdot_eq(model, i):
if i == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
fe = model.TIME.get_upper_element_boundary(i)
j = model.TIME._fe.index(fe)
return model.Sdot[i] == -model.phidot[i] + model.P_BIRTHS[j]
-model.Sdot_eq = Constraint(model.TIME, rule=_Sdot_eq)
+model.Sdot_eq = pyo.Constraint(model.TIME, rule=_Sdot_eq)
def _scaled_beta(model, i):
return (model.beta[i], model.beta_c * model.beta_patt[i])
-model.con_city_varying_beta = Constraint(model.S_BETA, rule=_scaled_beta)
+model.con_city_varying_beta = pyo.Constraint(model.S_BETA, rule=_scaled_beta)
def _mean_patt(model):
- return (1.0, sum_product(model.beta_patt) / len(model.S_BETA))
+ return (1.0, pyo.sum_product(model.beta_patt) / len(model.S_BETA))
-model.con_mean_patt = Constraint(rule=_mean_patt)
+model.con_mean_patt = pyo.Constraint(rule=_mean_patt)
def _beta_c(model):
return (0.75, model.beta_c, 1.5)
-model.con_beta_c = Constraint(rule=_beta_c)
+model.con_beta_c = pyo.Constraint(rule=_beta_c)
diff --git a/examples/dae/distill_DAE.py b/examples/dae/distill_DAE.py
index e822cfb1752..640e96abc08 100644
--- a/examples/dae/distill_DAE.py
+++ b/examples/dae/distill_DAE.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,23 +9,23 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.Feed = Param(initialize=24.0 / 60.0)
-model.x_Feed = Param(initialize=0.5)
-model.D = Param(initialize=model.x_Feed * model.Feed)
-model.vol = Param(initialize=1.6)
-model.atray = Param(initialize=0.25)
-model.acond = Param(initialize=0.5)
-model.areb = Param(initialize=1.0)
+model.Feed = pyo.Param(initialize=24.0 / 60.0)
+model.x_Feed = pyo.Param(initialize=0.5)
+model.D = pyo.Param(initialize=model.x_Feed * model.Feed)
+model.vol = pyo.Param(initialize=1.6)
+model.atray = pyo.Param(initialize=0.25)
+model.acond = pyo.Param(initialize=0.5)
+model.areb = pyo.Param(initialize=1.0)
-model.S_TRAYS = Set(dimen=1)
-model.S_RECTIFICATION = Set(within=model.S_TRAYS)
-model.S_STRIPPING = Set(within=model.S_TRAYS)
-model.x0 = Param(model.S_TRAYS)
+model.S_TRAYS = pyo.Set(dimen=1)
+model.S_RECTIFICATION = pyo.Set(within=model.S_TRAYS)
+model.S_STRIPPING = pyo.Set(within=model.S_TRAYS)
+model.x0 = pyo.Param(model.S_TRAYS)
model.t = ContinuousSet(initialize=range(1, 52))
# Alternatively you could simply specify bounds on the
@@ -33,26 +33,26 @@
# automatically.
# model.t = ContinuousSet(bounds=(1,51))
-model.y = Var(model.S_TRAYS, model.t)
+model.y = pyo.Var(model.S_TRAYS, model.t)
def x_init_rule(m, n, ti):
- return value(m.x0[n])
+ return pyo.value(m.x0[n])
-model.x = Var(model.S_TRAYS, model.t, initialize=x_init_rule)
+model.x = pyo.Var(model.S_TRAYS, model.t, initialize=x_init_rule)
model.dx = DerivativeVar(model.x)
-model.rr = Var(model.t, initialize=3.0)
-model.L = Var(model.t, initialize=0.6)
-model.V = Var(model.t, initialize=0.8)
-model.FL = Var(model.t, initialize=1)
-model.u1 = Var(model.t, initialize=3.0, bounds=(1, 5))
+model.rr = pyo.Var(model.t, initialize=3.0)
+model.L = pyo.Var(model.t, initialize=0.6)
+model.V = pyo.Var(model.t, initialize=0.8)
+model.FL = pyo.Var(model.t, initialize=1)
+model.u1 = pyo.Var(model.t, initialize=3.0, bounds=(1, 5))
-model.alpha = Param(initialize=1000)
-model.rho = Param(initialize=1)
-model.u1_ref = Param(initialize=2.0)
-model.y1_ref = Param(initialize=0.895814)
+model.alpha = pyo.Param(initialize=1000)
+model.rho = pyo.Param(initialize=1)
+model.u1_ref = pyo.Param(initialize=2.0)
+model.y1_ref = pyo.Param(initialize=0.895814)
###
@@ -62,42 +62,42 @@ def reflux_ratio_rule(m, t):
return m.rr[t] == m.u1[t]
-model.reflux_ratio = Constraint(model.t, rule=reflux_ratio_rule)
+model.reflux_ratio = pyo.Constraint(model.t, rule=reflux_ratio_rule)
def flowrate_rectificaiton_rule(m, t):
return m.L[t] == m.rr[t] * m.D
-model.flowrate_rectificaiton = Constraint(model.t, rule=flowrate_rectificaiton_rule)
+model.flowrate_rectificaiton = pyo.Constraint(model.t, rule=flowrate_rectificaiton_rule)
def vapor_column_rule(m, t):
return m.V[t] == m.L[t] + m.D
-model.vapor_column = Constraint(model.t, rule=vapor_column_rule)
+model.vapor_column = pyo.Constraint(model.t, rule=vapor_column_rule)
def flowrate_stripping_rule(m, t):
return m.FL[t] == m.Feed + m.L[t]
-model.flowrate_stripping = Constraint(model.t, rule=flowrate_stripping_rule)
+model.flowrate_stripping = pyo.Constraint(model.t, rule=flowrate_stripping_rule)
def mole_frac_balance_rule(m, n, t):
return m.y[n, t] == m.x[n, t] * m.vol / (1 + ((m.vol - 1) * m.x[n, t]))
-model.mole_frac_balance = Constraint(
+model.mole_frac_balance = pyo.Constraint(
model.S_TRAYS, model.t, rule=mole_frac_balance_rule
)
def _diffeq(m, n, t):
if t == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if n == 1:
return m.dx[n, t] == 1 / m.acond * m.V[t] * (m.y[n + 1, t] - m.x[n, t])
elif n in m.S_RECTIFICATION:
@@ -121,11 +121,11 @@ def _diffeq(m, n, t):
)
-model.diffeq = Constraint(model.S_TRAYS, model.t, rule=_diffeq)
+model.diffeq = pyo.Constraint(model.S_TRAYS, model.t, rule=_diffeq)
def _init_rule(m, n):
return m.x[n, 1] == m.x0[n]
-model.init_rule = Constraint(model.S_TRAYS, rule=_init_rule)
+model.init_rule = pyo.Constraint(model.S_TRAYS, rule=_init_rule)
diff --git a/examples/dae/dynamic_scheduling.py b/examples/dae/dynamic_scheduling.py
index 137307e31a9..0e2b5563468 100644
--- a/examples/dae/dynamic_scheduling.py
+++ b/examples/dae/dynamic_scheduling.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,28 +14,28 @@
# packages and includes modeling concepts from the DAE car example and
# the GDP jobshop example.
-from pyomo.environ import *
-from pyomo.dae import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
+from pyomo.gdp import Disjunct, Disjunction
-m = ConcreteModel()
+m = pyo.ConcreteModel()
-m.products = Set(initialize=['A', 'B'])
-m.AthenB = Set(initialize=[0, 1])
+m.products = pyo.Set(initialize=['A', 'B'])
+m.AthenB = pyo.Set(initialize=[0, 1])
m.tau = ContinuousSet(bounds=[0, 1]) # Unscaled Time
-m.k = Param(m.products, initialize={'A': 1, 'B': 5}) # Reaction Rates
+m.k = pyo.Param(m.products, initialize={'A': 1, 'B': 5}) # Reaction Rates
# Cost of having 'A' or 'B' in the final product stream
-m.cost = Param(m.products, initialize={'A': 15000, 'B': 20000})
+m.cost = pyo.Param(m.products, initialize={'A': 15000, 'B': 20000})
-m.tstart = Var(m.products, bounds=(0, None)) # Start Time
-m.tproc = Var(m.products, bounds=(0, None)) # Processing Time
-m.time = Var(m.products, m.tau, bounds=(0, None)) # Scaled time over each job
-m.totaltime = Var() # Total job time
+m.tstart = pyo.Var(m.products, bounds=(0, None)) # Start Time
+m.tproc = pyo.Var(m.products, bounds=(0, None)) # Processing Time
+m.time = pyo.Var(m.products, m.tau, bounds=(0, None)) # Scaled time over each job
+m.totaltime = pyo.Var() # Total job time
-m.c = Var(m.products, m.tau, bounds=(0, None))
+m.c = pyo.Var(m.products, m.tau, bounds=(0, None))
m.dc = DerivativeVar(m.c, wrt=m.tau)
m.dtime = DerivativeVar(m.time, wrt=m.tau)
@@ -49,7 +49,7 @@ def _diffeq(m, p, t):
return m.dc[p, t] == -m.tproc[p] * m.k[p] * m.c[p, t]
-m.diffeq = Constraint(m.products, m.tau, rule=_diffeq)
+m.diffeq = pyo.Constraint(m.products, m.tau, rule=_diffeq)
# Initial time
m.time['A', 0].fix(0)
@@ -61,7 +61,7 @@ def _finalc(m, p):
return m.c[p, 1] <= 0.001
-m.finalc = Constraint(m.products, rule=_finalc)
+m.finalc = pyo.Constraint(m.products, rule=_finalc)
# Scaled time
@@ -69,7 +69,7 @@ def _diffeqtime(m, p, t):
return m.dtime[p, t] == m.tproc[p]
-m.diffeqtime = Constraint(m.products, m.tau, rule=_diffeqtime)
+m.diffeqtime = pyo.Constraint(m.products, m.tau, rule=_diffeqtime)
# No clash disjuncts
@@ -77,10 +77,10 @@ def _noclash(disjunct, AthenB):
model = disjunct.model()
if AthenB:
e = model.tstart['A'] + model.tproc['A'] <= model.tstart['B']
- disjunct.c = Constraint(expr=e)
+ disjunct.c = pyo.Constraint(expr=e)
else:
e = model.tstart['B'] + model.tproc['B'] <= model.tstart['A']
- disjunct.c = Constraint(expr=e)
+ disjunct.c = pyo.Constraint(expr=e)
m.noclash = Disjunct(m.AthenB, rule=_noclash)
@@ -99,7 +99,7 @@ def _duetime(m):
return m.tstart['B'] + m.tproc['B'] <= 2.0
-m.duetime = Constraint(rule=_duetime)
+m.duetime = pyo.Constraint(rule=_duetime)
# Feasibility
@@ -107,7 +107,7 @@ def _feas(m, p):
return m.totaltime >= m.tstart[p] + m.tproc[p]
-m.feas = Constraint(m.products, rule=_feas)
+m.feas = pyo.Constraint(m.products, rule=_feas)
# Objective
@@ -115,28 +115,28 @@ def _obj(m):
return m.totaltime + sum(m.cost[p] * m.c[p, 1] for p in m.products)
-m.obj = Objective(rule=_obj)
+m.obj = pyo.Objective(rule=_obj)
# Discretize model
-discretizer = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=5, ncp=3)
# Reformulate Disjuncts
-gdp_relax = TransformationFactory('gdp.bigm')
+gdp_relax = pyo.TransformationFactory('gdp.bigm')
gdp_relax.apply_to(m, default_bigM=50.0)
# Solve the model
-solver = SolverFactory('couenne')
+solver = pyo.SolverFactory('couenne')
solver.solve(m, tee=True)
# Plot the results
import matplotlib.pyplot as plt
-timeA = [value(m.time['A', i]) + value(m.tstart['A']) for i in m.tau]
-timeB = [value(m.time['B', i]) + value(m.tstart['B']) for i in m.tau]
+timeA = [pyo.value(m.time['A', i]) + pyo.value(m.tstart['A']) for i in m.tau]
+timeB = [pyo.value(m.time['B', i]) + pyo.value(m.tstart['B']) for i in m.tau]
-concA = [value(m.c['A', i]) for i in m.tau]
-concB = [value(m.c['B', i]) for i in m.tau]
+concA = [pyo.value(m.c['A', i]) for i in m.tau]
+concB = [pyo.value(m.c['B', i]) for i in m.tau]
plt.plot(timeA, concA, 'r', label='Reactant A')
plt.plot(timeB, concB, 'b', label='Reactant B')
diff --git a/examples/dae/laplace_BVP.py b/examples/dae/laplace_BVP.py
index 61f911b3826..c14cdc19edf 100644
--- a/examples/dae/laplace_BVP.py
+++ b/examples/dae/laplace_BVP.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-m = ConcreteModel()
+m = pyo.ConcreteModel()
m.x = ContinuousSet(bounds=(0, 1))
m.y = ContinuousSet(bounds=(0, 1))
-m.u = Var(m.x, m.y)
+m.u = pyo.Var(m.x, m.y)
m.dudx = DerivativeVar(m.u, wrt=(m.x, m.x))
m.dudy = DerivativeVar(m.u, wrt=(m.y, m.y))
@@ -23,63 +23,63 @@
def _lowerY(m, i):
if i == 0 or i == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.u[i, 0] == 1
-m.lowerY = Constraint(m.x, rule=_lowerY)
+m.lowerY = pyo.Constraint(m.x, rule=_lowerY)
def _upperY(m, i):
if i == 0 or i == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.u[i, 1] == 2
-m.upperY = Constraint(m.x, rule=_upperY)
+m.upperY = pyo.Constraint(m.x, rule=_upperY)
def _lowerX(m, j):
if j == 0 or j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.u[0, j] == 1
-m.lowerX = Constraint(m.y, rule=_lowerX)
+m.lowerX = pyo.Constraint(m.y, rule=_lowerX)
def _upperX(m, j):
if j == 0 or j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.u[1, j] == 2
-m.upperX = Constraint(m.y, rule=_upperX)
+m.upperX = pyo.Constraint(m.y, rule=_upperX)
def _laplace(m, i, j):
if i == 0 or i == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if j == 0 or j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dudx[i, j] + m.dudy[i, j] == 0
-m.laplace = Constraint(m.x, m.y, rule=_laplace)
+m.laplace = pyo.Constraint(m.x, m.y, rule=_laplace)
def _dummy(m):
return 1.0
-m.obj = Objective(rule=_dummy)
+m.obj = pyo.Objective(rule=_dummy)
-discretizer = TransformationFactory('dae.finite_difference')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
discretizer.apply_to(m, nfe=20, wrt=m.y, scheme='FORWARD')
discretizer.apply_to(m, nfe=20, wrt=m.x, scheme='CENTRAL')
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(m, tee=True)
@@ -94,7 +94,7 @@ def _dummy(m):
tempx = []
for j in sorted(m.y):
tempx.append(i)
- temp.append(value(m.u[i, j]))
+ temp.append(pyo.value(m.u[i, j]))
x.append(tempx)
y.append(sorted(m.y))
u.append(temp)
diff --git a/examples/dae/run_Optimal_Control.py b/examples/dae/run_Optimal_Control.py
index 2e7bc79dff4..2bf85c00253 100644
--- a/examples/dae/run_Optimal_Control.py
+++ b/examples/dae/run_Optimal_Control.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,20 +9,20 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from Optimal_Control import m
# Discretize model using Backward Finite Difference method
-# discretizer = TransformationFactory('dae.finite_difference')
+# discretizer = pyo.TransformationFactory('dae.finite_difference')
# discretizer.apply_to(m,nfe=20,scheme='BACKWARD')
# Discretize model using Orthogonal Collocation
-discretizer = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=20, ncp=3, scheme='LAGRANGE-RADAU')
discretizer.reduce_collocation_points(m, var=m.u, ncp=1, contset=m.t)
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(m, tee=True)
@@ -35,9 +35,9 @@
for i in sorted(m.t):
t.append(i)
- x1.append(value(m.x1[i]))
- x2.append(value(m.x2[i]))
- u.append(value(m.u[i]))
+ x1.append(pyo.value(m.x1[i]))
+ x2.append(pyo.value(m.x2[i]))
+ u.append(pyo.value(m.u[i]))
import matplotlib.pyplot as plt
diff --git a/examples/dae/run_Parameter_Estimation.py b/examples/dae/run_Parameter_Estimation.py
index c9b649df8dd..1024cca73ca 100644
--- a/examples/dae/run_Parameter_Estimation.py
+++ b/examples/dae/run_Parameter_Estimation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from Parameter_Estimation import model
instance = model.create_instance('data_set2.dat')
instance.t.pprint()
# Discretize model using Backward Finite Difference method
-# discretizer = TransformationFactory('dae.finite_difference')
+# discretizer = pyo.TransformationFactory('dae.finite_difference')
# discretizer.apply_to(instance,nfe=20,scheme='BACKWARD')
# Discretize model using Orthogonal Collocation
-discretizer = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(instance, nfe=8, ncp=5)
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(instance, tee=True)
@@ -37,11 +37,11 @@
for i in sorted(instance.MEAS_t):
t_meas.append(i)
- x1_meas.append(value(instance.x1_meas[i]))
+ x1_meas.append(pyo.value(instance.x1_meas[i]))
for i in sorted(instance.t):
t.append(i)
- x1.append(value(instance.x1[i]))
+ x1.append(pyo.value(instance.x1[i]))
import matplotlib.pyplot as plt
diff --git a/examples/dae/run_Path_Constraint.py b/examples/dae/run_Path_Constraint.py
index 996b432a555..ddf1a98c240 100644
--- a/examples/dae/run_Path_Constraint.py
+++ b/examples/dae/run_Path_Constraint.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,27 +9,29 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from Path_Constraint import m
# Discretize model using Finite Difference Method
-# discretizer = TransformationFactory('dae.finite_difference')
+# discretizer = pyo.TransformationFactory('dae.finite_difference')
# discretizer.apply_to(m,nfe=20,scheme='BACKWARD')
# Discretize model using Orthogonal Collocation
-discretizer = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=7, ncp=6, scheme='LAGRANGE-RADAU')
discretizer.reduce_collocation_points(m, var=m.u, ncp=1, contset=m.t)
-results = SolverFactory('ipopt').solve(m, tee=True)
+results = pyo.SolverFactory('ipopt').solve(m, tee=True)
def plotter(subplot, x, *series, **kwds):
plt.subplot(subplot)
for i, y in enumerate(series):
plt.plot(
- list(x), [value(y[t]) for t in x], 'brgcmk'[i % 6] + kwds.get('points', '')
+ list(x),
+ [pyo.value(y[t]) for t in x],
+ 'brgcmk'[i % 6] + kwds.get('points', ''),
)
plt.title(kwds.get('title', ''))
plt.legend(tuple(y.name for y in series), frameon=True, edgecolor='k').draw_frame(
diff --git a/examples/dae/run_disease.py b/examples/dae/run_disease.py
index 5d9595a89d5..8e195af3011 100644
--- a/examples/dae/run_disease.py
+++ b/examples/dae/run_disease.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from disease_DAE import model
instance = model.create_instance('disease.dat')
-discretizer = TransformationFactory('dae.collocation')
+discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(instance, nfe=520, ncp=3)
@@ -25,7 +25,7 @@ def _S_bar(model):
)
-instance.con_S_bar = Constraint(rule=_S_bar)
+instance.con_S_bar = pyo.Constraint(rule=_S_bar)
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(instance, tee=True)
diff --git a/examples/dae/run_distill.py b/examples/dae/run_distill.py
index 9b09850f90a..b0572f74b14 100644
--- a/examples/dae/run_distill.py
+++ b/examples/dae/run_distill.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,18 +9,18 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from distill_DAE import model
instance = model.create_instance('distill.dat')
# Discretize using Finite Difference Approach
-discretizer = TransformationFactory('dae.finite_difference')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
discretizer.apply_to(instance, nfe=50, scheme='BACKWARD')
# Discretize using Orthogonal Collocation
-# discretizer = TransformationFactory('dae.collocation')
+# discretizer = pyo.TransformationFactory('dae.collocation')
# discretizer.apply_to(instance,nfe=50,ncp=3)
# The objective function in the manually discretized pyomo model
@@ -37,9 +37,9 @@ def obj_rule(m):
) + m.rho * sum((m.u1[i] - m.u1_ref) ** 2 for i in m.t if i != 1)
-instance.OBJ = Objective(rule=obj_rule)
+instance.OBJ = pyo.Objective(rule=obj_rule)
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(instance, tee=True)
@@ -50,8 +50,8 @@ def obj_rule(m):
x20 = []
for i in sorted(instance.t):
- x5.append(value(instance.x[5, i]))
- x20.append(value(instance.x[20, i]))
+ x5.append(pyo.value(instance.x[5, i]))
+ x20.append(pyo.value(instance.x[20, i]))
t.append(i)
import matplotlib.pyplot as plt
diff --git a/examples/dae/run_stochpdegas_automatic.py b/examples/dae/run_stochpdegas_automatic.py
index 6fc9f6d594c..4a34b3965a8 100644
--- a/examples/dae/run_stochpdegas_automatic.py
+++ b/examples/dae/run_stochpdegas_automatic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,15 +11,14 @@
import time
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
from stochpdegas_automatic import model
start = time.time()
instance = model.create_instance('stochpdegas_automatic.dat')
# discretize model
-discretizer = TransformationFactory('dae.finite_difference')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
discretizer.apply_to(instance, nfe=1, wrt=instance.DIS, scheme='FORWARD')
discretizer.apply_to(instance, nfe=47, wrt=instance.TIME, scheme='BACKWARD')
@@ -37,7 +36,7 @@ def supcost_rule(m, k):
)
-instance.supcost = Expression(instance.SCEN, rule=supcost_rule)
+instance.supcost = pyo.Expression(instance.SCEN, rule=supcost_rule)
def boostcost_rule(m, k):
@@ -48,7 +47,7 @@ def boostcost_rule(m, k):
)
-instance.boostcost = Expression(instance.SCEN, rule=boostcost_rule)
+instance.boostcost = pyo.Expression(instance.SCEN, rule=boostcost_rule)
def trackcost_rule(m, k):
@@ -59,7 +58,7 @@ def trackcost_rule(m, k):
)
-instance.trackcost = Expression(instance.SCEN, rule=trackcost_rule)
+instance.trackcost = pyo.Expression(instance.SCEN, rule=trackcost_rule)
def sspcost_rule(m, k):
@@ -70,7 +69,7 @@ def sspcost_rule(m, k):
)
-instance.sspcost = Expression(instance.SCEN, rule=sspcost_rule)
+instance.sspcost = pyo.Expression(instance.SCEN, rule=sspcost_rule)
def ssfcost_rule(m, k):
@@ -81,7 +80,7 @@ def ssfcost_rule(m, k):
)
-instance.ssfcost = Expression(instance.SCEN, rule=ssfcost_rule)
+instance.ssfcost = pyo.Expression(instance.SCEN, rule=ssfcost_rule)
def cost_rule(m, k):
@@ -90,28 +89,28 @@ def cost_rule(m, k):
)
-instance.cost = Expression(instance.SCEN, rule=cost_rule)
+instance.cost = pyo.Expression(instance.SCEN, rule=cost_rule)
def mcost_rule(m):
return (1.0 / m.S) * sum(m.cost[k] for k in m.SCEN)
-instance.mcost = Expression(rule=mcost_rule)
+instance.mcost = pyo.Expression(rule=mcost_rule)
def eqcvar_rule(m, k):
return m.cost[k] - m.nu <= m.phi[k]
-instance.eqcvar = Constraint(instance.SCEN, rule=eqcvar_rule)
+instance.eqcvar = pyo.Constraint(instance.SCEN, rule=eqcvar_rule)
def obj_rule(m):
return (1.0 - m.cvar_lambda) * m.mcost + m.cvar_lambda * m.cvarcost
-instance.obj = Objective(rule=obj_rule)
+instance.obj = pyo.Objective(rule=obj_rule)
endTime = time.time() - start
print('model creation time = %s' % (endTime,))
@@ -122,14 +121,14 @@ def obj_rule(m):
% (
i,
sum(
- sum(0.5 * value(instance.pow[i, j, k]) for j in instance.LINK_A)
+ sum(0.5 * pyo.value(instance.pow[i, j, k]) for j in instance.LINK_A)
for k in instance.TIME.get_finite_elements()
),
)
)
-solver = SolverFactory('ipopt')
+solver = pyo.SolverFactory('ipopt')
results = solver.solve(instance, tee=True)
for i in instance.SCEN:
@@ -138,7 +137,7 @@ def obj_rule(m):
% (
i,
sum(
- sum(0.5 * value(instance.pow[i, j, k]) for j in instance.LINK_A)
+ sum(0.5 * pyo.value(instance.pow[i, j, k]) for j in instance.LINK_A)
for k in instance.TIME.get_finite_elements()
),
)
diff --git a/examples/dae/simulator_dae_example.py b/examples/dae/simulator_dae_example.py
index 4ea1f9fd5f0..13ce30cadea 100644
--- a/examples/dae/simulator_dae_example.py
+++ b/examples/dae/simulator_dae_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -22,24 +22,24 @@
# zB' = p1*zA - (p2 + p3)*zB + p4*zC, zB(0)=0
# zA + zB + zC = 1
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from pyomo.dae.simulator import Simulator
def create_model():
- m = ConcreteModel()
+ m = pyo.ConcreteModel()
m.t = ContinuousSet(bounds=(0.0, 1))
- m.p1 = Param(initialize=4.0)
- m.p2 = Param(initialize=2.0)
- m.p3 = Param(initialize=40.0)
- m.p4 = Param(initialize=20.0)
+ m.p1 = pyo.Param(initialize=4.0)
+ m.p2 = pyo.Param(initialize=2.0)
+ m.p3 = pyo.Param(initialize=40.0)
+ m.p4 = pyo.Param(initialize=20.0)
- m.za = Var(m.t)
- m.zb = Var(m.t)
- m.zc = Var(m.t)
+ m.za = pyo.Var(m.t)
+ m.zb = pyo.Var(m.t)
+ m.zc = pyo.Var(m.t)
m.dza = DerivativeVar(m.za)
m.dzb = DerivativeVar(m.zb)
@@ -50,17 +50,17 @@ def create_model():
def _diffeq1(m, t):
return m.dza[t] == -m.p1 * m.za[t] + m.p2 * m.zb[t]
- m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
def _diffeq2(m, t):
return m.dzb[t] == m.p1 * m.za[t] - (m.p2 + m.p3) * m.zb[t] + m.p4 * m.zc[t]
- m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
def _algeq1(m, t):
return m.za[t] + m.zb[t] + m.zc[t] == 1
- m.algeq1 = Constraint(m.t, rule=_algeq1)
+ m.algeq1 = pyo.Constraint(m.t, rule=_algeq1)
return m
@@ -70,7 +70,7 @@ def simulate_model(m):
tsim, profiles = sim.simulate(numpoints=100, integrator='idas')
# Discretize model using Orthogonal Collocation
- discretizer = TransformationFactory('dae.collocation')
+ discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=10, ncp=3)
# Initialize the discretized model using the simulator profiles
@@ -83,9 +83,9 @@ def plot_result(m, sim, tsim, profiles):
import matplotlib.pyplot as plt
time = list(m.t)
- za = [value(m.za[t]) for t in m.t]
- zb = [value(m.zb[t]) for t in m.t]
- zc = [value(m.zc[t]) for t in m.t]
+ za = [pyo.value(m.za[t]) for t in m.t]
+ zb = [pyo.value(m.zb[t]) for t in m.t]
+ zc = [pyo.value(m.zc[t]) for t in m.t]
varorder = sim.get_variable_order()
algorder = sim.get_variable_order(vartype='algebraic')
diff --git a/examples/dae/simulator_dae_multindex_example.py b/examples/dae/simulator_dae_multindex_example.py
index 775eb4f8c79..c5c63f37990 100644
--- a/examples/dae/simulator_dae_multindex_example.py
+++ b/examples/dae/simulator_dae_multindex_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -25,13 +25,13 @@
# This example is modified such that the reaction coefficient
# p1 changes in time
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from pyomo.dae.simulator import Simulator
def create_model():
- m = ConcreteModel()
+ m = pyo.ConcreteModel()
m.t = ContinuousSet(bounds=(0.0, 1), initialize=[0.5])
@@ -40,14 +40,14 @@ def _p1_init(m, t):
return 1.0
return 4.0
- m.p1 = Param(m.t, initialize=4.0, default=_p1_init)
- m.p2 = Param(initialize=2.0)
- m.p3 = Param(initialize=40.0)
- m.p4 = Param(initialize=20.0)
+ m.p1 = pyo.Param(m.t, initialize=4.0, default=_p1_init)
+ m.p2 = pyo.Param(initialize=2.0)
+ m.p3 = pyo.Param(initialize=40.0)
+ m.p4 = pyo.Param(initialize=20.0)
- m.za = Var(m.t)
- m.zb = Var(m.t)
- m.zc = Var(m.t)
+ m.za = pyo.Var(m.t)
+ m.zb = pyo.Var(m.t)
+ m.zc = pyo.Var(m.t)
m.dza = DerivativeVar(m.za)
m.dzb = DerivativeVar(m.zb)
@@ -57,23 +57,23 @@ def _p1_init(m, t):
# Setting the time-varying profile
p1_profile = {0: 4.0, 0.5: 1.0}
- m.var_input = Suffix(direction=Suffix.LOCAL)
+ m.var_input = pyo.Suffix(direction=pyo.Suffix.LOCAL)
m.var_input[m.p1] = p1_profile
def _diffeq1(m, t):
return m.dza[t] == -m.p1[t] * m.za[t] + m.p2 * m.zb[t]
- m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
def _diffeq2(m, t):
return m.dzb[t] == m.p1[t] * m.za[t] - (m.p2 + m.p3) * m.zb[t] + m.p4 * m.zc[t]
- m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
def _algeq1(m, t):
return m.za[t] + m.zb[t] + m.zc[t] == 1
- m.algeq1 = Constraint(m.t, rule=_algeq1)
+ m.algeq1 = pyo.Constraint(m.t, rule=_algeq1)
return m
@@ -85,7 +85,7 @@ def simulate_model(m):
)
# Discretize model using Orthogonal Collocation
- discretizer = TransformationFactory('dae.collocation')
+ discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=10, ncp=3)
# Initialize the discretized model using the simulator profiles
@@ -98,9 +98,9 @@ def plot_results(m, sim, tsim, profiles):
import matplotlib.pyplot as plt
time = list(m.t)
- za = [value(m.za[t]) for t in m.t]
- zb = [value(m.zb[t]) for t in m.t]
- zc = [value(m.zc[t]) for t in m.t]
+ za = [pyo.value(m.za[t]) for t in m.t]
+ zb = [pyo.value(m.zb[t]) for t in m.t]
+ zc = [pyo.value(m.zc[t]) for t in m.t]
varorder = sim.get_variable_order()
algorder = sim.get_variable_order(vartype='algebraic')
diff --git a/examples/dae/simulator_ode_example.py b/examples/dae/simulator_ode_example.py
index f6f28b87d07..5fe601218d9 100644
--- a/examples/dae/simulator_ode_example.py
+++ b/examples/dae/simulator_ode_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -18,21 +18,21 @@
# theta' = omega
# omega' = -b*omega - c*sin(theta)
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from pyomo.dae.simulator import Simulator
def create_model():
- m = ConcreteModel()
+ m = pyo.ConcreteModel()
m.t = ContinuousSet(bounds=(0.0, 10.0))
- m.b = Param(initialize=0.25)
- m.c = Param(initialize=5.0)
+ m.b = pyo.Param(initialize=0.25)
+ m.c = pyo.Param(initialize=5.0)
- m.omega = Var(m.t)
- m.theta = Var(m.t)
+ m.omega = pyo.Var(m.t)
+ m.theta = pyo.Var(m.t)
m.domegadt = DerivativeVar(m.omega, wrt=m.t)
m.dthetadt = DerivativeVar(m.theta, wrt=m.t)
@@ -42,14 +42,14 @@ def create_model():
m.theta[0] = 3.14 - 0.1
def _diffeq1(m, t):
- return m.domegadt[t] == -m.b * m.omega[t] - m.c * sin(m.theta[t])
+ return m.domegadt[t] == -m.b * m.omega[t] - m.c * pyo.sin(m.theta[t])
- m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
def _diffeq2(m, t):
return m.dthetadt[t] == m.omega[t]
- m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
return m
@@ -65,7 +65,7 @@ def simulate_model(m):
tsim, profiles = sim.simulate(numpoints=100, integrator='vode')
# Discretize model using Orthogonal Collocation
- discretizer = TransformationFactory('dae.collocation')
+ discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=8, ncp=5)
# Initialize the discretized model using the simulator profiles
@@ -78,8 +78,8 @@ def plot_result(m, sim, tsim, profiles):
import matplotlib.pyplot as plt
time = list(m.t)
- omega = [value(m.omega[t]) for t in m.t]
- theta = [value(m.theta[t]) for t in m.t]
+ omega = [pyo.value(m.omega[t]) for t in m.t]
+ theta = [pyo.value(m.theta[t]) for t in m.t]
varorder = sim.get_variable_order()
diff --git a/examples/dae/simulator_ode_multindex_example.py b/examples/dae/simulator_ode_multindex_example.py
index b1b9111084b..81bba34061f 100644
--- a/examples/dae/simulator_ode_multindex_example.py
+++ b/examples/dae/simulator_ode_multindex_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -20,13 +20,13 @@
#
# Example modified to include time-varying values for b and c
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
from pyomo.dae.simulator import Simulator
def create_model():
- m = ConcreteModel()
+ m = pyo.ConcreteModel()
m.t = ContinuousSet(bounds=(0.0, 20.0))
@@ -35,17 +35,17 @@ def _b_default(m, t):
return 0.025
return 0.25
- m.b = Param(m.t, initialize=0.25, default=_b_default)
+ m.b = pyo.Param(m.t, initialize=0.25, default=_b_default)
def _c_default(m, t):
if t >= 7:
return 50
return 5
- m.c = Param(m.t, initialize=5.0, default=_c_default)
+ m.c = pyo.Param(m.t, initialize=5.0, default=_c_default)
- m.omega = Var(m.t)
- m.theta = Var(m.t)
+ m.omega = pyo.Var(m.t)
+ m.theta = pyo.Var(m.t)
m.domegadt = DerivativeVar(m.omega, wrt=m.t)
m.dthetadt = DerivativeVar(m.theta, wrt=m.t)
@@ -55,19 +55,19 @@ def _c_default(m, t):
m.theta[0] = 3.14 - 0.1
def _diffeq1(m, t):
- return m.domegadt[t] == -m.b[t] * m.omega[t] - m.c[t] * sin(m.theta[t])
+ return m.domegadt[t] == -m.b[t] * m.omega[t] - m.c[t] * pyo.sin(m.theta[t])
- m.diffeq1 = Constraint(m.t, rule=_diffeq1)
+ m.diffeq1 = pyo.Constraint(m.t, rule=_diffeq1)
def _diffeq2(m, t):
return m.dthetadt[t] == m.omega[t]
- m.diffeq2 = Constraint(m.t, rule=_diffeq2)
+ m.diffeq2 = pyo.Constraint(m.t, rule=_diffeq2)
b_profile = {0: 0.25, 15: 0.025}
c_profile = {0: 5.0, 7: 50}
- m.var_input = Suffix(direction=Suffix.LOCAL)
+ m.var_input = pyo.Suffix(direction=pyo.Suffix.LOCAL)
m.var_input[m.b] = b_profile
m.var_input[m.c] = c_profile
@@ -89,7 +89,7 @@ def simulate_model(m):
)
# Discretize model using Orthogonal Collocation
- discretizer = TransformationFactory('dae.collocation')
+ discretizer = pyo.TransformationFactory('dae.collocation')
discretizer.apply_to(m, nfe=20, ncp=3)
# Initialize the discretized model using the simulator profiles
@@ -102,8 +102,8 @@ def plot_result(m, sim, tsim, profiles):
import matplotlib.pyplot as plt
time = list(m.t)
- omega = [value(m.omega[t]) for t in m.t]
- theta = [value(m.theta[t]) for t in m.t]
+ omega = [pyo.value(m.omega[t]) for t in m.t]
+ theta = [pyo.value(m.theta[t]) for t in m.t]
varorder = sim.get_variable_order()
for idx, v in enumerate(varorder):
diff --git a/examples/dae/stochpdegas_automatic.py b/examples/dae/stochpdegas_automatic.py
index 397b4a18100..8251b4bfc97 100644
--- a/examples/dae/stochpdegas_automatic.py
+++ b/examples/dae/stochpdegas_automatic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,105 +14,109 @@
#
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-model = AbstractModel()
+model = pyo.AbstractModel()
# sets
-model.TF = Param(within=NonNegativeReals)
+model.TF = pyo.Param(within=pyo.NonNegativeReals)
def _tinit(m):
- return [0.5, value(m.TF)]
+ return [0.5, pyo.value(m.TF)]
# What it should be to match description in paper
- # return [0,value(m.TF)]
+ # return [0,pyo.value(m.TF)]
model.TIME = ContinuousSet(initialize=_tinit)
model.DIS = ContinuousSet(bounds=(0.0, 1.0))
-model.S = Param(within=PositiveIntegers)
-model.SCEN = RangeSet(1, model.S)
+model.S = pyo.Param(within=pyo.PositiveIntegers)
+model.SCEN = pyo.RangeSet(1, model.S)
# links
-model.LINK = Set(dimen=1)
-model.lstartloc = Param(model.LINK, within=Any)
-model.lendloc = Param(model.LINK, within=Any)
-model.ldiam = Param(model.LINK, within=PositiveReals, mutable=True)
-model.llength = Param(model.LINK, within=PositiveReals, mutable=True)
-model.ltype = Param(model.LINK, within=Any)
+model.LINK = pyo.Set(dimen=1)
+model.lstartloc = pyo.Param(model.LINK, within=pyo.Any)
+model.lendloc = pyo.Param(model.LINK, within=pyo.Any)
+model.ldiam = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.llength = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.ltype = pyo.Param(model.LINK, within=pyo.Any)
def link_a_init_rule(m):
return (l for l in m.LINK if m.ltype[l] == "a")
-model.LINK_A = Set(initialize=link_a_init_rule)
+model.LINK_A = pyo.Set(initialize=link_a_init_rule)
def link_p_init_rule(m):
return (l for l in m.LINK if m.ltype[l] == "p")
-model.LINK_P = Set(initialize=link_p_init_rule)
+model.LINK_P = pyo.Set(initialize=link_p_init_rule)
# nodes
-model.NODE = Set()
-model.pmin = Param(model.NODE, within=PositiveReals, mutable=True)
-model.pmax = Param(model.NODE, within=PositiveReals, mutable=True)
+model.NODE = pyo.Set()
+model.pmin = pyo.Param(model.NODE, within=pyo.PositiveReals, mutable=True)
+model.pmax = pyo.Param(model.NODE, within=pyo.PositiveReals, mutable=True)
# supply
-model.SUP = Set()
-model.sloc = Param(model.SUP, within=Any)
-model.smin = Param(model.SUP, within=NonNegativeReals, mutable=True)
-model.smax = Param(model.SUP, within=NonNegativeReals, mutable=True)
-model.scost = Param(model.SUP, within=NonNegativeReals)
+model.SUP = pyo.Set()
+model.sloc = pyo.Param(model.SUP, within=pyo.Any)
+model.smin = pyo.Param(model.SUP, within=pyo.NonNegativeReals, mutable=True)
+model.smax = pyo.Param(model.SUP, within=pyo.NonNegativeReals, mutable=True)
+model.scost = pyo.Param(model.SUP, within=pyo.NonNegativeReals)
# demand
-model.DEM = Set()
-model.dloc = Param(model.DEM, within=Any)
-model.d = Param(model.DEM, within=PositiveReals, mutable=True)
+model.DEM = pyo.Set()
+model.dloc = pyo.Param(model.DEM, within=pyo.Any)
+model.d = pyo.Param(model.DEM, within=pyo.PositiveReals, mutable=True)
# physical data
-model.eps = Param(initialize=0.025, within=PositiveReals)
-model.z = Param(initialize=0.80, within=PositiveReals)
-model.rhon = Param(initialize=0.72, within=PositiveReals)
-model.R = Param(initialize=8314.0, within=PositiveReals)
-model.M = Param(initialize=18.0, within=PositiveReals)
-model.pi = Param(initialize=3.14, within=PositiveReals)
-model.nu2 = Param(within=PositiveReals, mutable=True)
-model.lam = Param(model.LINK, within=PositiveReals, mutable=True)
-model.A = Param(model.LINK, within=NonNegativeReals, mutable=True)
-model.Tgas = Param(initialize=293.15, within=PositiveReals)
-model.Cp = Param(initialize=2.34, within=PositiveReals)
-model.Cv = Param(initialize=1.85, within=PositiveReals)
-model.gam = Param(initialize=model.Cp / model.Cv, within=PositiveReals)
-model.om = Param(initialize=(model.gam - 1.0) / model.gam, within=PositiveReals)
+model.eps = pyo.Param(initialize=0.025, within=pyo.PositiveReals)
+model.z = pyo.Param(initialize=0.80, within=pyo.PositiveReals)
+model.rhon = pyo.Param(initialize=0.72, within=pyo.PositiveReals)
+model.R = pyo.Param(initialize=8314.0, within=pyo.PositiveReals)
+model.M = pyo.Param(initialize=18.0, within=pyo.PositiveReals)
+model.pi = pyo.Param(initialize=3.14, within=pyo.PositiveReals)
+model.nu2 = pyo.Param(within=pyo.PositiveReals, mutable=True)
+model.lam = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.A = pyo.Param(model.LINK, within=pyo.NonNegativeReals, mutable=True)
+model.Tgas = pyo.Param(initialize=293.15, within=pyo.PositiveReals)
+model.Cp = pyo.Param(initialize=2.34, within=pyo.PositiveReals)
+model.Cv = pyo.Param(initialize=1.85, within=pyo.PositiveReals)
+model.gam = pyo.Param(initialize=model.Cp / model.Cv, within=pyo.PositiveReals)
+model.om = pyo.Param(initialize=(model.gam - 1.0) / model.gam, within=pyo.PositiveReals)
# scaling and constants
-model.ffac = Param(
- within=PositiveReals, initialize=(1.0e6 * model.rhon) / (24.0 * 3600.0)
+model.ffac = pyo.Param(
+ within=pyo.PositiveReals, initialize=(1.0e6 * model.rhon) / (24.0 * 3600.0)
)
-model.ffac2 = Param(within=PositiveReals, initialize=(3600.0) / (1.0e4 * model.rhon))
-model.pfac = Param(within=PositiveReals, initialize=1.0e5)
-model.pfac2 = Param(within=PositiveReals, initialize=1.0e-5)
-model.dfac = Param(within=PositiveReals, initialize=1.0e-3)
-model.lfac = Param(within=PositiveReals, initialize=1.0e3)
+model.ffac2 = pyo.Param(
+ within=pyo.PositiveReals, initialize=(3600.0) / (1.0e4 * model.rhon)
+)
+model.pfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e5)
+model.pfac2 = pyo.Param(within=pyo.PositiveReals, initialize=1.0e-5)
+model.dfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e-3)
+model.lfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e3)
-model.c1 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c2 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c3 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c4 = Param(within=PositiveReals, mutable=True)
+model.c1 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c2 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c3 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c4 = pyo.Param(within=pyo.PositiveReals, mutable=True)
# cost factors
-model.ce = Param(initialize=0.1, within=NonNegativeReals)
-model.cd = Param(initialize=1.0e6, within=NonNegativeReals)
-model.cT = Param(initialize=1.0e6, within=NonNegativeReals)
-model.cs = Param(initialize=0.0, within=NonNegativeReals)
-model.TDEC = Param(within=PositiveReals)
+model.ce = pyo.Param(initialize=0.1, within=pyo.NonNegativeReals)
+model.cd = pyo.Param(initialize=1.0e6, within=pyo.NonNegativeReals)
+model.cT = pyo.Param(initialize=1.0e6, within=pyo.NonNegativeReals)
+model.cs = pyo.Param(initialize=0.0, within=pyo.NonNegativeReals)
+model.TDEC = pyo.Param(within=pyo.PositiveReals)
# define stochastic info
-model.rand_d = Param(model.SCEN, model.DEM, within=NonNegativeReals, mutable=True)
+model.rand_d = pyo.Param(
+ model.SCEN, model.DEM, within=pyo.NonNegativeReals, mutable=True
+)
# convert units for input data
@@ -138,12 +142,12 @@ def rescale_rule(m):
m.pmax[i] = m.pmax[i] * m.pfac * m.pfac2 # from bar to Pascals and then to bar
-model.rescale = BuildAction(rule=rescale_rule)
+model.rescale = pyo.BuildAction(rule=rescale_rule)
def compute_constants(m):
for i in m.LINK:
- m.lam[i] = (2.0 * log10(3.7 * m.ldiam[i] / (m.eps * m.dfac))) ** (-2.0)
+ m.lam[i] = (2.0 * pyo.log10(3.7 * m.ldiam[i] / (m.eps * m.dfac))) ** (-2.0)
m.A[i] = (1.0 / 4.0) * m.pi * m.ldiam[i] * m.ldiam[i]
m.nu2 = m.gam * m.z * m.R * m.Tgas / m.M
m.c1[i] = (m.pfac2 / m.ffac2) * (m.nu2 / m.A[i])
@@ -157,7 +161,7 @@ def compute_constants(m):
m.c4 = (1 / m.ffac2) * (m.Cp * m.Tgas)
-model.compute_constants = BuildAction(rule=compute_constants)
+model.compute_constants = pyo.BuildAction(rule=compute_constants)
# set stochastic demands
@@ -172,7 +176,7 @@ def compute_demands_rule(m):
m.rand_d[k, j] = 1.3 * m.d[j]
-model.compute_demands = BuildAction(rule=compute_demands_rule)
+model.compute_demands = pyo.BuildAction(rule=compute_demands_rule)
def stochd_init(m, k, j, t):
@@ -191,11 +195,11 @@ def stochd_init(m, k, j, t):
return m.d[j]
-model.stochd = Param(
+model.stochd = pyo.Param(
model.SCEN,
model.DEM,
model.TIME,
- within=PositiveReals,
+ within=pyo.PositiveReals,
mutable=True,
default=stochd_init,
)
@@ -203,45 +207,47 @@ def stochd_init(m, k, j, t):
# define temporal variables
def p_bounds_rule(m, k, j, t):
- return (value(m.pmin[j]), value(m.pmax[j]))
+ return (pyo.value(m.pmin[j]), pyo.value(m.pmax[j]))
def p_init(m, k, j, t):
- return (value(m.pmax[j]) + value(m.pmin[j])) / 2
+ return (pyo.value(m.pmax[j]) + pyo.value(m.pmin[j])) / 2
-model.p = Var(
+model.p = pyo.Var(
model.SCEN, model.NODE, model.TIME, bounds=p_bounds_rule, initialize=p_init
)
-model.dp = Var(
+model.dp = pyo.Var(
model.SCEN, model.LINK_A, model.TIME, bounds=(0.0, 100.0), initialize=10.0
)
-model.fin = Var(
+model.fin = pyo.Var(
model.SCEN, model.LINK, model.TIME, bounds=(1.0, 500.0), initialize=100.0
)
-model.fout = Var(
+model.fout = pyo.Var(
model.SCEN, model.LINK, model.TIME, bounds=(1.0, 500.0), initialize=100.0
)
def s_bounds_rule(m, k, j, t):
- return (0.01, value(m.smax[j]))
+ return (0.01, pyo.value(m.smax[j]))
-model.s = Var(model.SCEN, model.SUP, model.TIME, bounds=s_bounds_rule, initialize=10.0)
-model.dem = Var(model.SCEN, model.DEM, model.TIME, initialize=100.0)
-model.pow = Var(
+model.s = pyo.Var(
+ model.SCEN, model.SUP, model.TIME, bounds=s_bounds_rule, initialize=10.0
+)
+model.dem = pyo.Var(model.SCEN, model.DEM, model.TIME, initialize=100.0)
+model.pow = pyo.Var(
model.SCEN, model.LINK_A, model.TIME, bounds=(0.0, 3000.0), initialize=1000.0
)
-model.slack = Var(
+model.slack = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(0.0, None), initialize=10.0
)
# define spatio-temporal variables
-model.px = Var(
+model.px = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(10.0, 100.0), initialize=50.0
)
-model.fx = Var(
+model.fx = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(1.0, 100.0), initialize=100.0
)
@@ -263,19 +269,19 @@ def powereq_rule(m, j, i, t):
)
-model.powereq = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=powereq_rule)
+model.powereq = pyo.Constraint(model.SCEN, model.LINK_A, model.TIME, rule=powereq_rule)
# cvar model
-model.cvar_lambda = Param(within=NonNegativeReals)
-model.nu = Var(initialize=100.0)
-model.phi = Var(model.SCEN, bounds=(0.0, None), initialize=100.0)
+model.cvar_lambda = pyo.Param(within=pyo.NonNegativeReals)
+model.nu = pyo.Var(initialize=100.0)
+model.phi = pyo.Var(model.SCEN, bounds=(0.0, None), initialize=100.0)
def cvarcost_rule(m):
return (1.0 / m.S) * sum((m.phi[k] / (1.0 - 0.95) + m.nu) for k in m.SCEN)
-model.cvarcost = Expression(rule=cvarcost_rule)
+model.cvarcost = pyo.Expression(rule=cvarcost_rule)
# node balances
@@ -289,7 +295,7 @@ def nodeeq_rule(m, k, i, t):
)
-model.nodeeq = Constraint(model.SCEN, model.NODE, model.TIME, rule=nodeeq_rule)
+model.nodeeq = pyo.Constraint(model.SCEN, model.NODE, model.TIME, rule=nodeeq_rule)
# boundary conditions flow
@@ -297,51 +303,57 @@ def flow_start_rule(m, j, i, t):
return m.fx[j, i, t, m.DIS.first()] == m.fin[j, i, t]
-model.flow_start = Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_start_rule)
+model.flow_start = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, rule=flow_start_rule
+)
def flow_end_rule(m, j, i, t):
return m.fx[j, i, t, m.DIS.last()] == m.fout[j, i, t]
-model.flow_end = Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_end_rule)
+model.flow_end = pyo.Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_end_rule)
# First PDE for gas network model
def flow_rule(m, j, i, t, k):
if t == m.TIME.first() or k == m.DIS.last():
- return Constraint.Skip # Do not apply pde at initial time or final location
+ return pyo.Constraint.Skip # Do not apply pde at initial time or final location
return (
m.dpxdt[j, i, t, k] / 3600 + m.c1[i] / m.llength[i] * m.dfxdx[j, i, t, k] == 0
)
-model.flow = Constraint(model.SCEN, model.LINK, model.TIME, model.DIS, rule=flow_rule)
+model.flow = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, model.DIS, rule=flow_rule
+)
# Second PDE for gas network model
def press_rule(m, j, i, t, k):
if t == m.TIME.first() or k == m.DIS.last():
- return Constraint.Skip # Do not apply pde at initial time or final location
+ return pyo.Constraint.Skip # Do not apply pde at initial time or final location
return (
m.dfxdt[j, i, t, k] / 3600
== -m.c2[i] / m.llength[i] * m.dpxdx[j, i, t, k] - m.slack[j, i, t, k]
)
-model.press = Constraint(model.SCEN, model.LINK, model.TIME, model.DIS, rule=press_rule)
+model.press = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, model.DIS, rule=press_rule
+)
def slackeq_rule(m, j, i, t, k):
if t == m.TIME.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
m.slack[j, i, t, k] * m.px[j, i, t, k]
== m.c3[i] * m.fx[j, i, t, k] * m.fx[j, i, t, k]
)
-model.slackeq = Constraint(
+model.slackeq = pyo.Constraint(
model.SCEN, model.LINK, model.TIME, model.DIS, rule=slackeq_rule
)
@@ -351,7 +363,7 @@ def presspas_start_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.first()] == m.p[j, m.lstartloc[i], t]
-model.presspas_start = Constraint(
+model.presspas_start = pyo.Constraint(
model.SCEN, model.LINK_P, model.TIME, rule=presspas_start_rule
)
@@ -360,7 +372,7 @@ def presspas_end_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.last()] == m.p[j, m.lendloc[i], t]
-model.presspas_end = Constraint(
+model.presspas_end = pyo.Constraint(
model.SCEN, model.LINK_P, model.TIME, rule=presspas_end_rule
)
@@ -370,7 +382,7 @@ def pressact_start_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.first()] == m.p[j, m.lstartloc[i], t] + m.dp[j, i, t]
-model.pressact_start = Constraint(
+model.pressact_start = pyo.Constraint(
model.SCEN, model.LINK_A, model.TIME, rule=pressact_start_rule
)
@@ -379,7 +391,7 @@ def pressact_end_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.last()] == m.p[j, m.lendloc[i], t]
-model.pressact_end = Constraint(
+model.pressact_end = pyo.Constraint(
model.SCEN, model.LINK_A, model.TIME, rule=pressact_end_rule
)
@@ -389,7 +401,7 @@ def suppress_rule(m, k, j, t):
return m.p[k, m.sloc[j], t] == m.pmin[m.sloc[j]]
-model.suppress = Constraint(model.SCEN, model.SUP, model.TIME, rule=suppress_rule)
+model.suppress = pyo.Constraint(model.SCEN, model.SUP, model.TIME, rule=suppress_rule)
# discharge pressure for compressors
@@ -397,22 +409,24 @@ def dispress_rule(m, j, i, t):
return m.p[j, m.lstartloc[i], t] + m.dp[j, i, t] <= m.pmax[m.lstartloc[i]]
-model.dispress = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=dispress_rule)
+model.dispress = pyo.Constraint(
+ model.SCEN, model.LINK_A, model.TIME, rule=dispress_rule
+)
# ss constraints
def flow_ss_rule(m, j, i, k):
if k == m.DIS.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dfxdx[j, i, m.TIME.first(), k] / m.llength[i] == 0.0
-model.flow_ss = Constraint(model.SCEN, model.LINK, model.DIS, rule=flow_ss_rule)
+model.flow_ss = pyo.Constraint(model.SCEN, model.LINK, model.DIS, rule=flow_ss_rule)
def pres_ss_rule(m, j, i, k):
if k == m.DIS.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
0.0
== -m.c2[i] / m.llength[i] * m.dpxdx[j, i, m.TIME.first(), k]
@@ -420,27 +434,29 @@ def pres_ss_rule(m, j, i, k):
)
-model.pres_ss = Constraint(model.SCEN, model.LINK, model.DIS, rule=pres_ss_rule)
+model.pres_ss = pyo.Constraint(model.SCEN, model.LINK, model.DIS, rule=pres_ss_rule)
# non-anticipativity constraints
def nonantdq_rule(m, j, i, t):
if j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if t >= m.TDEC + 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dp[j, i, t] == m.dp[1, i, t]
-model.nonantdq = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=nonantdq_rule)
+model.nonantdq = pyo.Constraint(
+ model.SCEN, model.LINK_A, model.TIME, rule=nonantdq_rule
+)
def nonantde_rule(m, j, i, t):
if j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if t >= m.TDEC + 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dem[j, i, t] == m.dem[1, i, t]
-model.nonantde = Constraint(model.SCEN, model.DEM, model.TIME, rule=nonantde_rule)
+model.nonantde = pyo.Constraint(model.SCEN, model.DEM, model.TIME, rule=nonantde_rule)
diff --git a/examples/doc/samples/__init__.py b/examples/doc/samples/__init__.py
index 0110902b288..af79da12d7f 100644
--- a/examples/doc/samples/__init__.py
+++ b/examples/doc/samples/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/doc/samples/case_studies/deer/DeerProblem.py b/examples/doc/samples/case_studies/deer/DeerProblem.py
index d09c9b53887..4da826fecb3 100644
--- a/examples/doc/samples/case_studies/deer/DeerProblem.py
+++ b/examples/doc/samples/case_studies/deer/DeerProblem.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,43 +9,43 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Model
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.p1 = Param()
-model.p2 = Param()
-model.p3 = Param()
-model.p4 = Param()
-model.p5 = Param()
-model.p6 = Param()
-model.p7 = Param()
-model.p8 = Param()
-model.p9 = Param()
-model.ps = Param()
+model.p1 = pyo.Param()
+model.p2 = pyo.Param()
+model.p3 = pyo.Param()
+model.p4 = pyo.Param()
+model.p5 = pyo.Param()
+model.p6 = pyo.Param()
+model.p7 = pyo.Param()
+model.p8 = pyo.Param()
+model.p9 = pyo.Param()
+model.ps = pyo.Param()
-model.f = Var(initialize=20, within=PositiveReals)
-model.d = Var(initialize=20, within=PositiveReals)
-model.b = Var(initialize=20, within=PositiveReals)
+model.f = pyo.Var(initialize=20, within=pyo.PositiveReals)
+model.d = pyo.Var(initialize=20, within=pyo.PositiveReals)
+model.b = pyo.Var(initialize=20, within=pyo.PositiveReals)
-model.hf = Var(initialize=20, within=PositiveReals)
-model.hd = Var(initialize=20, within=PositiveReals)
-model.hb = Var(initialize=20, within=PositiveReals)
+model.hf = pyo.Var(initialize=20, within=pyo.PositiveReals)
+model.hd = pyo.Var(initialize=20, within=pyo.PositiveReals)
+model.hb = pyo.Var(initialize=20, within=pyo.PositiveReals)
-model.br = Var(initialize=1.5, within=PositiveReals)
+model.br = pyo.Var(initialize=1.5, within=pyo.PositiveReals)
-model.c = Var(initialize=500000, within=PositiveReals)
+model.c = pyo.Var(initialize=500000, within=pyo.PositiveReals)
def obj_rule(amodel):
return 10 * amodel.hb + amodel.hd + amodel.hf
-model.obj = Objective(rule=obj_rule, sense=maximize)
+model.obj = pyo.Objective(rule=obj_rule, sense=pyo.maximize)
def f_bal_rule(amodel):
@@ -56,21 +56,21 @@ def f_bal_rule(amodel):
)
-model.f_bal = Constraint(rule=f_bal_rule)
+model.f_bal = pyo.Constraint(rule=f_bal_rule)
def d_bal_rule(amodel):
return amodel.d == amodel.p4 * amodel.d + amodel.p5 / 2.0 * amodel.f - amodel.hd
-model.d_bal = Constraint(rule=d_bal_rule)
+model.d_bal = pyo.Constraint(rule=d_bal_rule)
def b_bal_rule(amodel):
return amodel.b == amodel.p6 * amodel.b + amodel.p5 / 2.0 * amodel.f - amodel.hb
-model.b_bal = Constraint(rule=b_bal_rule)
+model.b_bal = pyo.Constraint(rule=b_bal_rule)
def food_cons_rule(amodel):
@@ -79,25 +79,25 @@ def food_cons_rule(amodel):
)
-model.food_cons = Constraint(rule=food_cons_rule)
+model.food_cons = pyo.Constraint(rule=food_cons_rule)
def supply_rule(amodel):
return amodel.c <= amodel.ps
-model.supply = Constraint(rule=supply_rule)
+model.supply = pyo.Constraint(rule=supply_rule)
def birth_rule(amodel):
return amodel.br == 1.1 + 0.8 * (amodel.ps - amodel.c) / amodel.ps
-model.birth = Constraint(rule=birth_rule)
+model.birth = pyo.Constraint(rule=birth_rule)
def proc_rule(amodel):
return amodel.b >= 1.0 / 5.0 * (0.4 * amodel.f + amodel.d)
-model.proc = Constraint(rule=proc_rule)
+model.proc = pyo.Constraint(rule=proc_rule)
diff --git a/examples/doc/samples/case_studies/diet/DietProblem.py b/examples/doc/samples/case_studies/diet/DietProblem.py
index 64624310943..4652ff1a222 100644
--- a/examples/doc/samples/case_studies/diet/DietProblem.py
+++ b/examples/doc/samples/case_studies/diet/DietProblem.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,26 +9,26 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.foods = Set()
-model.nutrients = Set()
-model.costs = Param(model.foods)
-model.min_nutrient = Param(model.nutrients)
-model.max_nutrient = Param(model.nutrients)
-model.volumes = Param(model.foods)
-model.max_volume = Param()
-model.nutrient_value = Param(model.nutrients, model.foods)
-model.amount = Var(model.foods, within=NonNegativeReals)
+model.foods = pyo.Set()
+model.nutrients = pyo.Set()
+model.costs = pyo.Param(model.foods)
+model.min_nutrient = pyo.Param(model.nutrients)
+model.max_nutrient = pyo.Param(model.nutrients)
+model.volumes = pyo.Param(model.foods)
+model.max_volume = pyo.Param()
+model.nutrient_value = pyo.Param(model.nutrients, model.foods)
+model.amount = pyo.Var(model.foods, within=pyo.NonNegativeReals)
def costRule(model):
return sum(model.costs[n] * model.amount[n] for n in model.foods)
-model.cost = Objective(rule=costRule)
+model.cost = pyo.Objective(rule=costRule)
def volumeRule(model):
@@ -37,7 +37,7 @@ def volumeRule(model):
)
-model.volume = Constraint(rule=volumeRule)
+model.volume = pyo.Constraint(rule=volumeRule)
def nutrientRule(model, n):
@@ -45,4 +45,4 @@ def nutrientRule(model, n):
return (model.min_nutrient[n], value, model.max_nutrient[n])
-model.nutrientConstraint = Constraint(model.nutrients, rule=nutrientRule)
+model.nutrientConstraint = pyo.Constraint(model.nutrients, rule=nutrientRule)
diff --git a/examples/doc/samples/case_studies/diet/DietProblem.tex b/examples/doc/samples/case_studies/diet/DietProblem.tex
index d933e097d88..9eaa7d68e9f 100644
--- a/examples/doc/samples/case_studies/diet/DietProblem.tex
+++ b/examples/doc/samples/case_studies/diet/DietProblem.tex
@@ -10,53 +10,53 @@ \subsection*{Build the model}
\hspace*{5mm}We begin our Pyomo model with
\begin{verbatim}
-from pyomo.core import *
+import pyomo.environ as pyo
\end{verbatim}
\noindent
to import the Pyomo package for use in the code. The next step is to create an object of the model class, which by convention we call âmodel.â We implement this by writing
-\begin{verbatim}model = AbstractModel() \end{verbatim}
+\begin{verbatim}model = pyo.AbstractModel() \end{verbatim}
\noindent
The rest of our work will be contained within this object.
In the diet problem, there are two main sets that we are looking at: the set of foods and the set of nutrients, which we define as
-\begin{verbatim}model.foods = Set()
-model.nutrients = Set()\end{verbatim}
+\begin{verbatim}model.foods = pyo.Set()
+model.nutrients = pyo.Set()\end{verbatim}
Both of these sets could be very large (arguably, the set of all foods is unbounded); however, for implementing the model in Pyomo, this is irrelevant. It is in the data file that the information for these sets is filled in.
The solution to the diet problem involves minimizing the amount of money we are spending on food. Obviously, to do this we must know the cost of each kind of food. To do this, we create a one dimensional parameter that measures the cost associated with each food:
-\begin{verbatim}model.costs = Param(model.foods)\end{verbatim}
+\begin{verbatim}model.costs = pyo.Param(model.foods)\end{verbatim}
\noindent
This says that for each food, there is a cost associated with it, which will be implemented later when we construct the data file.
Similarly, each nutrient has a minimum and maximum requirement (note that for some nutrients the maximum is arbitrarily large). We can emulate the code for cost to create two one dimensional variables, each over nutrients.
-\begin{verbatim}model.min_nutrient=Param(model.nutrients)
-model.max_nutrient=Param(model.nutrients)\end{verbatim}
+\begin{verbatim}model.min_nutrient=pyo.Param(model.nutrients)
+model.max_nutrient=pyo.Param(model.nutrients)\end{verbatim}
For this model, we also want to consider how much food a person can reasonably consume---the solution is useless if no person can eat that much. Thus, we add a volume parameter over the set of foods. This is done similarly to the previous examples.
-\begin{verbatim}model.volumes=Param(model.foods)\end{verbatim}
+\begin{verbatim}model.volumes=pyo.Param(model.foods)\end{verbatim}
We also need a parameter for the max volume of food that can be consumed. We do this like the previous examples but without a set that the parameter is over. This is because the max volume of food consumed is independent of either food or nutrients. We input
-\begin{verbatim}model.max_volume=Param()\end{verbatim}
+\begin{verbatim}model.max_volume=pyo.Param()\end{verbatim}
There's one last parameter that must be taken into consideration: how much of each nutrient each food contains. Unlike the previous examples, this parameter is in two dimensions---it is over both the set of foods and the set of nutrients. This just requires a small change in the code.
-\begin{verbatim}model.nutrient_value=Param(model.nutrients, model.foods) \end{verbatim}
+\begin{verbatim}model.nutrient_value=pyo.Param(model.nutrients, model.foods) \end{verbatim}
The comma indicates that this parameter is over two different sets, and thus is in two dimensions. When we create the data file, we will be able to fill in how much of each nutrient each food contains.
-At this point we have defined our sets and parameters. However, we have yet to cosnider the amount of food to be bought and eaten. This is the variable weâre trying to solve for, and thus we create an object of the variable class. Since this is just recording how much food to purchase, we create a one dimensional variable over food:
+At this point we have defined our sets and parameters. However, we have yet to consider the amount of food to be bought and eaten. This is the variable weâre trying to solve for, and thus we create an object of the variable class. Since this is just recording how much food to purchase, we create a one dimensional variable over food:
-\begin{verbatim}model.amount=Var(model.foods, within = NonNegativeReals) \end{verbatim}
+\begin{verbatim}model.amount=pyo.Var(model.foods, within = pyo.NonNegativeReals) \end{verbatim}
We restrict our domain to the non-negative reals. If we accepted negative numbers than the model could tell us to buy negative amounts of food, which is an unrealistic---and thus useless---model. We could further restrict the domain to the integers to make it more realistic, but that would make the problem much harder for little gain: if this model is used on a large scale than the difference between the integer solution and the non-integer solution is often irrelevant.
@@ -71,7 +71,7 @@ \subsection*{Build the model}
\noindent
which will go through and multiply the costs and amounts of each food together and then take their sum as outlined above. We must include another line, though:
-\begin{verbatim}model.cost=Objective(rule=costRule) \end{verbatim}
+\begin{verbatim}model.cost=pyo.Objective(rule=costRule) \end{verbatim}
This line defines the objective of the model as the costRule, which Pyomo interprets as the value it needs to minimize; in this case it will minimize our costs. Also, as a note, we defined the objective as ``model.cost'' which is not to be confused with the parameter we defined earlier as ``model.costs,'' despite their similar names. These are two different values and accidentally giving them the same name will cause problems when trying to solve the problem.
@@ -81,7 +81,7 @@ \subsection*{Build the model}
return sum(model.volumes[n]*model.amount[n] for n in
model.foods) <= model.max_volume
-model.volume = Constraint(rule=volumeRule)
+model.volume = pyo.Constraint(rule=volumeRule)
\end{verbatim}
Note that here we have a constraint instead of an objective. This requires that the rule returns true, but otherwise the value is irrelevant. While objective looks for the least value, constraints just require that a value works.
@@ -94,7 +94,7 @@ \subsection*{Build the model}
for f in model.foods)
return (model.min_nutrient[n], value, model.max_nutrient[n])
-model.nutrientConstraint = Constraint(model.nutrients, rule=nutrientRule)
+model.nutrientConstraint = pyo.Constraint(model.nutrients, rule=nutrientRule)
\end{verbatim}
The rule itself will act much like the previous rules, but by adding an index into the constraint we will cycle through each of the nutrients. Essentially, what we have done is compressed many ``nutrient rules,'' each of which acts the same, into one rule that will look at each nutrient individually.
diff --git a/examples/doc/samples/case_studies/diet/README.txt b/examples/doc/samples/case_studies/diet/README.txt
index c30e963dc27..111d257b3f6 100644
--- a/examples/doc/samples/case_studies/diet/README.txt
+++ b/examples/doc/samples/case_studies/diet/README.txt
@@ -8,13 +8,13 @@ We begin our Pyomo model with
{{{
#!python
-from pyomo.core import *
+import pyomo.environ as pyo
}}}
to import the Pyomo package for use in the code. The next step is to create an object of the model class, which by convention we call "`model`" We implement this by writing
{{{
#!python
-model = AbstractModel()
+model = pyo.AbstractModel()
}}}
The rest of our work will be contained within this object.
@@ -22,8 +22,8 @@ In the diet problem, there are two main sets that we are looking at: the set of
{{{
#!python
-model.foods = Set()
-model.nutrients = Set()
+model.foods = pyo.Set()
+model.nutrients = pyo.Set()
}}}
Both of these sets could be very large (arguably, the set of all foods is unbounded); however, for implementing the model in Pyomo, this is irrelevant. It is in the data file that the information for these sets is filled in.
@@ -32,7 +32,7 @@ The solution to the diet problem involves minimizing the amount of money we are
{{{
#!python
-model.costs = Param(model.foods)
+model.costs = pyo.Param(model.foods)
}}}
This says that for each food, there is a cost associated with it, which will be implemented later when we construct the data file.
@@ -41,38 +41,38 @@ Similarly, each nutrient has a minimum and maximum requirement (note that for so
{{{
#!python
-model.min_nutrient=Param(model.nutrients)
-model.max_nutrient=Param(model.nutrients)
+model.min_nutrient=pyo.Param(model.nutrients)
+model.max_nutrient=pyo.Param(model.nutrients)
}}}
For this model, we also want to consider how much food a person can reasonably consume---the solution is useless if no person can eat that much. Thus, we add a volume parameter over the set of foods. This is done similarly to the previous examples.
{{{
#!python
-model.volumes=Param(model.foods)
+model.volumes=pyo.Param(model.foods)
}}}
We also need a parameter for the max volume of food that can be consumed. We do this like the previous examples but without a set that the parameter is over. This is because the max volume of food consumed is independent of either food or nutrients. We input
{{{
#!python
-model.max_volume=Param()
+model.max_volume=pyo.Param()
}}}
There's one last parameter that must be taken into consideration: how much of each nutrient each food contains. Unlike the previous examples, this parameter is in two dimensions--it is over both the set of foods and the set of nutrients. This just requires a small change in the code.
{{{
#!python
-model.nutrient_value=Param(model.nutrients, model.foods)
+model.nutrient_value=pyo.Param(model.nutrients, model.foods)
}}}
The comma indicates that this parameter is over two different sets, and thus is in two dimensions. When we create the data file, we will be able to fill in how much of each nutrient each food contains.
-At this point we have defined our sets and parameters. However, we have yet to cosnider the amount of food to be bought and eaten. This is the variable we're trying to solve for, and thus we create an object of the variable class. Since this is just recording how much food to purchase, we create a one dimensional variable over food:
+At this point we have defined our sets and parameters. However, we have yet to consider the amount of food to be bought and eaten. This is the variable we're trying to solve for, and thus we create an object of the variable class. Since this is just recording how much food to purchase, we create a one dimensional variable over food:
{{{
#!python
-model.amount=Var(model.foods, within = NonNegativeReals)
+model.amount=pyo.Var(model.foods, within = pyo.NonNegativeReals)
}}}
We restrict our domain to the non-negative reals. If we accepted negative numbers than the model could tell us to buy negative amounts of food, which is an unrealistic--and thus useless--model. We could further restrict the domain to the integers to make it more realistic, but that would make the problem much harder for little gain: if this model is used on a large scale than the difference between the integer solution and the non-integer solution is often irrelevant.
@@ -90,7 +90,7 @@ which will go through and multiply the costs and amounts of each food together a
{{{
#!python
-model.cost=Objective(rule=costRule
+model.cost=pyo.Objective(rule=costRule
}}}
This line defines the objective of the model as the costRule, which Pyomo interprets as the value it needs to minimize; in this case it will minimize our costs. Also, as a note, we defined the objective as "model.cost" which is not to be confused with the parameter we defined earlier as `"model.costs" despite their similar names. These are two different values and accidentally giving them the same name will cause problems when trying to solve the problem.
@@ -102,7 +102,7 @@ We must also create a rule for the volume consumed. The construction of this ru
def volumeRule(model):
return sum(model.volumes[n]*model.amount[n] for n in model.foods) <= model.max_volume
-model.volume = Constraint(rule=volumeRule)
+model.volume = pyo.Constraint(rule=volumeRule)
}}}
Note that here we have a constraint instead of an objective. This requires that the rule returns true, but otherwise the value is irrelevant. While objective looks for the least value, constraints just require that a value works.
@@ -116,7 +116,7 @@ def nutrientRule(n, model):
for f in model.foods)
return (model.min_nutrient[n], value, model.max_nutrient[n])
-model.nutrientConstraint = Constraint(model.nutrients, rule=nutrientRule)
+model.nutrientConstraint = pyo.Constraint(model.nutrients, rule=nutrientRule)
}}}
The rule itself will act much like the previous rules, but by adding an index into the constraint we will cycle through each of the nutrients. Essentially, what we have done is compressed many "nutrient rules," each of which acts the same, into one rule that will look at each nutrient individually.
diff --git a/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py b/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
index 6a0edb38350..22cf8f185e7 100644
--- a/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
+++ b/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,27 +9,27 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.S_SI = Set(ordered=True)
+model.S_SI = pyo.Set(ordered=True)
-model.P_REP_CASES = Param(model.S_SI)
-model.P_POP = Param()
+model.P_REP_CASES = pyo.Param(model.S_SI)
+model.P_POP = pyo.Param()
-model.I = Var(model.S_SI, bounds=(0, model.P_POP), initialize=1)
-model.S = Var(model.S_SI, bounds=(0, model.P_POP), initialize=300)
-model.beta = Var(bounds=(0.05, 70))
-model.alpha = Var(bounds=(0.5, 1.5))
-model.eps_I = Var(model.S_SI, initialize=0.0)
+model.I = pyo.Var(model.S_SI, bounds=(0, model.P_POP), initialize=1)
+model.S = pyo.Var(model.S_SI, bounds=(0, model.P_POP), initialize=300)
+model.beta = pyo.Var(bounds=(0.05, 70))
+model.alpha = pyo.Var(bounds=(0.5, 1.5))
+model.eps_I = pyo.Var(model.S_SI, initialize=0.0)
def _objective(model):
return sum((model.eps_I[i]) ** 2 for i in model.S_SI)
-model.objective = Objective(rule=_objective, sense=minimize)
+model.objective = pyo.Objective(rule=_objective, sense=pyo.minimize)
def _InfDynamics(model, i):
@@ -41,7 +41,7 @@ def _InfDynamics(model, i):
)
-model.InfDynamics = Constraint(model.S_SI, rule=_InfDynamics)
+model.InfDynamics = pyo.Constraint(model.S_SI, rule=_InfDynamics)
def _SusDynamics(model, i):
@@ -49,11 +49,11 @@ def _SusDynamics(model, i):
return model.S[i] == model.S[i - 1] - model.I[i]
-model.SusDynamics = Constraint(model.S_SI, rule=_SusDynamics)
+model.SusDynamics = pyo.Constraint(model.S_SI, rule=_SusDynamics)
def _Data(model, i):
return model.P_REP_CASES[i] == model.I[i] + model.eps_I[i]
-model.Data = Constraint(model.S_SI, rule=_Data)
+model.Data = pyo.Constraint(model.S_SI, rule=_Data)
diff --git a/examples/doc/samples/case_studies/max_flow/MaxFlow.py b/examples/doc/samples/case_studies/max_flow/MaxFlow.py
index 1e75fa4e79d..957b39e8a7e 100644
--- a/examples/doc/samples/case_studies/max_flow/MaxFlow.py
+++ b/examples/doc/samples/case_studies/max_flow/MaxFlow.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,18 +9,18 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.nodes = Set()
-model.arcs = Set(within=model.nodes * model.nodes)
-model.sources = Set(within=model.nodes)
-model.sinks = Set(within=model.nodes)
-model.upperBound = Param(model.arcs)
-model.supply = Param(model.sources)
-model.demand = Param(model.sinks)
-model.amount = Var(model.arcs, within=NonNegativeReals)
+model.nodes = pyo.Set()
+model.arcs = pyo.Set(within=model.nodes * model.nodes)
+model.sources = pyo.Set(within=model.nodes)
+model.sinks = pyo.Set(within=model.nodes)
+model.upperBound = pyo.Param(model.arcs)
+model.supply = pyo.Param(model.sources)
+model.demand = pyo.Param(model.sinks)
+model.amount = pyo.Var(model.arcs, within=pyo.NonNegativeReals)
def totalRule(model):
@@ -28,7 +28,7 @@ def totalRule(model):
return expression
-model.maxFlow = Objective(rule=totalRule, sense=maximize)
+model.maxFlow = pyo.Objective(rule=totalRule, sense=pyo.maximize)
def maxRule(model, arcIn, arcOut):
@@ -36,7 +36,7 @@ def maxRule(model, arcIn, arcOut):
return constraint_equation
-model.loadOnArc = Constraint(model.arcs, rule=maxRule)
+model.loadOnArc = pyo.Constraint(model.arcs, rule=maxRule)
def flowRule(model, node):
@@ -56,4 +56,4 @@ def flowRule(model, node):
return constraint_equation
-model.flow = Constraint(model.nodes, rule=flowRule)
+model.flow = pyo.Constraint(model.nodes, rule=flowRule)
diff --git a/examples/doc/samples/case_studies/max_flow/MaxFlow.tex b/examples/doc/samples/case_studies/max_flow/MaxFlow.tex
index 417b0093652..ad2242e2fa5 100644
--- a/examples/doc/samples/case_studies/max_flow/MaxFlow.tex
+++ b/examples/doc/samples/case_studies/max_flow/MaxFlow.tex
@@ -25,23 +25,23 @@ \subsection*{Build the model}
As always, start by importing Pyomo and creating an object of the class model.
\begin{verbatim}
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
\end{verbatim}
Now, we must define our sets. The set of locations, which we'll call nodes, is fairly typical. Additionally, we must create a set of arcs. Since each arc is a tuple from the set of nodes crossed with itself, we must define it slightly differently. This is very similar to how we defined the routes in the first network flow problem---in fact, the only difference is the names of the sets.
\begin{verbatim}
-model.nodes = Set()
-model.arcs = Set(within=model.nodes*model.nodes)
+model.nodes = pyo.Set()
+model.arcs = pyo.Set(within=model.nodes*model.nodes)
\end{verbatim}
The ``within='' notation implies that we're creating a subset of something else---in this case arcs is a subset of all the tuples that could be generated by the nodes crossed with themselves. This is important since the set of sources and sinks are going to be defined as subsets of the set of nodes. In code, this looks like:
\begin{verbatim}
-model.sources = Set(within=model.nodes)
-model.sinks = Set(within=model.nodes)
+model.sources = pyo.Set(within=model.nodes)
+model.sinks = pyo.Set(within=model.nodes)
\end{verbatim}
\noindent
@@ -50,25 +50,25 @@ \subsection*{Build the model}
We now consider the parameters. Each arc has an upper bound on how many families can travel along it, so we create a parameter over the set of arcs.
\begin{verbatim}
-model.upperBound = Param(model.arcs)
+model.upperBound = pyo.Param(model.arcs)
\end{verbatim}
We will also create a supply parameter over the set of sources and a demand parameter for the sinks. Since we're just looking for the max supply in this problem, the supply parameter will be arbitrarily large and the demand parameter will be $0$ when we define them in the data file. This way, the program won't accidentally crash with an infeasible model and we can guarantee we achieve the max flow. However, in other cases it might be useful to have an explicit number for the supply at each source or demand at each sink, so we include it to make the model more general.
\begin{verbatim}
-model.supply = Param(model.sources)
-model.demand = Param(model.sinks)
+model.supply = pyo.Param(model.sources)
+model.demand = pyo.Param(model.sinks)
\end{verbatim}
Finally, we need to define a variable. Like the previous examples, this variable will be the amount that goes along each arc; in this case it will be how many families travel on each path between the zoo and Home. As usual, we restrict the domain to non negative numbers since, simply put, negative families don't make sense.
\begin{verbatim}
-model.amount = Var(model.arcs, within=NonNegativeReals)
+model.amount = pyo.Var(model.arcs, within=pyo.NonNegativeReals)
\end{verbatim}
At this point, we must now begin constructing the objective and constraints. The objective of this problem is to maximize the number of people flowing into Home, which is a very different objective than what we've done before; unlike the previous cases, we're not trying to minimize a value. Additionally, in previous examples we would just take the dot product of the cost and amount vectors, which isn't helpful in this case.
-Solving these two problems is pretty simple, fortunately. To begin with, to maximize the objective we just insert ``sense=maximize'' into the arguments the objective takes, which will tell the model to try and maximize this value. Similarly, we could have put ``sense=minimize'' in the previous examples, but since the objective naturally tries to minimize the rule it takes in, this would be redundant.
+Solving these two problems is pretty simple, fortunately. To begin with, to maximize the objective we just insert ``sense=pyo.maximize'' into the arguments the objective takes, which will tell the model to try and maximize this value. Similarly, we could have put ``sense=pyo.minimize'' in the previous examples, but since the objective naturally tries to minimize the rule it takes in, this would be redundant.
The other problem we ran into was how to measure the number of people who arrive at Home. The most logical way to do this is take every arc that ends at home, find the amount of people traveling along it, and sum those values together. For the code, though, we're being a bit more general since in this abstract model there could be multiple sinks (rather than just Home). The logic is still the same: just find the amount traveling on each arc that goes into a sink and add those values together.
@@ -81,7 +81,7 @@ \subsection*{Build the model}
)
return expression
-model.maxFlow = Objective(rule=totalRule, sense=maximize)
+model.maxFlow = pyo.Objective(rule=totalRule, sense=pyo.maximize)
\end{verbatim}
Another important element of this model is the maximum amount that can travel on each route. Without that, the max flow problem would be trivial: the answer is always infinity! To avoid this situation, we need to ensure that the amount traveling along each arc is less than or equal to the upper bound of how much can move along the arc. One part that deserves note is that we give the constraint the set of arcs as an argument, but in defining the rule we give it two arguments: arcIn and arcOut. The reason for this is because the set of arcs is itself a set of tuples, so when we feed it in as an argument we're actually supplying two arguments. The final result will be this:
@@ -92,7 +92,7 @@ \subsection*{Build the model}
<= model.upperBound[arcIn, arcOut])
return constraint_equation
-model.loadOnArc = Constraint(model.arcs, rule=maxRule)
+model.loadOnArc = pyo.Constraint(model.arcs, rule=maxRule)
\end{verbatim}
We have one last rule to consider: the flow rule. The idea behind the flow rule is that something traveling along the network won't just appear or disappear. The amount that flows into a location must be equal to the amount that flows out, with the exception of sinks and sources. It's this last part that makes the constraint complicated since we now have three cases---the node is regular, a source or a sink---that must each be treated slightly differently.
@@ -114,7 +114,7 @@ \subsection*{Build the model}
return constraint_equation
-model.flow = Constraint(model.nodes, rule=flowRule)
+model.flow = pyo.Constraint(model.nodes, rule=flowRule)
\end{verbatim}
@@ -194,7 +194,7 @@ \subsection*{Build the model}
return constraint_equation
-model.flow = Constraint(model.nodes, rule=flowRule)
+model.flow = pyo.Constraint(model.nodes, rule=flowRule)
\end{verbatim}
Save this model as a .py file before continuing.
diff --git a/examples/doc/samples/case_studies/max_flow/README.txt b/examples/doc/samples/case_studies/max_flow/README.txt
index 985a702d623..dcd16ba2f14 100644
--- a/examples/doc/samples/case_studies/max_flow/README.txt
+++ b/examples/doc/samples/case_studies/max_flow/README.txt
@@ -16,25 +16,25 @@ As always, start by importing Pyomo and creating an object of the class model.
{{{
#!python
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
}}}
Now, we must define our sets. The set of locations, which we'll call nodes, is fairly typical. Additionally, we must create a set of arcs. Since each arc is a tuple from the set of nodes crossed with itself, we must define it slightly differently. This is very similar to how we defined the routes in the first network flow problem--in fact, the only difference is the names of the sets.
{{{
#!python
-model.nodes = Set()
-model.arcs = Set(within=model.nodes*model.nodes)
+model.nodes = pyo.Set()
+model.arcs = pyo.Set(within=model.nodes*model.nodes)
}}}
The "within=" notation implies that we're creating a subset of something else--in this case arcs is a subset of all the tuples that could be generated by the nodes crossed with themselves. This is important since the set of sources and sinks are going to be defined as subsets of the set of nodes. In code, this looks like:
{{{
#!python
-model.sources = Set(within=model.nodes)
-model.sinks = Set(within=model.nodes)
+model.sources = pyo.Set(within=model.nodes)
+model.sinks = pyo.Set(within=model.nodes)
}}}
While we only have one source and sink in this example, it's often useful to create a more general model than necessary. This same model can be used next week to find the maximum flow between three office building and four residential areas, for example.
@@ -42,27 +42,27 @@ We now consider the parameters. Each arc has an upper bound on how many familie
{{{
#!python
-model.upperBound = Param(model.arcs)
+model.upperBound = pyo.Param(model.arcs)
}}}
We will also create a supply parameter over the set of sources and a demand parameter for the sinks. Since we're just looking for the max supply in this problem, the supply parameter will be arbitrarily large and the demand parameter will be 0 when we define them in the data file. This way, the program won't accidentally crash with an infeasible model and we can guarantee we achieve the max flow. However, in other cases it might be useful to have an explicit number for the supply at each source or demand at each sink, so we include it to make the model more general.
{{{
#!python
-model.supply = Param(model.sources)
-model.demand = Param(model.sinks)
+model.supply = pyo.Param(model.sources)
+model.demand = pyo.Param(model.sinks)
}}}
Finally, we need to define a variable. Like the previous examples, this variable will be the amount that goes along each arc; in this case it will be how many families travel on each path between the zoo and Home. As usual, we restrict the domain to non negative numbers since, simply put, negative families don't make sense.
{{{
#!python
-model.amount = Var(model.arcs, within=NonNegativeReals)
+model.amount = pyo.Var(model.arcs, within=pyo.NonNegativeReals)
}}}
At this point, we must now begin constructing the objective and constraints. The objective of this problem is to maximize the number of people flowing into Home, which is a very different objective than what we've done before; unlike the previous cases, we're not trying to minimize a value. Additionally, in previous examples we would just take the dot product of the cost and amount vectors, which isn't helpful in this case.
-Solving these two problems is pretty simple, fortunately. To begin with, to maximize the objective we just insert "sense=maximize" into the arguments the objective takes, which will tell the model to try and maximize this value. Similarly, we could have put "sense=minimize" in the previous examples, but since the objective naturally tries to minimize the rule it takes in, this would be redundant.
+Solving these two problems is pretty simple, fortunately. To begin with, to maximize the objective we just insert "sense=pyo.maximize" into the arguments the objective takes, which will tell the model to try and maximize this value. Similarly, we could have put "sense=pyo.minimize" in the previous examples, but since the objective naturally tries to minimize the rule it takes in, this would be redundant.
The other problem we ran into was how to measure the number of people who arrive at Home. The most logical way to do this is take every arc that ends at home, find the amount of people traveling along it, and sum those values together. For the code, though, we're being a bit more general since in this abstract model there could be multiple sinks (rather than just Home). The logic is still the same: just find the amount traveling on each arc that goes into a sink and add those values together.
@@ -76,7 +76,7 @@ def totalRule(model):
)
return expression
-model.maxFlow = Objective(rule=totalRule, sense=maximize)
+model.maxFlow = pyo.Objective(rule=totalRule, sense=pyo.maximize)
}}}
Another important element of this model is the maximum amount that can travel on each route. Without that, the max flow problem would be trivial: the answer is always infinity! To avoid this situation, we need to ensure that the amount traveling along each arc is less than or equal to the upper bound of how much can move along the arc. One part that deserves note is that we give the constraint the set of arcs as an argument, but in defining the rule we give it two arguments: arcIn and arcOut. The reason for this is because the set of arcs is itself a set of tuples, so when we feed it in as an argument we're actually supplying two arguments. The final result will be this:
@@ -88,7 +88,7 @@ def maxRule(arcIn, arcOut, model):
<= model.upperBound[arcIn, arcOut])
return constraint_equation
-model.loadOnArc = Constraint(model.arcs, rule=maxRule)
+model.loadOnArc = pyo.Constraint(model.arcs, rule=maxRule)
}}}
We have one last rule to consider: the flow rule. The idea behind the flow rule is that something traveling along the network won't just appear or disappear. The amount that flows into a location must be equal to the amount that flows out, with the exception of sinks and sources. It's this last part that makes the constraint complicated since we now have three cases--the node is regular, a source or a sink--that must each be treated slightly differently.
@@ -111,7 +111,7 @@ def flowRule(node, model):
return constraint_equation
-model.flow = Constraint(model.nodes, rule=flowRule)
+model.flow = pyo.Constraint(model.nodes, rule=flowRule)
}}}
@@ -195,7 +195,7 @@ def flowRule(node, model):
return constraint_equation
-model.flow = Constraint(model.nodes, rule=flowRule)
+model.flow = pyo.Constraint(model.nodes, rule=flowRule)
}}}
Save this model as a .py file before continuing.
diff --git a/examples/doc/samples/case_studies/network_flow/README.txt b/examples/doc/samples/case_studies/network_flow/README.txt
index 137138a6fdc..f2038912961 100644
--- a/examples/doc/samples/case_studies/network_flow/README.txt
+++ b/examples/doc/samples/case_studies/network_flow/README.txt
@@ -14,17 +14,17 @@ We begin this model as we always do
{{{
#!python
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
}}}
Now we must define our sets. In the transportation problem, we had a set for the warehouses and a set for the stores. In this example, we're going to be more sophisticated: we're going to just have one set for all the locations. Additionally, we're going to have one set that holds all of the different routes between these locations. This construction will help later when creating the constraints and is a more typical model for a network flow problem: we care about the nodes and arcs, so it makes sense to make those the sets. The code is a little different than what we've done before.
{{{
#!python
-model.places = Set()
-model.routes = Set(within=model.places*model.places)
+model.places = pyo.Set()
+model.routes = pyo.Set(within=model.places*model.places)
}}}
While the definition for the set "places" should be familiar, how we defined "routes" is a bit more foreign. By saying
@@ -38,25 +38,25 @@ The parameters are fairly straightforward after this point. Each place has an a
{{{
#!python
-model.supply = Param(model.places)
-model.demand = Param(model.places)
-model.cost = Param(model.routes)
-model.minimum = Param(model.routes)
-model.maximum = Param(model.routes)
+model.supply = pyo.Param(model.places)
+model.demand = pyo.Param(model.places)
+model.cost = pyo.Param(model.routes)
+model.minimum = pyo.Param(model.routes)
+model.maximum = pyo.Param(model.routes)
}}}
Now to define our variables. We're trying to figure out how much to ship along any route, so creating an amount variable over the set of routes seems logical. As in the previous examples, we restrict it to non-negative numbers as shipping negative shoes is impossible and illogical.
{{{
#!python
-model.amount = Var(model.routes, within=NonNegativeReals)
+model.amount = pyo.Var(model.routes, within=pyo.NonNegativeReals)
}}}
In the transportation problem, we were lucky and (after we added a bit more supply) the total supply was the same as the total demand. But what if we had more supply than demand? It would be hard for a user to track down where that extra supply is; they would need to carefully look through each warehouse and store, calculating how much is coming in compared to the location's supply and demand to find where the extra supplies went. To make it simpler for the user in this problem to find the extra amounts, we introduce another variable: excess. At the end, when we solve the problem, the solution will also include an "excess" section that tells us how many shoes are left over at each location so we won't lose track of any of our supply. Note that excess is a variable over the locations and shouldn't be negative. From here, the implementation is similar to the amount variable.
{{{
#!python
-model.excess = Var(model.places, within=NonNegativeReals)
+model.excess = pyo.Var(model.places, within=pyo.NonNegativeReals)
}}}
As in the diet problem and the transportation problem, our goal is to minimize cost. To calculate the total cost, we just take the amount that will travel along each route, multiply it with the cost to travel that route, and sum all of these values together. To code it we input
@@ -66,7 +66,7 @@ As in the diet problem and the transportation problem, our goal is to minimize c
def costRule(model):
return sum(model.cost[n]*model.amount[n] for n in model.routes)
-model.costTotal = Objective(rule=costRule)
+model.costTotal = pyo.Objective(rule=costRule)
}}}
Once again, this is just taking the dot product of the cost and amount vectors. Recall the being an objective means that Pyomo will try to minimize this value. Since total cost is our objective, Pyomo will find the least expensive way to ship our goods from the mills to the factories which is exactly what we're looking for.
@@ -77,7 +77,7 @@ One of the main factors outlined above was that we ship a minimum amount on each
def loadRule(i,j, model):
return (model.minimum[i,j], model.amount[i,j], model.maximum[i,j])
-model.loadOnRoad = Constraint(model.routes, rule=loadRule)
+model.loadOnRoad = pyo.Constraint(model.routes, rule=loadRule)
}}}
The second line here indicates that the value of "amount" must be between the minimum and maximum values (inclusive) allowed on that route. Also, by putting routes as one of the arguments to the constraint we will cycle through every possible route when doing this rule. Essentially, this is just the cost rule for each individual route compressed into one constraint. Considering that this one constraint also contains the minimum and maximum load rules, we see that it is very, very powerful.
@@ -106,7 +106,7 @@ def supplyDemandRule(nn, model):
return input == output
-model.supplyDemand = Constraint(model.places, rule=supplyDemandRule)
+model.supplyDemand = pyo.Constraint(model.places, rule=supplyDemandRule)
}}}
What we did was just construct a few additional variables; this wasn't required but makes reading and understanding the code much, much simpler. The variable "amountIn" looks at each route to find ones that end in this location, then adds the amount on each of those routes together to determine how much flows to each location. The "amountOut" variable functions similarly for the flow out. Then we just create an "input" and "output" and ensure they're equal. Like in some of the previous constraints, we feed the set of places into the constraint as an argument so it will index over that set, and thus this rule functions for all the places in our network.
diff --git a/examples/doc/samples/case_studies/network_flow/networkFlow1.py b/examples/doc/samples/case_studies/network_flow/networkFlow1.py
index eb8c8e48a1a..fbaf1a8242d 100644
--- a/examples/doc/samples/case_studies/network_flow/networkFlow1.py
+++ b/examples/doc/samples/case_studies/network_flow/networkFlow1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,33 +9,33 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.places = Set()
-model.routes = Set(within=model.places * model.places)
-model.supply = Param(model.places)
-model.demand = Param(model.places)
-model.cost = Param(model.routes)
-model.minimum = Param(model.routes)
-model.maximum = Param(model.routes)
-model.amount = Var(model.routes, within=NonNegativeReals)
-model.excess = Var(model.places, within=NonNegativeReals)
+model.places = pyo.Set()
+model.routes = pyo.Set(within=model.places * model.places)
+model.supply = pyo.Param(model.places)
+model.demand = pyo.Param(model.places)
+model.cost = pyo.Param(model.routes)
+model.minimum = pyo.Param(model.routes)
+model.maximum = pyo.Param(model.routes)
+model.amount = pyo.Var(model.routes, within=pyo.NonNegativeReals)
+model.excess = pyo.Var(model.places, within=pyo.NonNegativeReals)
def costRule(model):
return sum(model.cost[n] * model.amount[n] for n in model.routes)
-model.costTotal = Objective(rule=costRule)
+model.costTotal = pyo.Objective(rule=costRule)
def loadRule(model, i, j):
return (model.minimum[i, j], model.amount[i, j], model.maximum[i, j])
-model.loadOnRoad = Constraint(model.routes, rule=loadRule)
+model.loadOnRoad = pyo.Constraint(model.routes, rule=loadRule)
def supplyDemandRule(model, nn):
@@ -48,4 +48,4 @@ def supplyDemandRule(model, nn):
return input == output
-model.supplyDemand = Constraint(model.places, rule=supplyDemandRule)
+model.supplyDemand = pyo.Constraint(model.places, rule=supplyDemandRule)
diff --git a/examples/doc/samples/case_studies/network_flow/networkFlow1.tex b/examples/doc/samples/case_studies/network_flow/networkFlow1.tex
index 24e2c729374..6dbf14bb21a 100644
--- a/examples/doc/samples/case_studies/network_flow/networkFlow1.tex
+++ b/examples/doc/samples/case_studies/network_flow/networkFlow1.tex
@@ -85,16 +85,16 @@ \subsection*{Build the model}
We begin this model as we always do
\begin{verbatim}
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
\end{verbatim}
Now we must define our sets. In the transportation problem, we had a set for the warehouses and a set for the stores. In this example, we're going to be more sophisticated: we're going to just have one set for all the locations. Additionally, we're going to have one set that holds all of the different routes between these locations. This construction will help later when creating the constraints and is a more typical model for a network flow problem: we care about the nodes and arcs, so it makes sense to make those the sets. The code is a little different than what we've done before.
\begin{verbatim}
-model.places = Set()
-model.routes = Set(within=model.places*model.places)
+model.places = pyo.Set()
+model.routes = pyo.Set(within=model.places*model.places)
\end{verbatim}
While the definition for the set ``places'' should be familiar, how we defined ``routes'' is a bit more foreign. By saying \begin{verbatim}within=model.places*model.places\end{verbatim} we mean that routes is a subset of places crossed with itself. Thus, the set of routes will be a set of tuples, and each part of these tuples will come from the set of places. This is exactly what we want as each route is uniquely defined by its starting and ending place, so if we have a route (A,B) that just means we can ship grain from place A to place B. Note, though, that this does not mean we can ship from B to A, that's a different tuple, (B,A).
@@ -102,23 +102,23 @@ \subsection*{Build the model}
The parameters are fairly straightforward after this point. Each place has an associated supply and demand (either or both of which could be $0$), and each route has a minimum and maximum amount that it can be used. Also, each route has an associated cost with it. All of these are parameters over one set so the implementation should be routine at this point.
\begin{verbatim}
-model.supply = Param(model.places)
-model.demand = Param(model.places)
-model.cost = Param(model.routes)
-model.minimum = Param(model.routes)
-model.maximum = Param(model.routes)
+model.supply = pyo.Param(model.places)
+model.demand = pyo.Param(model.places)
+model.cost = pyo.Param(model.routes)
+model.minimum = pyo.Param(model.routes)
+model.maximum = pyo.Param(model.routes)
\end{verbatim}
Now to define our variables. We're trying to figure out how much to ship along any route, so creating an amount variable over the set of routes seems logical. As in the previous examples, we restrict it to non-negative numbers as shipping negative amounts of grain is impossible and illogical.
\begin{verbatim}
-model.amount = Var(model.routes, within=NonNegativeReals)
+model.amount = pyo.Var(model.routes, within=pyo.NonNegativeReals)
\end{verbatim}
In the transportation problem, we were lucky and (after we added a bit more supply) the total supply was the same as the total demand. But what if we have more supply than demand? It would be hard for a user to track down where that extra supply is; they would need to carefully look through each warehouse and store, calculating how much is coming in compared to the location's supply and demand to find where the extra supplies went. To make it simpler for the user to find the extra amounts, we introduce another variable: excess. At the end, when we solve the problem, the solution will also include an ``excess'' section that tells us how much grain is left over at each location so we won't lose track of any of our supply, but instead easily and quickly know where it is. Note that excess is a variable over the locations and shouldn't be negative. From here, the implementation is similar to the amount variable.
\begin{verbatim}
-model.excess = Var(model.places, within=NonNegativeReals)
+model.excess = pyo.Var(model.places, within=pyo.NonNegativeReals)
\end{verbatim}
As in the diet problem and the transportation problem, our goal is to minimize cost. To calculate the total cost, we just take the amount that will travel along each route, multiply it with the cost to travel that route, and sum all of these values together. To code it we input
@@ -127,7 +127,7 @@ \subsection*{Build the model}
def costRule(model):
return sum(model.cost[n]*model.amount[n] for n in model.routes)
-model.costTotal = Objective(rule=costRule)
+model.costTotal = pyo.Objective(rule=costRule)
\end{verbatim}
\noindent
@@ -140,7 +140,7 @@ \subsection*{Build the model}
return (model.minimum[i,j], model.amount[i,j],
model.maximum[i,j])
-model.loadOnRoad = Constraint(model.routes, rule=loadRule)
+model.loadOnRoad = pyo.Constraint(model.routes, rule=loadRule)
\end{verbatim}
The second line here indicates that the value of amount must be between the minimum and maximum values (inclusive) allowed on that route. Also, but putting routes as one of the arguments to the constraint we will cycle through every possible route when doing this rule. Essentially, this is just the cost rule for each individual route compressed into one constraint. Considering that this one constraint also contains the minimum and maximum load rules, we see that it is very, very useful.
@@ -169,7 +169,7 @@ \subsection*{Build the model}
return input == output
-model.supplyDemand = Constraint(model.places, rule=supplyDemandRule)
+model.supplyDemand = pyo.Constraint(model.places, rule=supplyDemandRule)
\end{verbatim}
What we did was just construct a few additional variables; this wasn't required but makes reading and understanding the code much, much simpler. The variable ``amountIn'' looks at each route to find ones that end in this location, then adds the amount on each of those routes together to determine how much flows to each location. The ``amountOut'' variable functions similarly for the flow out. Then we just create an ``input'' and ``output'' and ensure they're equal. As in some of the previous constraints, we feed the set of places into the constraint as an argument so it will index over that set, and thus this rule functions for all the places in our network.
diff --git a/examples/doc/samples/case_studies/rosen/Rosenbrock.py b/examples/doc/samples/case_studies/rosen/Rosenbrock.py
index 51e7d51b57d..e9d06f0b360 100644
--- a/examples/doc/samples/case_studies/rosen/Rosenbrock.py
+++ b/examples/doc/samples/case_studies/rosen/Rosenbrock.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,13 +10,13 @@
# ___________________________________________________________________________
# @intro:
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# @:intro
# @vars:
-model.x = Var(initialize=1.5)
-model.y = Var(initialize=1.5)
+model.x = pyo.Var(initialize=1.5)
+model.y = pyo.Var(initialize=1.5)
# @:vars
@@ -25,5 +25,5 @@ def rosenbrock(amodel):
return (1.0 - amodel.x) ** 2 + 100.0 * (amodel.y - amodel.x**2) ** 2
-model.obj = Objective(rule=rosenbrock, sense=minimize)
+model.obj = pyo.Objective(rule=rosenbrock, sense=pyo.minimize)
# @:obj
diff --git a/examples/doc/samples/case_studies/transportation/README.txt b/examples/doc/samples/case_studies/transportation/README.txt
index 8087666b83b..12c94a3059f 100644
--- a/examples/doc/samples/case_studies/transportation/README.txt
+++ b/examples/doc/samples/case_studies/transportation/README.txt
@@ -8,26 +8,26 @@ We begin by importing the Pyomo package and creating an object of the type Model
{{{
#!python
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
}}}
The next step is to define our sets that are being acted upon. The warehouses have a supply and the stores have demand, so those two make sense as sets (with supply and demand parameters that rely on them). Each route will have an associated cost, so we could create a set of routes. However, it's more efficient (and easier to read) to make the costs a parameter over two set, the warehouses and the stores, so we will only need to define those two sets.
{{{
#!python
-model.warehouses = Set()
-model.stores = Set()
+model.warehouses = pyo.Set()
+model.stores = pyo.Set()
}}}
As outlined above, we also have several parameters to take into account: supply, demand and costs We input these similar to how we did it in the diet problem.
{{{
#!python
-model.supply = Param(model.warehouses)
-model.demand = Param(model.stores)
-model.costs = Param(model.warehouses, model.stores)
+model.supply = pyo.Param(model.warehouses)
+model.demand = pyo.Param(model.stores)
+model.costs = pyo.Param(model.warehouses, model.stores)
}}}
Note once again that the costs are a parameter of two dimensions since it takes in two arguments.
@@ -35,7 +35,7 @@ We have one final addition to make: the variable to solve for. We're looking fo
{{{
#!python
-model.amounts = Var(model.warehouses, model.stores, within = NonNegativeReals)
+model.amounts = pyo.Var(model.warehouses, model.stores, within = pyo.NonNegativeReals)
}}}
We restrict our solutions to be the non-negative reals as otherwise the solution is likely to be illogical and useless---it could involve shipping negative amounts of supplies to gain money, for example.
@@ -50,7 +50,7 @@ def costRule(model):
for i in model.stores
)
-model.cost=Objective(rule=costRule)
+model.cost=pyo.Objective(rule=costRule)
}}}
It's worth looking at what's happning here a bit more in-depth. The line
{{{
@@ -66,7 +66,7 @@ Now we must construct our constraints. In this example we only have two, and th
def minDemandRule(store, model):
return sum(model.amounts[i, store] for i in model.warehouses) >= model.demand[store]
-model.demandConstraint = Constraint(model.stores,
+model.demandConstraint = pyo.Constraint(model.stores,
rule=minDemandRule)
}}}
By inputting the set "stores" into the constraint, it tells the constraint to run this rule for each element of "stores." What will happen is the rule will look at each store individually to insure the amount flowing into it exceeds the store's demands. We construct the supply rule in a similar fashion.
@@ -76,7 +76,7 @@ By inputting the set "stores" into the constraint, it tells the constraint to ru
def maxSupplyRule(warehouse, model):
return sum(model.amounts[warehouse, j] for j in model.stores) <= model.supply[warehouse]
-model.supplyConstraint = Constraint(model.warehouses, rule=maxSupplyRule)
+model.supplyConstraint = pyo.Constraint(model.warehouses, rule=maxSupplyRule)
}}}
We have now finished constructing our transportation model, which we save as transportation.py. (That period is the end of a sentence, not part of the file name). The next step is to create a data file.
diff --git a/examples/doc/samples/case_studies/transportation/transportation.py b/examples/doc/samples/case_studies/transportation/transportation.py
index 588ae764953..bc9f89f18b6 100644
--- a/examples/doc/samples/case_studies/transportation/transportation.py
+++ b/examples/doc/samples/case_studies/transportation/transportation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,16 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.warehouses = Set()
-model.stores = Set()
-model.supply = Param(model.warehouses)
-model.demand = Param(model.stores)
-model.costs = Param(model.warehouses, model.stores)
-model.amounts = Var(model.warehouses, model.stores, within=NonNegativeReals)
+model.warehouses = pyo.Set()
+model.stores = pyo.Set()
+model.supply = pyo.Param(model.warehouses)
+model.demand = pyo.Param(model.stores)
+model.costs = pyo.Param(model.warehouses, model.stores)
+model.amounts = pyo.Var(model.warehouses, model.stores, within=pyo.NonNegativeReals)
def costRule(model):
@@ -29,14 +29,14 @@ def costRule(model):
)
-model.cost = Objective(rule=costRule)
+model.cost = pyo.Objective(rule=costRule)
def minDemandRule(model, store):
return sum(model.amounts[i, store] for i in model.warehouses) >= model.demand[store]
-model.demandConstraint = Constraint(model.stores, rule=minDemandRule)
+model.demandConstraint = pyo.Constraint(model.stores, rule=minDemandRule)
def maxSupplyRule(model, warehouse):
@@ -46,4 +46,4 @@ def maxSupplyRule(model, warehouse):
)
-model.supplyConstraint = Constraint(model.warehouses, rule=maxSupplyRule)
+model.supplyConstraint = pyo.Constraint(model.warehouses, rule=maxSupplyRule)
diff --git a/examples/doc/samples/case_studies/transportation/transportationProblem.tex b/examples/doc/samples/case_studies/transportation/transportationProblem.tex
index ca3caf2d751..b2c5565ddfd 100644
--- a/examples/doc/samples/case_studies/transportation/transportationProblem.tex
+++ b/examples/doc/samples/case_studies/transportation/transportationProblem.tex
@@ -10,24 +10,24 @@ \subsection*{Build the model}
We begin by importing the Pyomo package and creating an object of the type Model, which we call model.
\begin{verbatim}
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
\end{verbatim}
The next step is to define our sets that are being acted upon. The warehouses have a supply and the stores have demand, so those two make sense as sets (with supply and demand parameters that rely on them). Each route will have an associated cost, so we could create a set of routes. However, it's more efficient (and easier to read) to make the costs a parameter over two set, the warehouses and the stores, so we will only need to define those two sets.
\begin{verbatim}
-model.warehouses = Set()
-model.stores = Set()
+model.warehouses = pyo.Set()
+model.stores = pyo.Set()
\end{verbatim}
As outlined above, we also have several parameters to take into account: supply, demand and costs We input these similar to how we did it in the diet problem.
\begin{verbatim}
-model.supply = Param(model.warehouses)
-model.demand = Param(model.stores)
-model.costs = Param(model.warehouses, model.stores)
+model.supply = pyo.Param(model.warehouses)
+model.demand = pyo.Param(model.stores)
+model.costs = pyo.Param(model.warehouses, model.stores)
\end{verbatim}
\noindent
@@ -36,8 +36,8 @@ \subsection*{Build the model}
We have one final addition to make: the variable to solve for. We're looking for the amount of goods to be sent from each warehouse to each store, so we create a variable over the set of warehouses and the set of stores that determines how much will be shipped from each warehouse to each store. This is slightly different than in the diet problem, where our variable was just over one set, but the difference is minor in the implementation.
\begin{verbatim}
-model.amounts = Var(model.warehouses, model.stores,
- within = NonNegativeReals)
+model.amounts = pyo.Var(model.warehouses, model.stores,
+ within = pyo.NonNegativeReals)
\end{verbatim}
\noindent
@@ -53,7 +53,7 @@ \subsection*{Build the model}
for i in model.stores
)
-model.cost=Objective(rule=costRule)
+model.cost=pyo.Objective(rule=costRule)
\end{verbatim}
\noindent
@@ -66,7 +66,7 @@ \subsection*{Build the model}
return sum(model.amounts[i, store] for i in model.warehouses)
>= model.demand[store]
-model.demandConstraint = Constraint(model.stores,
+model.demandConstraint = pyo.Constraint(model.stores,
rule=minDemandRule)
\end{verbatim}
@@ -78,7 +78,7 @@ \subsection*{Build the model}
return sum(model.amounts[warehouse, j] for j in model.stores)
<= model.supply[warehouse]
-model.supplyConstraint = Constraint(model.warehouses,
+model.supplyConstraint = pyo.Constraint(model.warehouses,
rule=maxSupplyRule)
\end{verbatim}
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py b/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
index f49c5b591ae..ca8442822a2 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,16 @@
# ___________________________________________________________________________
import cplex
-from cutstock_util import *
+from cutstock_util import (
+ getCutCount,
+ getPatCount,
+ getCuts,
+ getPatterns,
+ getSheetsAvail,
+ getCutDemand,
+ getPriceSheetData,
+ getCutsInPattern,
+)
from cplex.exceptions import CplexSolverError
# Reading in Data using the cutstock_util
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_grb.py b/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
index 483d84b02e6..60186e69969 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,16 @@
# ___________________________________________________________________________
from gurobipy import *
-from cutstock_util import *
+from cutstock_util import (
+ getCutCount,
+ getPatCount,
+ getCuts,
+ getPatterns,
+ getSheetsAvail,
+ getCutDemand,
+ getPriceSheetData,
+ getCutsInPattern,
+)
# Reading in Data using the cutstock_util
cutcount = getCutCount()
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py b/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
index 9a6c8301e8f..6cf12b16b40 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,17 @@
# ___________________________________________________________________________
from lpsolve55 import *
-from cutstock_util import *
+from cutstock_util import (
+ getCutCount,
+ getPatCount,
+ getCuts,
+ getPatterns,
+ getSheetsAvail,
+ getCutDemand,
+ getPriceSheetData,
+ getCutsInPattern,
+)
+
# Reading in Data using the cutstock_util
cutcount = getCutCount()
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py b/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
index d14b0fe46c1..25144b29e7d 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,17 @@
# ___________________________________________________________________________
from pulp import *
-from cutstock_util import *
+from cutstock_util import (
+ getCutCount,
+ getPatCount,
+ getCuts,
+ getPatterns,
+ getSheetsAvail,
+ getCutDemand,
+ getPriceSheetData,
+ getCutsInPattern,
+)
+
# Reading in Data using the cutstock_util
cutcount = getCutCount()
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py b/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
index 48d7e6b26fd..d8768f24e12 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,17 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
-import pyomo.opt
-from cutstock_util import *
+import pyomo.environ as pyo
+from cutstock_util import (
+ getCutCount,
+ getPatCount,
+ getCuts,
+ getPatterns,
+ getSheetsAvail,
+ getCutDemand,
+ getPriceSheetData,
+ getCutsInPattern,
+)
# Reading in Data using the cutstock_util
cutcount = getCutCount()
@@ -37,22 +45,22 @@
tmp[Cuts[i]] = CutDemand[i]
CutDemand = tmp
-model = ConcreteModel(name="CutStock Problem")
+model = pyo.ConcreteModel(name="CutStock Problem")
# Defining Variables
-model.SheetsCut = Var()
-model.TotalCost = Var()
-model.PatternCount = Var(Patterns, bounds=(0, None))
-model.ExcessCuts = Var(Cuts, bounds=(0, None))
+model.SheetsCut = pyo.Var()
+model.TotalCost = pyo.Var()
+model.PatternCount = pyo.Var(Patterns, bounds=(0, None))
+model.ExcessCuts = pyo.Var(Cuts, bounds=(0, None))
# objective
-model.objective = Objective(expr=1.0 * model.TotalCost)
+model.objective = pyo.Objective(expr=1.0 * model.TotalCost)
# Constraints
-model.TotCost = Constraint(expr=model.TotalCost == PriceSheet * model.SheetsCut)
-model.RawAvail = Constraint(expr=model.SheetsCut <= SheetsAvail)
-model.Sheets = Constraint(expr=summation(model.PatternCount) == model.SheetsCut)
-model.CutReq = Constraint(Cuts)
+model.TotCost = pyo.Constraint(expr=model.TotalCost == PriceSheet * model.SheetsCut)
+model.RawAvail = pyo.Constraint(expr=model.SheetsCut <= SheetsAvail)
+model.Sheets = pyo.Constraint(expr=pyo.summation(model.PatternCount) == model.SheetsCut)
+model.CutReq = pyo.Constraint(Cuts)
for c in Cuts:
model.CutReq.add(
c,
@@ -61,13 +69,13 @@
)
instance = model.create()
-opt = pyomo.opt.SolverFactory('glpk')
+opt = pyo.SolverFactory('glpk')
results = opt.solve(instance)
instance.load(results)
print("Status:", results.solver.status)
-print("Minimum total cost:", value(instance.objective))
+print("Minimum total cost:", pyo.value(instance.objective))
for v in instance.variables():
var = instance.variable(v)
- if value(var) > 0:
- print(v, "=", value(var))
+ if pyo.value(var) > 0:
+ print(v, "=", pyo.value(var))
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_util.py b/examples/doc/samples/comparisons/cutstock/cutstock_util.py
index da5349ec06c..0676f1884ce 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_util.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_util.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/doc/samples/comparisons/sched/pyomo/sched.py b/examples/doc/samples/comparisons/sched/pyomo/sched.py
index cf781713641..ce588281eef 100644
--- a/examples/doc/samples/comparisons/sched/pyomo/sched.py
+++ b/examples/doc/samples/comparisons/sched/pyomo/sched.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,78 +9,78 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.TASKS = Set()
-model.PEOPLE = Set()
-model.SLOTS = Set()
+model.TASKS = pyo.Set()
+model.PEOPLE = pyo.Set()
+model.SLOTS = pyo.Set()
-model.amt = Param(model.TASKS, model.PEOPLE, within=NonNegativeReals)
-model.nrooms = Param(model.SLOTS, within=NonNegativeReals)
-model.ntasks = Param(model.TASKS, within=NonNegativeReals)
-model.minp = Param(model.TASKS, within=NonNegativeReals)
+model.amt = pyo.Param(model.TASKS, model.PEOPLE, within=pyo.NonNegativeReals)
+model.nrooms = pyo.Param(model.SLOTS, within=pyo.NonNegativeReals)
+model.ntasks = pyo.Param(model.TASKS, within=pyo.NonNegativeReals)
+model.minp = pyo.Param(model.TASKS, within=pyo.NonNegativeReals)
def maxp_valid(value, i, Model):
return Model.maxp[i] >= Model.minp[i]
-model.maxp = Param(model.TASKS, validate=maxp_valid)
+model.maxp = pyo.Param(model.TASKS, validate=maxp_valid)
-model.x = Var(model.TASKS, model.PEOPLE, model.SLOTS, within=Binary)
-model.xts = Var(model.TASKS, model.SLOTS, within=Binary)
-model.xtp = Var(model.TASKS, model.PEOPLE, within=Binary)
+model.x = pyo.Var(model.TASKS, model.PEOPLE, model.SLOTS, within=pyo.Binary)
+model.xts = pyo.Var(model.TASKS, model.SLOTS, within=pyo.Binary)
+model.xtp = pyo.Var(model.TASKS, model.PEOPLE, within=pyo.Binary)
def rule1_rule(t, s, Model):
return sum(Model.x[t, p, s] for p in Model.PEOPLE) >= Model.xts[t, s]
-model.rule1 = Constraint(model.TASKS, model.SLOTS)
+model.rule1 = pyo.Constraint(model.TASKS, model.SLOTS)
def rule2_rule(t, p, s, Model):
return Model.x[t, p, s] <= Model.xts[t, s]
-model.rule2 = Constraint(model.TASKS, model.PEOPLE, model.SLOTS)
+model.rule2 = pyo.Constraint(model.TASKS, model.PEOPLE, model.SLOTS)
def rule3_rule(t, p, Model):
return sum(Model.x[t, p, s] for s in Model.SLOTS) == Model.xtp[t, p]
-model.rule3 = Constraint(model.TASKS, model.PEOPLE)
+model.rule3 = pyo.Constraint(model.TASKS, model.PEOPLE)
def rule4_rule(t, Model):
return sum(Model.xts[t, s] for s in Model.SLOTS) == Model.ntasks[t]
-model.rule4 = Constraint(model.TASKS)
+model.rule4 = pyo.Constraint(model.TASKS)
def rule5_rule(t, Model):
return Model.minp[t] <= sum(Model.xtp[t, p] for p in Model.PEOPLE) <= Model.maxp[t]
-model.rule5 = Constraint(model.TASKS)
+model.rule5 = pyo.Constraint(model.TASKS)
def rule6_rule(s, Model):
return sum(Model.xts[t, s] for t in Model.TASKS) <= Model.nrooms[s]
-model.rule6 = Constraint(model.SLOTS)
+model.rule6 = pyo.Constraint(model.SLOTS)
def rule7_rule(p, s, Model):
return sum(Model.x[t, p, s] for t in Model.TASKS) == 1
-model.rule7 = Constraint(model.PEOPLE, model.SLOTS)
+model.rule7 = pyo.Constraint(model.PEOPLE, model.SLOTS)
def z_rule(Model):
@@ -89,4 +89,4 @@ def z_rule(Model):
)
-model.z = Objective(sense=maximize)
+model.z = pyo.Objective(sense=pyo.maximize)
diff --git a/examples/doc/samples/scripts/__init__.py b/examples/doc/samples/scripts/__init__.py
index 0110902b288..af79da12d7f 100644
--- a/examples/doc/samples/scripts/__init__.py
+++ b/examples/doc/samples/scripts/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/doc/samples/scripts/s1/knapsack.py b/examples/doc/samples/scripts/s1/knapsack.py
index cee3937b668..989e61cd472 100644
--- a/examples/doc/samples/scripts/s1/knapsack.py
+++ b/examples/doc/samples/scripts/s1/knapsack.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,31 +9,31 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.ITEMS = Set()
+model.ITEMS = pyo.Set()
-model.v = Param(model.ITEMS, within=PositiveReals)
+model.v = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.w = Param(model.ITEMS, within=PositiveReals)
+model.w = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.limit = Param(within=PositiveReals)
+model.limit = pyo.Param(within=pyo.PositiveReals)
-model.x = Var(model.ITEMS, within=Binary)
+model.x = pyo.Var(model.ITEMS, within=pyo.Binary)
def value_rule(model):
return sum(model.v[i] * model.x[i] for i in model.ITEMS)
-model.value = Objective(sense=maximize, rule=value_rule)
+model.value = pyo.Objective(sense=pyo.maximize, rule=value_rule)
def weight_rule(model):
return sum(model.w[i] * model.x[i] for i in model.ITEMS) <= model.limit
-model.weight = Constraint(rule=weight_rule)
+model.weight = pyo.Constraint(rule=weight_rule)
diff --git a/examples/doc/samples/scripts/s1/script.py b/examples/doc/samples/scripts/s1/script.py
index 4ddaea45e19..305e2407033 100644
--- a/examples/doc/samples/scripts/s1/script.py
+++ b/examples/doc/samples/scripts/s1/script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
-import pyomo.opt
-import pyomo.environ
+import pyomo.environ as pyo
#
# Import model
@@ -22,7 +20,7 @@
instance = knapsack.model.create_instance("knapsack.dat")
#
# Setup the optimizer
-opt = pyomo.opt.SolverFactory("glpk")
+opt = pyo.SolverFactory("glpk")
#
# Optimize
results = opt.solve(instance, symbolic_solver_labels=True)
diff --git a/examples/doc/samples/scripts/s2/knapsack.py b/examples/doc/samples/scripts/s2/knapsack.py
index 3131cee7bc5..fc8d17ac73a 100644
--- a/examples/doc/samples/scripts/s2/knapsack.py
+++ b/examples/doc/samples/scripts/s2/knapsack.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,34 +9,34 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.ITEMS = Set()
+model.ITEMS = pyo.Set()
-model.v = Param(model.ITEMS, within=PositiveReals)
+model.v = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.w = Param(model.ITEMS, within=PositiveReals)
+model.w = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.limit = Param(within=PositiveReals)
+model.limit = pyo.Param(within=pyo.PositiveReals)
-model.x = Var(model.ITEMS, within=PercentFraction)
+model.x = pyo.Var(model.ITEMS, within=pyo.PercentFraction)
def value_rule(model):
return sum(model.v[i] * model.x[i] for i in model.ITEMS)
-model.value = Objective(sense=maximize, rule=value_rule)
+model.value = pyo.Objective(sense=pyo.maximize, rule=value_rule)
def weight_rule(model):
return sum(model.w[i] * model.x[i] for i in model.ITEMS) <= model.limit
-model.weight = Constraint(rule=weight_rule)
+model.weight = pyo.Constraint(rule=weight_rule)
# This constraint is not active, to illustrate how zero dual values are
@@ -45,4 +45,4 @@ def W_rule(model):
return sum(model.w[i] * model.x[i] for i in model.ITEMS) <= 2 * model.limit
-model.W = Constraint(rule=W_rule)
+model.W = pyo.Constraint(rule=W_rule)
diff --git a/examples/doc/samples/scripts/s2/script.py b/examples/doc/samples/scripts/s2/script.py
index fe97d6ab8fd..6f1e03ade79 100644
--- a/examples/doc/samples/scripts/s2/script.py
+++ b/examples/doc/samples/scripts/s2/script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
-import pyomo.opt
-import pyomo.environ
+from pyomo.environ import SolverFactory
#
# Import model
@@ -22,7 +20,7 @@
instance = knapsack.model.create_instance("knapsack.dat")
#
# Setup the optimizer
-opt = pyomo.opt.SolverFactory("glpk")
+opt = SolverFactory("glpk")
#
# Optimize
results = opt.solve(instance, suffixes=['.*'])
diff --git a/examples/doc/samples/scripts/test_scripts.py b/examples/doc/samples/scripts/test_scripts.py
index 691a44aea2d..c36179a77b8 100644
--- a/examples/doc/samples/scripts/test_scripts.py
+++ b/examples/doc/samples/scripts/test_scripts.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/doc/samples/update.py b/examples/doc/samples/update.py
index 8789413303c..e2acb830fab 100644
--- a/examples/doc/samples/update.py
+++ b/examples/doc/samples/update.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/batchProcessing.py b/examples/gdp/batchProcessing.py
index 9810f5d63f1..b1290c90674 100644
--- a/examples/gdp/batchProcessing.py
+++ b/examples/gdp/batchProcessing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
'''Problem from http://www.minlp.org/library/problem/index.php?i=172&lib=GDP
We are minimizing the cost of a design of a plant with parallel processing units and storage tanks
@@ -23,10 +23,10 @@
def build_model():
- model = AbstractModel()
+ model = pyo.AbstractModel()
# TODO: it looks like they set a bigM for each j. Which I need to look up how to do...
- model.BigM = Suffix(direction=Suffix.LOCAL)
+ model.BigM = pyo.Suffix(direction=pyo.Suffix.LOCAL)
model.BigM[None] = 1000
## Constants from GAMS
@@ -34,13 +34,13 @@ def build_model():
2 * 5
) # btw, I know 2*5 is 10... I don't know why it's written this way in GAMS?
StorageTankSizeFactorByProd = 3
- MinFlow = -log(10000)
- VolumeLB = log(300)
- VolumeUB = log(3500)
- StorageTankSizeLB = log(100)
- StorageTankSizeUB = log(15000)
- UnitsInPhaseUB = log(6)
- UnitsOutOfPhaseUB = log(6)
+ MinFlow = -pyo.log(10000)
+ VolumeLB = pyo.log(300)
+ VolumeUB = pyo.log(3500)
+ StorageTankSizeLB = pyo.log(100)
+ StorageTankSizeUB = pyo.log(15000)
+ UnitsInPhaseUB = pyo.log(6)
+ UnitsOutOfPhaseUB = pyo.log(6)
# TODO: YOU ARE HERE. YOU HAVEN'T ACTUALLY MADE THESE THE BOUNDS YET, NOR HAVE YOU FIGURED OUT WHOSE
# BOUNDS THEY ARE. AND THERE ARE MORE IN GAMS.
@@ -48,36 +48,36 @@ def build_model():
# Sets
##########
- model.PRODUCTS = Set()
- model.STAGES = Set(ordered=True)
- model.PARALLELUNITS = Set(ordered=True)
+ model.PRODUCTS = pyo.Set()
+ model.STAGES = pyo.Set(ordered=True)
+ model.PARALLELUNITS = pyo.Set(ordered=True)
# TODO: this seems like an over-complicated way to accomplish this task...
def filter_out_last(model, j):
return j != model.STAGES.last()
- model.STAGESExceptLast = Set(initialize=model.STAGES, filter=filter_out_last)
+ model.STAGESExceptLast = pyo.Set(initialize=model.STAGES, filter=filter_out_last)
# TODO: these aren't in the formulation??
- # model.STORAGE_TANKS = Set()
+ # model.STORAGE_TANKS = pyo.Set()
###############
# Parameters
###############
- model.HorizonTime = Param()
- model.Alpha1 = Param()
- model.Alpha2 = Param()
- model.Beta1 = Param()
- model.Beta2 = Param()
+ model.HorizonTime = pyo.Param()
+ model.Alpha1 = pyo.Param()
+ model.Alpha2 = pyo.Param()
+ model.Beta1 = pyo.Param()
+ model.Beta2 = pyo.Param()
- model.ProductionAmount = Param(model.PRODUCTS)
- model.ProductSizeFactor = Param(model.PRODUCTS, model.STAGES)
- model.ProcessingTime = Param(model.PRODUCTS, model.STAGES)
+ model.ProductionAmount = pyo.Param(model.PRODUCTS)
+ model.ProductSizeFactor = pyo.Param(model.PRODUCTS, model.STAGES)
+ model.ProcessingTime = pyo.Param(model.PRODUCTS, model.STAGES)
# These are hard-coded in the GAMS file, hence the defaults
- model.StorageTankSizeFactor = Param(model.STAGES, default=StorageTankSizeFactor)
- model.StorageTankSizeFactorByProd = Param(
+ model.StorageTankSizeFactor = pyo.Param(model.STAGES, default=StorageTankSizeFactor)
+ model.StorageTankSizeFactorByProd = pyo.Param(
model.PRODUCTS, model.STAGES, default=StorageTankSizeFactorByProd
)
@@ -86,17 +86,17 @@ def filter_out_last(model, j):
# I made PRODUCTS ordered so I could do this... Is that bad? And it does index
# from 1, right?
def get_log_coeffs(model, k):
- return log(model.PARALLELUNITS.ord(k))
+ return pyo.log(model.PARALLELUNITS.ord(k))
- model.LogCoeffs = Param(model.PARALLELUNITS, initialize=get_log_coeffs)
+ model.LogCoeffs = pyo.Param(model.PARALLELUNITS, initialize=get_log_coeffs)
# bounds
- model.volumeLB = Param(model.STAGES, default=VolumeLB)
- model.volumeUB = Param(model.STAGES, default=VolumeUB)
- model.storageTankSizeLB = Param(model.STAGES, default=StorageTankSizeLB)
- model.storageTankSizeUB = Param(model.STAGES, default=StorageTankSizeUB)
- model.unitsInPhaseUB = Param(model.STAGES, default=UnitsInPhaseUB)
- model.unitsOutOfPhaseUB = Param(model.STAGES, default=UnitsOutOfPhaseUB)
+ model.volumeLB = pyo.Param(model.STAGES, default=VolumeLB)
+ model.volumeUB = pyo.Param(model.STAGES, default=VolumeUB)
+ model.storageTankSizeLB = pyo.Param(model.STAGES, default=StorageTankSizeLB)
+ model.storageTankSizeUB = pyo.Param(model.STAGES, default=StorageTankSizeUB)
+ model.unitsInPhaseUB = pyo.Param(model.STAGES, default=UnitsInPhaseUB)
+ model.unitsOutOfPhaseUB = pyo.Param(model.STAGES, default=UnitsOutOfPhaseUB)
################
# Variables
@@ -105,20 +105,20 @@ def get_log_coeffs(model, k):
# TODO: right now these match the formulation. There are more in GAMS...
# unit size of stage j
- # model.volume = Var(model.STAGES)
+ # model.volume = pyo.Var(model.STAGES)
# # TODO: GAMS has a batch size indexed just by products that isn't in the formulation... I'm going
# # to try to avoid it for the moment...
# # batch size of product i at stage j
- # model.batchSize = Var(model.PRODUCTS, model.STAGES)
+ # model.batchSize = pyo.Var(model.PRODUCTS, model.STAGES)
# # TODO: this is different in GAMS... They index by stages too?
# # cycle time of product i divided by batch size of product i
- # model.cycleTime = Var(model.PRODUCTS)
+ # model.cycleTime = pyo.Var(model.PRODUCTS)
# # number of units in parallel out-of-phase (or in phase) at stage j
- # model.unitsOutOfPhase = Var(model.STAGES)
- # model.unitsInPhase = Var(model.STAGES)
+ # model.unitsOutOfPhase = pyo.Var(model.STAGES)
+ # model.unitsInPhase = pyo.Var(model.STAGES)
# # TODO: what are we going to do as a boundary condition here? For that last stage?
# # size of intermediate storage tank between stage j and j+1
- # model.storageTankSize = Var(model.STAGES)
+ # model.storageTankSize = pyo.Var(model.STAGES)
# variables for convexified problem
# TODO: I am beginning to think these are my only variables actually.
@@ -127,29 +127,29 @@ def get_log_coeffs(model, k):
def get_volume_bounds(model, j):
return (model.volumeLB[j], model.volumeUB[j])
- model.volume_log = Var(model.STAGES, bounds=get_volume_bounds)
- model.batchSize_log = Var(model.PRODUCTS, model.STAGES)
- model.cycleTime_log = Var(model.PRODUCTS)
+ model.volume_log = pyo.Var(model.STAGES, bounds=get_volume_bounds)
+ model.batchSize_log = pyo.Var(model.PRODUCTS, model.STAGES)
+ model.cycleTime_log = pyo.Var(model.PRODUCTS)
def get_unitsOutOfPhase_bounds(model, j):
return (0, model.unitsOutOfPhaseUB[j])
- model.unitsOutOfPhase_log = Var(model.STAGES, bounds=get_unitsOutOfPhase_bounds)
+ model.unitsOutOfPhase_log = pyo.Var(model.STAGES, bounds=get_unitsOutOfPhase_bounds)
def get_unitsInPhase_bounds(model, j):
return (0, model.unitsInPhaseUB[j])
- model.unitsInPhase_log = Var(model.STAGES, bounds=get_unitsInPhase_bounds)
+ model.unitsInPhase_log = pyo.Var(model.STAGES, bounds=get_unitsInPhase_bounds)
def get_storageTankSize_bounds(model, j):
return (model.storageTankSizeLB[j], model.storageTankSizeUB[j])
# TODO: these bounds make it infeasible...
- model.storageTankSize_log = Var(model.STAGES, bounds=get_storageTankSize_bounds)
+ model.storageTankSize_log = pyo.Var(model.STAGES, bounds=get_storageTankSize_bounds)
# binary variables for deciding number of parallel units in and out of phase
- model.outOfPhase = Var(model.STAGES, model.PARALLELUNITS, within=Binary)
- model.inPhase = Var(model.STAGES, model.PARALLELUNITS, within=Binary)
+ model.outOfPhase = pyo.Var(model.STAGES, model.PARALLELUNITS, within=pyo.Binary)
+ model.inPhase = pyo.Var(model.STAGES, model.PARALLELUNITS, within=pyo.Binary)
###############
# Objective
@@ -157,18 +157,18 @@ def get_storageTankSize_bounds(model, j):
def get_cost_rule(model):
return model.Alpha1 * sum(
- exp(
+ pyo.exp(
model.unitsInPhase_log[j]
+ model.unitsOutOfPhase_log[j]
+ model.Beta1 * model.volume_log[j]
)
for j in model.STAGES
) + model.Alpha2 * sum(
- exp(model.Beta2 * model.storageTankSize_log[j])
+ pyo.exp(model.Beta2 * model.storageTankSize_log[j])
for j in model.STAGESExceptLast
)
- model.min_cost = Objective(rule=get_cost_rule)
+ model.min_cost = pyo.Objective(rule=get_cost_rule)
##############
# Constraints
@@ -177,34 +177,34 @@ def get_cost_rule(model):
def processing_capacity_rule(model, j, i):
return (
model.volume_log[j]
- >= log(model.ProductSizeFactor[i, j])
+ >= pyo.log(model.ProductSizeFactor[i, j])
+ model.batchSize_log[i, j]
- model.unitsInPhase_log[j]
)
- model.processing_capacity = Constraint(
+ model.processing_capacity = pyo.Constraint(
model.STAGES, model.PRODUCTS, rule=processing_capacity_rule
)
def processing_time_rule(model, j, i):
return (
model.cycleTime_log[i]
- >= log(model.ProcessingTime[i, j])
+ >= pyo.log(model.ProcessingTime[i, j])
- model.batchSize_log[i, j]
- model.unitsOutOfPhase_log[j]
)
- model.processing_time = Constraint(
+ model.processing_time = pyo.Constraint(
model.STAGES, model.PRODUCTS, rule=processing_time_rule
)
def finish_in_time_rule(model):
return model.HorizonTime >= sum(
- model.ProductionAmount[i] * exp(model.cycleTime_log[i])
+ model.ProductionAmount[i] * pyo.exp(model.cycleTime_log[i])
for i in model.PRODUCTS
)
- model.finish_in_time = Constraint(rule=finish_in_time_rule)
+ model.finish_in_time = pyo.Constraint(rule=finish_in_time_rule)
###############
# Disjunctions
@@ -216,38 +216,39 @@ def storage_tank_selection_disjunct_rule(disjunct, selectStorageTank, j):
def volume_stage_j_rule(disjunct, i):
return (
model.storageTankSize_log[j]
- >= log(model.StorageTankSizeFactor[j]) + model.batchSize_log[i, j]
+ >= pyo.log(model.StorageTankSizeFactor[j]) + model.batchSize_log[i, j]
)
def volume_stage_jPlus1_rule(disjunct, i):
return (
model.storageTankSize_log[j]
- >= log(model.StorageTankSizeFactor[j]) + model.batchSize_log[i, j + 1]
+ >= pyo.log(model.StorageTankSizeFactor[j])
+ + model.batchSize_log[i, j + 1]
)
def batch_size_rule(disjunct, i):
- return inequality(
- -log(model.StorageTankSizeFactorByProd[i, j]),
+ return pyo.inequality(
+ -pyo.log(model.StorageTankSizeFactorByProd[i, j]),
model.batchSize_log[i, j] - model.batchSize_log[i, j + 1],
- log(model.StorageTankSizeFactorByProd[i, j]),
+ pyo.log(model.StorageTankSizeFactorByProd[i, j]),
)
def no_batch_rule(disjunct, i):
return model.batchSize_log[i, j] - model.batchSize_log[i, j + 1] == 0
if selectStorageTank:
- disjunct.volume_stage_j = Constraint(
+ disjunct.volume_stage_j = pyo.Constraint(
model.PRODUCTS, rule=volume_stage_j_rule
)
- disjunct.volume_stage_jPlus1 = Constraint(
+ disjunct.volume_stage_jPlus1 = pyo.Constraint(
model.PRODUCTS, rule=volume_stage_jPlus1_rule
)
- disjunct.batch_size = Constraint(model.PRODUCTS, rule=batch_size_rule)
+ disjunct.batch_size = pyo.Constraint(model.PRODUCTS, rule=batch_size_rule)
else:
# The formulation says 0, but GAMS has this constant.
# 04/04: Francisco says volume should be free:
- # disjunct.no_volume = Constraint(expr=model.storageTankSize_log[j] == MinFlow)
- disjunct.no_batch = Constraint(model.PRODUCTS, rule=no_batch_rule)
+ # disjunct.no_volume = pyo.Constraint(expr=model.storageTankSize_log[j] == MinFlow)
+ disjunct.no_batch = pyo.Constraint(model.PRODUCTS, rule=no_batch_rule)
model.storage_tank_selection_disjunct = Disjunct(
[0, 1], model.STAGESExceptLast, rule=storage_tank_selection_disjunct_rule
@@ -270,35 +271,39 @@ def units_out_of_phase_rule(model, j):
model.LogCoeffs[k] * model.outOfPhase[j, k] for k in model.PARALLELUNITS
)
- model.units_out_of_phase = Constraint(model.STAGES, rule=units_out_of_phase_rule)
+ model.units_out_of_phase = pyo.Constraint(
+ model.STAGES, rule=units_out_of_phase_rule
+ )
def units_in_phase_rule(model, j):
return model.unitsInPhase_log[j] == sum(
model.LogCoeffs[k] * model.inPhase[j, k] for k in model.PARALLELUNITS
)
- model.units_in_phase = Constraint(model.STAGES, rule=units_in_phase_rule)
+ model.units_in_phase = pyo.Constraint(model.STAGES, rule=units_in_phase_rule)
# and since I didn't do the disjunction as a disjunction, we need the XORs:
def units_out_of_phase_xor_rule(model, j):
return sum(model.outOfPhase[j, k] for k in model.PARALLELUNITS) == 1
- model.units_out_of_phase_xor = Constraint(
+ model.units_out_of_phase_xor = pyo.Constraint(
model.STAGES, rule=units_out_of_phase_xor_rule
)
def units_in_phase_xor_rule(model, j):
return sum(model.inPhase[j, k] for k in model.PARALLELUNITS) == 1
- model.units_in_phase_xor = Constraint(model.STAGES, rule=units_in_phase_xor_rule)
+ model.units_in_phase_xor = pyo.Constraint(
+ model.STAGES, rule=units_in_phase_xor_rule
+ )
return model
if __name__ == "__main__":
m = build_model().create_instance('batchProcessing1.dat')
- TransformationFactory('gdp.bigm').apply_to(m)
- SolverFactory('gams').solve(
+ pyo.TransformationFactory('gdp.bigm').apply_to(m)
+ pyo.SolverFactory('gams').solve(
m, solver='baron', tee=True, add_options=['option optcr=1e-6;']
)
m.min_cost.display()
diff --git a/examples/gdp/circles/circles.py b/examples/gdp/circles/circles.py
index a8b7a156fad..207baccca05 100644
--- a/examples/gdp/circles/circles.py
+++ b/examples/gdp/circles/circles.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,8 +10,8 @@
# ___________________________________________________________________________
"""
-The "circles" GDP example problem originating in Lee and Grossman (2000). The
-goal is to choose a point to minimize a convex quadratic function over a set of
+The "circles" GDP example problem originating in Lee and Grossman (2000). The
+goal is to choose a point to minimize a convex quadratic function over a set of
disjoint hyperspheres.
"""
diff --git a/examples/gdp/constrained_layout/cons_layout_model.py b/examples/gdp/constrained_layout/cons_layout_model.py
index d38fd0cc66b..54ac1d989c0 100644
--- a/examples/gdp/constrained_layout/cons_layout_model.py
+++ b/examples/gdp/constrained_layout/cons_layout_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/disease_model.py b/examples/gdp/disease_model.py
index 498337e35e6..9ea16b4de43 100644
--- a/examples/gdp/disease_model.py
+++ b/examples/gdp/disease_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -17,8 +17,8 @@
# ============================================
# import packages
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
import math
@@ -1596,10 +1596,8 @@ def build_model():
26,
]
- # from new_data_set import *
-
# declare model name
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
# declare constants
bpy = 26 # biweeks per year
@@ -1607,9 +1605,9 @@ def build_model():
bigM = 50.0 # big M for disjunction constraints
# declare sets
- model.S_meas = RangeSet(1, bpy * years)
- model.S_meas_small = RangeSet(1, bpy * years - 1)
- model.S_beta = RangeSet(1, bpy)
+ model.S_meas = pyo.RangeSet(1, bpy * years)
+ model.S_meas_small = pyo.RangeSet(1, bpy * years - 1)
+ model.S_beta = pyo.RangeSet(1, bpy)
# define variable bounds
def _gt_zero(m, i):
@@ -1621,22 +1619,22 @@ def _beta_bounds(m):
# define variables
# log of estimated cases
- # model.logI = Var(model.S_meas, bounds=_gt_zero)
- model.logI = Var(model.S_meas, bounds=(0.001, 1e7))
+ # model.logI = pyo.Var(model.S_meas, bounds=_gt_zero)
+ model.logI = pyo.Var(model.S_meas, bounds=(0.001, 1e7))
# log of transmission parameter beta
- # model.logbeta = Var(model.S_beta, bounds=_gt_zero)
- model.logbeta = Var(model.S_beta, bounds=(0.0001, 5))
+ # model.logbeta = pyo.Var(model.S_beta, bounds=_gt_zero)
+ model.logbeta = pyo.Var(model.S_beta, bounds=(0.0001, 5))
# binary variable y over all betas
- # model.y = Var(model.S_beta, within=Binary)
+ # model.y = pyo.Var(model.S_beta, within=Binary)
# low value of beta
- # model.logbeta_low = Var(bounds=_beta_bounds)
- model.logbeta_low = Var(bounds=(0.0001, 5))
+ # model.logbeta_low = pyo.Var(bounds=_beta_bounds)
+ model.logbeta_low = pyo.Var(bounds=(0.0001, 5))
# high value of beta
- # model.logbeta_high = Var(bounds=_beta_bounds)
- model.logbeta_high = Var(bounds=(0.0001, 5))
+ # model.logbeta_high = pyo.Var(bounds=_beta_bounds)
+ model.logbeta_high = pyo.Var(bounds=(0.0001, 5))
# dummy variables
- model.p = Var(model.S_meas, bounds=_gt_zero)
- model.n = Var(model.S_meas, bounds=_gt_zero)
+ model.p = pyo.Var(model.S_meas, bounds=_gt_zero)
+ model.n = pyo.Var(model.S_meas, bounds=_gt_zero)
# define indexed constants
@@ -1657,7 +1655,7 @@ def _obj_rule(m):
expr = sum(m.p[i] + m.n[i] for i in m.S_meas)
return expr
- model.obj = Objective(rule=_obj_rule, sense=minimize)
+ model.obj = pyo.Objective(rule=_obj_rule, sense=pyo.minimize)
# define constraints
def _logSIR(m, i):
@@ -1669,26 +1667,30 @@ def _logSIR(m, i):
)
return (0.0, expr)
- model.logSIR = Constraint(model.S_meas_small, rule=_logSIR)
+ model.logSIR = pyo.Constraint(model.S_meas_small, rule=_logSIR)
# objective function constraint
def _p_n_const(m, i):
expr = logIstar[i - 1] - m.logI[i] - m.p[i] + m.n[i]
return (0.0, expr)
- model.p_n_const = Constraint(model.S_meas, rule=_p_n_const)
+ model.p_n_const = pyo.Constraint(model.S_meas, rule=_p_n_const)
# disjuncts
- model.BigM = Suffix()
- model.y = RangeSet(0, 1)
+ model.BigM = pyo.Suffix()
+ model.y = pyo.RangeSet(0, 1)
def _high_low(disjunct, i, y):
model = disjunct.model()
if y:
- disjunct.c = Constraint(expr=model.logbeta_high - model.logbeta[i] == 0.0)
+ disjunct.c = pyo.Constraint(
+ expr=model.logbeta_high - model.logbeta[i] == 0.0
+ )
else:
- disjunct.c = Constraint(expr=model.logbeta[i] - model.logbeta_low == 0.0)
+ disjunct.c = pyo.Constraint(
+ expr=model.logbeta[i] - model.logbeta_low == 0.0
+ )
model.BigM[disjunct.c] = bigM
model.high_low = Disjunct(model.S_beta, model.y, rule=_high_low)
@@ -1707,29 +1709,29 @@ def _disj(model, i):
def highbeta_L(m,i):
expr = m.logbeta[i] - m.logbeta_high + bigM*(1-m.y[i])
return (0.0, expr, None)
-model.highbeta_L = Constraint(model.S_beta, rule=highbeta_L)
+model.highbeta_L = pyo.Constraint(model.S_beta, rule=highbeta_L)
def highbeta_U(m,i):
expr = m.logbeta[i] - m.logbeta_high
return (None, expr, 0.0)
-model.highbeta_U = Constraint(model.S_beta, rule=highbeta_U)
+model.highbeta_U = pyo.Constraint(model.S_beta, rule=highbeta_U)
# low beta disjuncts
def lowbeta_U(m,i):
expr = m.logbeta[i] - m.logbeta_low - bigM*(m.y[i])
return (None, expr, 0.0)
-model.lowbeta_U = Constraint(model.S_beta, rule=lowbeta_U)
+model.lowbeta_U = pyo.Constraint(model.S_beta, rule=lowbeta_U)
def lowbeta_L(m,i):
expr = m.logbeta[i] - m.logbeta_low
return (0.0, expr, None)
-model.lowbeta_L = Constraint(model.S_beta, rule=lowbeta_L)
+model.lowbeta_L = pyo.Constraint(model.S_beta, rule=lowbeta_L)
"""
if __name__ == "__main__":
m = build_model()
- TransformationFactory('gdp.bigm').apply_to(m)
- SolverFactory('gams').solve(
+ pyo.TransformationFactory('gdp.bigm').apply_to(m)
+ pyo.SolverFactory('gams').solve(
m, solver='baron', tee=True, add_options=['option optcr=1e-6;']
)
m.obj.display()
diff --git a/examples/gdp/eight_process/eight_proc_logical.py b/examples/gdp/eight_process/eight_proc_logical.py
index 4496427d421..08331a08513 100644
--- a/examples/gdp/eight_process/eight_proc_logical.py
+++ b/examples/gdp/eight_process/eight_proc_logical.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/eight_process/eight_proc_model.py b/examples/gdp/eight_process/eight_proc_model.py
index 41bb6d462f1..349f7fb5298 100644
--- a/examples/gdp/eight_process/eight_proc_model.py
+++ b/examples/gdp/eight_process/eight_proc_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/eight_process/eight_proc_verbose_model.py b/examples/gdp/eight_process/eight_proc_verbose_model.py
index 1fd68909146..f4150d1f4cc 100644
--- a/examples/gdp/eight_process/eight_proc_verbose_model.py
+++ b/examples/gdp/eight_process/eight_proc_verbose_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/farm_layout/farm_layout.py b/examples/gdp/farm_layout/farm_layout.py
index 1b232b9cfa6..961c85dc9a5 100644
--- a/examples/gdp/farm_layout/farm_layout.py
+++ b/examples/gdp/farm_layout/farm_layout.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,10 +11,10 @@
"""
Farm layout example from Sawaya (2006). The goal is to determine optimal placements and dimensions for farm
-plots of specified areas to minimize the perimeter of a minimal enclosing fence. This is a GDP problem with
-some hyperbolic constraints to establish consistency of areas with length and width. The FLay05 and FLay06
-instances may take some time to solve; the others should be fast. Note that the Sawaya paper contains a
-little bit of nonclarity: it references "height" variables which do not exist - we use "length" for the x-axis
+plots of specified areas to minimize the perimeter of a minimal enclosing fence. This is a GDP problem with
+some hyperbolic constraints to establish consistency of areas with length and width. The FLay05 and FLay06
+instances may take some time to solve; the others should be fast. Note that the Sawaya paper contains a
+little bit of nonclarity: it references "height" variables which do not exist - we use "length" for the x-axis
and "width" on the y-axis, and it also is unclear on the way the coordinates define the rectangles; we have
decided that they are on the bottom-left and adapted the disjunction constraints to match.
"""
diff --git a/examples/gdp/jobshop-nodisjuncts.py b/examples/gdp/jobshop-nodisjuncts.py
index 0cd5b5ab274..96b04170456 100644
--- a/examples/gdp/jobshop-nodisjuncts.py
+++ b/examples/gdp/jobshop-nodisjuncts.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunction
#
# Jobshop example from http://www.gams.com/modlib/libhtml/logmip4.htm
@@ -32,29 +32,29 @@
def build_model():
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.JOBS = Set(ordered=True)
- model.STAGES = Set(ordered=True)
- model.I_BEFORE_K = RangeSet(0, 1)
+ model.JOBS = pyo.Set(ordered=True)
+ model.STAGES = pyo.Set(ordered=True)
+ model.I_BEFORE_K = pyo.RangeSet(0, 1)
# Task durations
- model.tau = Param(model.JOBS, model.STAGES, default=0)
+ model.tau = pyo.Param(model.JOBS, model.STAGES, default=0)
# Total Makespan (this will be the objective)
- model.ms = Var()
+ model.ms = pyo.Var()
# Start time of each job
def t_bounds(model, I):
- return (0, sum(value(model.tau[idx]) for idx in model.tau))
+ return (0, sum(pyo.value(model.tau[idx]) for idx in model.tau))
- model.t = Var(model.JOBS, within=NonNegativeReals, bounds=t_bounds)
+ model.t = pyo.Var(model.JOBS, within=pyo.NonNegativeReals, bounds=t_bounds)
# Auto-generate the L set (potential collisions between 2 jobs at any stage.
def _L_filter(model, I, K, J):
return I < K and model.tau[I, J] and model.tau[K, J]
- model.L = Set(
+ model.L = pyo.Set(
initialize=model.JOBS * model.JOBS * model.STAGES, dimen=3, filter=_L_filter
)
@@ -63,7 +63,7 @@ def _L_filter(model, I, K, J):
def _feas(model, I):
return model.ms >= model.t[I] + sum(model.tau[I, M] for M in model.STAGES)
- model.Feas = Constraint(model.JOBS, rule=_feas)
+ model.Feas = pyo.Constraint(model.JOBS, rule=_feas)
# Define the disjunctions: either job I occurs before K or K before I
def _disj(model, I, K, J):
@@ -74,5 +74,5 @@ def _disj(model, I, K, J):
model.disj = Disjunction(model.L, rule=_disj)
# minimize makespan
- model.makespan = Objective(expr=model.ms)
+ model.makespan = pyo.Objective(expr=model.ms)
return model
diff --git a/examples/gdp/jobshop.py b/examples/gdp/jobshop.py
index 7119ee7655c..90abca0cf10 100644
--- a/examples/gdp/jobshop.py
+++ b/examples/gdp/jobshop.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
#
# Jobshop example from http://www.gams.com/modlib/libhtml/logmip4.htm
@@ -32,29 +32,29 @@
def build_model():
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.JOBS = Set(ordered=True)
- model.STAGES = Set(ordered=True)
- model.I_BEFORE_K = RangeSet(0, 1)
+ model.JOBS = pyo.Set(ordered=True)
+ model.STAGES = pyo.Set(ordered=True)
+ model.I_BEFORE_K = pyo.RangeSet(0, 1)
# Task durations
- model.tau = Param(model.JOBS, model.STAGES, default=0)
+ model.tau = pyo.Param(model.JOBS, model.STAGES, default=0)
# Total Makespan (this will be the objective)
- model.ms = Var()
+ model.ms = pyo.Var()
# Start time of each job
def t_bounds(model, I):
- return (0, sum(value(model.tau[idx]) for idx in model.tau))
+ return (0, sum(pyo.value(model.tau[idx]) for idx in model.tau))
- model.t = Var(model.JOBS, within=NonNegativeReals, bounds=t_bounds)
+ model.t = pyo.Var(model.JOBS, within=pyo.NonNegativeReals, bounds=t_bounds)
# Auto-generate the L set (potential collisions between 2 jobs at any stage.
def _L_filter(model, I, K, J):
return I < K and model.tau[I, J] and model.tau[K, J]
- model.L = Set(
+ model.L = pyo.Set(
initialize=model.JOBS * model.JOBS * model.STAGES, dimen=3, filter=_L_filter
)
@@ -63,7 +63,7 @@ def _L_filter(model, I, K, J):
def _feas(model, I):
return model.ms >= model.t[I] + sum(model.tau[I, M] for M in model.STAGES)
- model.Feas = Constraint(model.JOBS, rule=_feas)
+ model.Feas = pyo.Constraint(model.JOBS, rule=_feas)
# Disjunctions to prevent clashes at a stage: This creates a set of
# disjunct pairs: one if job I occurs before job K and the other if job
@@ -73,9 +73,9 @@ def _NoClash(disjunct, I, K, J, IthenK):
lhs = model.t[I] + sum([M < J and model.tau[I, M] or 0 for M in model.STAGES])
rhs = model.t[K] + sum([M < J and model.tau[K, M] or 0 for M in model.STAGES])
if IthenK:
- disjunct.c = Constraint(expr=lhs + model.tau[I, J] <= rhs)
+ disjunct.c = pyo.Constraint(expr=lhs + model.tau[I, J] <= rhs)
else:
- disjunct.c = Constraint(expr=rhs + model.tau[K, J] <= lhs)
+ disjunct.c = pyo.Constraint(expr=rhs + model.tau[K, J] <= lhs)
model.NoClash = Disjunct(model.L, model.I_BEFORE_K, rule=_NoClash)
@@ -86,14 +86,14 @@ def _disj(model, I, K, J):
model.disj = Disjunction(model.L, rule=_disj)
# minimize makespan
- model.makespan = Objective(expr=model.ms)
+ model.makespan = pyo.Objective(expr=model.ms)
return model
if __name__ == "__main__":
m = build_model().create_instance('jobshop-small.dat')
- TransformationFactory('gdp.bigm').apply_to(m)
- SolverFactory('gams').solve(
+ pyo.TransformationFactory('gdp.bigm').apply_to(m)
+ pyo.SolverFactory('gams').solve(
m, solver='baron', tee=True, add_options=['option optcr=1e-6;']
)
m.makespan.display()
diff --git a/examples/gdp/medTermPurchasing_Literal.py b/examples/gdp/medTermPurchasing_Literal.py
index b6d16c216fe..b0d2e69814a 100755
--- a/examples/gdp/medTermPurchasing_Literal.py
+++ b/examples/gdp/medTermPurchasing_Literal.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
# Medium-term Purchasing Contracts problem from http://minlp.org/library/lib.php?lib=GDP
# This model maximizes profit in a short-term horizon in which various contracts
@@ -31,7 +31,7 @@
def build_model():
- model = AbstractModel()
+ model = pyo.AbstractModel()
# Constants (data that was hard-coded in GAMS model)
AMOUNT_UB = 1000
@@ -48,33 +48,33 @@ def build_model():
# T
# t in GAMS
- model.TimePeriods = Set(ordered=True)
+ model.TimePeriods = pyo.Set(ordered=True)
# Available length contracts
# p in GAMS
- model.Contracts_Length = Set()
+ model.Contracts_Length = pyo.Set()
# JP
# final(j) in GAMS
# Finished products
- model.Products = Set()
+ model.Products = pyo.Set()
# JM
# rawmat(J) in GAMS
# Set of Raw Materials-- raw materials, intermediate products, and final products partition J
- model.RawMaterials = Set()
+ model.RawMaterials = pyo.Set()
# C
# c in GAMS
- model.Contracts = Set()
+ model.Contracts = pyo.Set()
# I
# i in GAMS
- model.Processes = Set()
+ model.Processes = pyo.Set()
# J
# j in GAMS
- model.Streams = Set()
+ model.Streams = pyo.Set()
##################
# Parameters
@@ -82,85 +82,85 @@ def build_model():
# Q_it
# excap(i) in GAMS
- model.Capacity = Param(model.Processes)
+ model.Capacity = pyo.Param(model.Processes)
# u_ijt
# cov(i) in GAMS
- model.ProcessConstants = Param(model.Processes)
+ model.ProcessConstants = pyo.Param(model.Processes)
# a_jt^U and d_jt^U
# spdm(j,t) in GAMS
- model.SupplyAndDemandUBs = Param(model.Streams, model.TimePeriods, default=0)
+ model.SupplyAndDemandUBs = pyo.Param(model.Streams, model.TimePeriods, default=0)
# d_jt^L
# lbdm(j, t) in GAMS
- model.DemandLB = Param(model.Streams, model.TimePeriods, default=0)
+ model.DemandLB = pyo.Param(model.Streams, model.TimePeriods, default=0)
# delta_it
# delta(i, t) in GAMS
# operating cost of process i at time t
- model.OperatingCosts = Param(model.Processes, model.TimePeriods)
+ model.OperatingCosts = pyo.Param(model.Processes, model.TimePeriods)
# prices of raw materials under FP contract and selling prices of products
# pf(j, t) in GAMS
# omega_jt and pf_jt
- model.Prices = Param(model.Streams, model.TimePeriods, default=0)
+ model.Prices = pyo.Param(model.Streams, model.TimePeriods, default=0)
# Price for quantities less than min amount under discount contract
# pd1(j, t) in GAMS
- model.RegPrice_Discount = Param(model.Streams, model.TimePeriods)
+ model.RegPrice_Discount = pyo.Param(model.Streams, model.TimePeriods)
# Discounted price for the quantity purchased exceeding the min amount
# pd2(j,t0 in GAMS
- model.DiscountPrice_Discount = Param(model.Streams, model.TimePeriods)
+ model.DiscountPrice_Discount = pyo.Param(model.Streams, model.TimePeriods)
# Price for quantities below min amount
# pb1(j,t) in GAMS
- model.RegPrice_Bulk = Param(model.Streams, model.TimePeriods)
+ model.RegPrice_Bulk = pyo.Param(model.Streams, model.TimePeriods)
# Price for quantities above min amount
# pb2(j, t) in GAMS
- model.DiscountPrice_Bulk = Param(model.Streams, model.TimePeriods)
+ model.DiscountPrice_Bulk = pyo.Param(model.Streams, model.TimePeriods)
# prices with length contract
# pl(j, p, t) in GAMS
- model.Prices_Length = Param(
+ model.Prices_Length = pyo.Param(
model.Streams, model.Contracts_Length, model.TimePeriods, default=0
)
# sigmad_jt
# sigmad(j, t) in GAMS
# Minimum quantity of chemical j that must be bought before receiving a Discount under discount contract
- model.MinAmount_Discount = Param(model.Streams, model.TimePeriods, default=0)
+ model.MinAmount_Discount = pyo.Param(model.Streams, model.TimePeriods, default=0)
# min quantity to receive discount under bulk contract
# sigmab(j, t) in GAMS
- model.MinAmount_Bulk = Param(model.Streams, model.TimePeriods, default=0)
+ model.MinAmount_Bulk = pyo.Param(model.Streams, model.TimePeriods, default=0)
# min quantity to receive discount under length contract
# sigmal(j, p) in GAMS
- model.MinAmount_Length = Param(model.Streams, model.Contracts_Length, default=0)
+ model.MinAmount_Length = pyo.Param(model.Streams, model.Contracts_Length, default=0)
# main products of process i
# These are 1 (true) if stream j is the main product of process i, false otherwise.
# jm(j, i) in GAMS
- model.MainProducts = Param(model.Streams, model.Processes, default=0)
+ model.MainProducts = pyo.Param(model.Streams, model.Processes, default=0)
# theta_jt
# psf(j, t) in GAMS
# Shortfall penalty of product j at time t
- model.ShortfallPenalty = Param(model.Products, model.TimePeriods)
+ model.ShortfallPenalty = pyo.Param(model.Products, model.TimePeriods)
# shortfall upper bound
# sfub(j, t) in GAMS
- model.ShortfallUB = Param(model.Products, model.TimePeriods, default=0)
+ model.ShortfallUB = pyo.Param(model.Products, model.TimePeriods, default=0)
# epsilon_jt
# cinv(j, t) in GAMS
# inventory cost of material j at time t
- model.InventoryCost = Param(model.Streams, model.TimePeriods)
+ model.InventoryCost = pyo.Param(model.Streams, model.TimePeriods)
# invub(j, t) in GAMS
# inventory upper bound
- model.InventoryLevelUB = Param(model.Streams, model.TimePeriods, default=0)
+ model.InventoryLevelUB = pyo.Param(model.Streams, model.TimePeriods, default=0)
## UPPER BOUNDS HARDCODED INTO GAMS MODEL
@@ -172,31 +172,33 @@ def getAmountUBs(model, j, t):
def getCostUBs(model, j, t):
return COST_UB
- model.AmountPurchasedUB_FP = Param(
+ model.AmountPurchasedUB_FP = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.AmountPurchasedUB_Discount = Param(
+ model.AmountPurchasedUB_Discount = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.AmountPurchasedBelowMinUB_Discount = Param(
+ model.AmountPurchasedBelowMinUB_Discount = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.AmountPurchasedAboveMinUB_Discount = Param(
+ model.AmountPurchasedAboveMinUB_Discount = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.AmountPurchasedUB_FD = Param(
+ model.AmountPurchasedUB_FD = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.AmountPurchasedUB_Bulk = Param(
+ model.AmountPurchasedUB_Bulk = pyo.Param(
model.Streams, model.TimePeriods, initialize=getAmountUBs
)
- model.CostUB_FP = Param(model.Streams, model.TimePeriods, initialize=getCostUBs)
- model.CostUB_FD = Param(model.Streams, model.TimePeriods, initialize=getCostUBs)
- model.CostUB_Discount = Param(
+ model.CostUB_FP = pyo.Param(model.Streams, model.TimePeriods, initialize=getCostUBs)
+ model.CostUB_FD = pyo.Param(model.Streams, model.TimePeriods, initialize=getCostUBs)
+ model.CostUB_Discount = pyo.Param(
+ model.Streams, model.TimePeriods, initialize=getCostUBs
+ )
+ model.CostUB_Bulk = pyo.Param(
model.Streams, model.TimePeriods, initialize=getCostUBs
)
- model.CostUB_Bulk = Param(model.Streams, model.TimePeriods, initialize=getCostUBs)
####################
# VARIABLES
@@ -204,11 +206,13 @@ def getCostUBs(model, j, t):
# prof in GAMS
# will be objective
- model.Profit = Var()
+ model.Profit = pyo.Var()
# f(j, t) in GAMS
# mass flow rates in tons per time interval t
- model.FlowRate = Var(model.Streams, model.TimePeriods, within=NonNegativeReals)
+ model.FlowRate = pyo.Var(
+ model.Streams, model.TimePeriods, within=pyo.NonNegativeReals
+ )
# V_jt
# inv(j, t) in GAMS
@@ -216,7 +220,7 @@ def getCostUBs(model, j, t):
def getInventoryBounds(model, i, j):
return (0, model.InventoryLevelUB[i, j])
- model.InventoryLevel = Var(
+ model.InventoryLevel = pyo.Var(
model.Streams, model.TimePeriods, bounds=getInventoryBounds
)
@@ -226,7 +230,9 @@ def getInventoryBounds(model, i, j):
def getShortfallBounds(model, i, j):
return (0, model.ShortfallUB[i, j])
- model.Shortfall = Var(model.Products, model.TimePeriods, bounds=getShortfallBounds)
+ model.Shortfall = pyo.Var(
+ model.Products, model.TimePeriods, bounds=getShortfallBounds
+ )
# amounts purchased under different contracts
@@ -235,7 +241,7 @@ def getShortfallBounds(model, i, j):
def get_FP_bounds(model, j, t):
return (0, model.AmountPurchasedUB_FP[j, t])
- model.AmountPurchased_FP = Var(
+ model.AmountPurchased_FP = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_FP_bounds
)
@@ -243,7 +249,7 @@ def get_FP_bounds(model, j, t):
def get_Discount_Total_bounds(model, j, t):
return (0, model.AmountPurchasedUB_Discount[j, t])
- model.AmountPurchasedTotal_Discount = Var(
+ model.AmountPurchasedTotal_Discount = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_Discount_Total_bounds
)
@@ -252,7 +258,7 @@ def get_Discount_Total_bounds(model, j, t):
def get_Discount_BelowMin_bounds(model, j, t):
return (0, model.AmountPurchasedBelowMinUB_Discount[j, t])
- model.AmountPurchasedBelowMin_Discount = Var(
+ model.AmountPurchasedBelowMin_Discount = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_Discount_BelowMin_bounds
)
@@ -261,7 +267,7 @@ def get_Discount_BelowMin_bounds(model, j, t):
def get_Discount_AboveMin_bounds(model, j, t):
return (0, model.AmountPurchasedBelowMinUB_Discount[j, t])
- model.AmountPurchasedAboveMin_Discount = Var(
+ model.AmountPurchasedAboveMin_Discount = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_Discount_AboveMin_bounds
)
@@ -270,7 +276,7 @@ def get_Discount_AboveMin_bounds(model, j, t):
def get_bulk_bounds(model, j, t):
return (0, model.AmountPurchasedUB_Bulk[j, t])
- model.AmountPurchased_Bulk = Var(
+ model.AmountPurchased_Bulk = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_bulk_bounds
)
@@ -279,7 +285,7 @@ def get_bulk_bounds(model, j, t):
def get_FD_bounds(model, j, t):
return (0, model.AmountPurchasedUB_FD[j, t])
- model.AmountPurchased_FD = Var(
+ model.AmountPurchased_FD = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_FD_bounds
)
@@ -290,21 +296,21 @@ def get_FD_bounds(model, j, t):
def get_CostUBs_FD(model, j, t):
return (0, model.CostUB_FD[j, t])
- model.Cost_FD = Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_FD)
+ model.Cost_FD = pyo.Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_FD)
# costpf(j, t) in GAMS
# cost of fixed duration contract
def get_CostUBs_FP(model, j, t):
return (0, model.CostUB_FP[j, t])
- model.Cost_FP = Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_FP)
+ model.Cost_FP = pyo.Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_FP)
# costpd(j, t) in GAMS
# cost of discount contract
def get_CostUBs_Discount(model, j, t):
return (0, model.CostUB_Discount[j, t])
- model.Cost_Discount = Var(
+ model.Cost_Discount = pyo.Var(
model.Streams, model.TimePeriods, bounds=get_CostUBs_Discount
)
@@ -313,14 +319,18 @@ def get_CostUBs_Discount(model, j, t):
def get_CostUBs_Bulk(model, j, t):
return (0, model.CostUB_Bulk[j, t])
- model.Cost_Bulk = Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_Bulk)
+ model.Cost_Bulk = pyo.Var(model.Streams, model.TimePeriods, bounds=get_CostUBs_Bulk)
# binary variables
- model.BuyFPContract = RangeSet(0, 1)
- model.BuyDiscountContract = Set(initialize=('BelowMin', 'AboveMin', 'NotSelected'))
- model.BuyBulkContract = Set(initialize=('BelowMin', 'AboveMin', 'NotSelected'))
- model.BuyFDContract = Set(initialize=('1Month', '2Month', '3Month', 'NotSelected'))
+ model.BuyFPContract = pyo.RangeSet(0, 1)
+ model.BuyDiscountContract = pyo.Set(
+ initialize=('BelowMin', 'AboveMin', 'NotSelected')
+ )
+ model.BuyBulkContract = pyo.Set(initialize=('BelowMin', 'AboveMin', 'NotSelected'))
+ model.BuyFDContract = pyo.Set(
+ initialize=('1Month', '2Month', '3Month', 'NotSelected')
+ )
################
# CONSTRAINTS
@@ -377,7 +387,7 @@ def profit_rule(model):
salesIncome - purchaseCost - productionCost - inventoryCost - shortfallCost
)
- model.profit = Objective(rule=profit_rule, sense=maximize)
+ model.profit = pyo.Objective(rule=profit_rule, sense=pyo.maximize)
# flow of raw materials is the total amount purchased (across all contracts)
def raw_material_flow_rule(model, j, t):
@@ -389,7 +399,7 @@ def raw_material_flow_rule(model, j, t):
+ model.AmountPurchasedTotal_Discount[j, t]
)
- model.raw_material_flow = Constraint(
+ model.raw_material_flow = pyo.Constraint(
model.RawMaterials, model.TimePeriods, rule=raw_material_flow_rule
)
@@ -400,7 +410,7 @@ def discount_amount_total_rule(model, j, t):
+ model.AmountPurchasedAboveMin_Discount[j, t]
)
- model.discount_amount_total_rule = Constraint(
+ model.discount_amount_total_rule = pyo.Constraint(
model.RawMaterials, model.TimePeriods, rule=discount_amount_total_rule
)
@@ -409,36 +419,40 @@ def discount_amount_total_rule(model, j, t):
def mass_balance_rule1(model, t):
return model.FlowRate[1, t] == model.FlowRate[2, t] + model.FlowRate[3, t]
- model.mass_balance1 = Constraint(model.TimePeriods, rule=mass_balance_rule1)
+ model.mass_balance1 = pyo.Constraint(model.TimePeriods, rule=mass_balance_rule1)
def mass_balance_rule2(model, t):
return model.FlowRate[5, t] == model.FlowRate[4, t] + model.FlowRate[8, t]
- model.mass_balance2 = Constraint(model.TimePeriods, rule=mass_balance_rule2)
+ model.mass_balance2 = pyo.Constraint(model.TimePeriods, rule=mass_balance_rule2)
def mass_balance_rule3(model, t):
return model.FlowRate[6, t] == model.FlowRate[7, t]
- model.mass_balance3 = Constraint(model.TimePeriods, rule=mass_balance_rule3)
+ model.mass_balance3 = pyo.Constraint(model.TimePeriods, rule=mass_balance_rule3)
def mass_balance_rule4(model, t):
return model.FlowRate[3, t] == 10 * model.FlowRate[5, t]
- model.mass_balance4 = Constraint(model.TimePeriods, rule=mass_balance_rule4)
+ model.mass_balance4 = pyo.Constraint(model.TimePeriods, rule=mass_balance_rule4)
# process input/output constraints
# these are also totally specific to the process network
def process_balance_rule1(model, t):
return model.FlowRate[9, t] == model.ProcessConstants[1] * model.FlowRate[2, t]
- model.process_balance1 = Constraint(model.TimePeriods, rule=process_balance_rule1)
+ model.process_balance1 = pyo.Constraint(
+ model.TimePeriods, rule=process_balance_rule1
+ )
def process_balance_rule2(model, t):
return model.FlowRate[10, t] == model.ProcessConstants[2] * (
model.FlowRate[5, t] + model.FlowRate[3, t]
)
- model.process_balance2 = Constraint(model.TimePeriods, rule=process_balance_rule2)
+ model.process_balance2 = pyo.Constraint(
+ model.TimePeriods, rule=process_balance_rule2
+ )
def process_balance_rule3(model, t):
return (
@@ -446,7 +460,9 @@ def process_balance_rule3(model, t):
== RandomConst_Line264 * model.ProcessConstants[3] * model.FlowRate[7, t]
)
- model.process_balance3 = Constraint(model.TimePeriods, rule=process_balance_rule3)
+ model.process_balance3 = pyo.Constraint(
+ model.TimePeriods, rule=process_balance_rule3
+ )
def process_balance_rule4(model, t):
return (
@@ -454,24 +470,32 @@ def process_balance_rule4(model, t):
== RandomConst_Line265 * model.ProcessConstants[3] * model.FlowRate[7, t]
)
- model.process_balance4 = Constraint(model.TimePeriods, rule=process_balance_rule4)
+ model.process_balance4 = pyo.Constraint(
+ model.TimePeriods, rule=process_balance_rule4
+ )
# process capacity constraints
# these are hardcoded based on the three processes and the process flow structure
def process_capacity_rule1(model, t):
return model.FlowRate[9, t] <= model.Capacity[1]
- model.process_capacity1 = Constraint(model.TimePeriods, rule=process_capacity_rule1)
+ model.process_capacity1 = pyo.Constraint(
+ model.TimePeriods, rule=process_capacity_rule1
+ )
def process_capacity_rule2(model, t):
return model.FlowRate[10, t] <= model.Capacity[2]
- model.process_capacity2 = Constraint(model.TimePeriods, rule=process_capacity_rule2)
+ model.process_capacity2 = pyo.Constraint(
+ model.TimePeriods, rule=process_capacity_rule2
+ )
def process_capacity_rule3(model, t):
return model.FlowRate[11, t] + model.FlowRate[8, t] <= model.Capacity[3]
- model.process_capacity3 = Constraint(model.TimePeriods, rule=process_capacity_rule3)
+ model.process_capacity3 = pyo.Constraint(
+ model.TimePeriods, rule=process_capacity_rule3
+ )
# Inventory balance of final products
# again, these are hardcoded.
@@ -483,23 +507,25 @@ def inventory_balance1(model, t):
== model.FlowRate[12, t] + model.InventoryLevel[12, t]
)
- model.inventory_balance1 = Constraint(model.TimePeriods, rule=inventory_balance1)
+ model.inventory_balance1 = pyo.Constraint(
+ model.TimePeriods, rule=inventory_balance1
+ )
def inventory_balance_rule2(model, t):
if t != 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
model.FlowRate[10, t] + model.FlowRate[11, t]
== model.InventoryLevel[13, t] + model.FlowRate[13, t]
)
- model.inventory_balance2 = Constraint(
+ model.inventory_balance2 = pyo.Constraint(
model.TimePeriods, rule=inventory_balance_rule2
)
def inventory_balance_rule3(model, t):
if t <= 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
model.InventoryLevel[13, t - 1]
+ model.FlowRate[10, t]
@@ -507,7 +533,7 @@ def inventory_balance_rule3(model, t):
== model.InventoryLevel[13, t] + model.FlowRate[13, t]
)
- model.inventory_balance3 = Constraint(
+ model.inventory_balance3 = pyo.Constraint(
model.TimePeriods, rule=inventory_balance_rule3
)
@@ -515,7 +541,7 @@ def inventory_balance_rule3(model, t):
def inventory_capacity_rule(model, j, t):
return model.InventoryLevel[j, t] <= model.InventoryLevelUB[j, t]
- model.inventory_capacity_rule = Constraint(
+ model.inventory_capacity_rule = pyo.Constraint(
model.Products, model.TimePeriods, rule=inventory_capacity_rule
)
@@ -526,13 +552,15 @@ def shortfall_rule(model, j, t):
== model.SupplyAndDemandUBs[j, t] - model.FlowRate[j, t]
)
- model.shortfall = Constraint(model.Products, model.TimePeriods, rule=shortfall_rule)
+ model.shortfall = pyo.Constraint(
+ model.Products, model.TimePeriods, rule=shortfall_rule
+ )
# maximum shortfall allowed
def shortfall_max_rule(model, j, t):
return model.Shortfall[j, t] <= model.ShortfallUB[j, t]
- model.shortfall_max = Constraint(
+ model.shortfall_max = pyo.Constraint(
model.Products, model.TimePeriods, rule=shortfall_max_rule
)
@@ -540,7 +568,7 @@ def shortfall_max_rule(model, j, t):
def supplier_capacity_rule(model, j, t):
return model.FlowRate[j, t] <= model.SupplyAndDemandUBs[j, t]
- model.supplier_capacity = Constraint(
+ model.supplier_capacity = pyo.Constraint(
model.RawMaterials, model.TimePeriods, rule=supplier_capacity_rule
)
@@ -548,13 +576,17 @@ def supplier_capacity_rule(model, j, t):
def demand_UB_rule(model, j, t):
return model.FlowRate[j, t] <= model.SupplyAndDemandUBs[j, t]
- model.demand_UB = Constraint(model.Products, model.TimePeriods, rule=demand_UB_rule)
+ model.demand_UB = pyo.Constraint(
+ model.Products, model.TimePeriods, rule=demand_UB_rule
+ )
# demand lower bound
def demand_LB_rule(model, j, t):
return model.FlowRate[j, t] >= model.DemandLB[j, t]
- model.demand_LB = Constraint(model.Products, model.TimePeriods, rule=demand_LB_rule)
+ model.demand_LB = pyo.Constraint(
+ model.Products, model.TimePeriods, rule=demand_LB_rule
+ )
# FIXED PRICE CONTRACT
@@ -562,11 +594,11 @@ def demand_LB_rule(model, j, t):
def FP_contract_disjunct_rule(disjunct, j, t, buy):
model = disjunct.model()
if buy:
- disjunct.c = Constraint(
+ disjunct.c = pyo.Constraint(
expr=model.AmountPurchased_FP[j, t] <= MAX_AMOUNT_FP
)
else:
- disjunct.c = Constraint(expr=model.AmountPurchased_FP[j, t] == 0)
+ disjunct.c = pyo.Constraint(expr=model.AmountPurchased_FP[j, t] == 0)
model.FP_contract_disjunct = Disjunct(
model.RawMaterials,
@@ -589,7 +621,7 @@ def FP_contract_cost_rule(model, j, t):
model.Cost_FP[j, t] == model.AmountPurchased_FP[j, t] * model.Prices[j, t]
)
- model.FP_contract_cost = Constraint(
+ model.FP_contract_cost = pyo.Constraint(
model.RawMaterials, model.TimePeriods, rule=FP_contract_cost_rule
)
@@ -599,26 +631,26 @@ def FP_contract_cost_rule(model, j, t):
def discount_contract_disjunct_rule(disjunct, j, t, buy):
model = disjunct.model()
if buy == 'BelowMin':
- disjunct.belowMin = Constraint(
+ disjunct.belowMin = pyo.Constraint(
expr=model.AmountPurchasedBelowMin_Discount[j, t]
<= model.MinAmount_Discount[j, t]
)
- disjunct.aboveMin = Constraint(
+ disjunct.aboveMin = pyo.Constraint(
expr=model.AmountPurchasedAboveMin_Discount[j, t] == 0
)
elif buy == 'AboveMin':
- disjunct.belowMin = Constraint(
+ disjunct.belowMin = pyo.Constraint(
expr=model.AmountPurchasedBelowMin_Discount[j, t]
== model.MinAmount_Discount[j, t]
)
- disjunct.aboveMin = Constraint(
+ disjunct.aboveMin = pyo.Constraint(
expr=model.AmountPurchasedAboveMin_Discount[j, t] >= 0
)
elif buy == 'NotSelected':
- disjunct.belowMin = Constraint(
+ disjunct.belowMin = pyo.Constraint(
expr=model.AmountPurchasedBelowMin_Discount[j, t] == 0
)
- disjunct.aboveMin = Constraint(
+ disjunct.aboveMin = pyo.Constraint(
expr=model.AmountPurchasedAboveMin_Discount[j, t] == 0
)
else:
@@ -652,7 +684,7 @@ def discount_cost_rule(model, j, t):
* model.AmountPurchasedAboveMin_Discount[j, t]
)
- model.discount_cost = Constraint(
+ model.discount_cost = pyo.Constraint(
model.RawMaterials, model.TimePeriods, rule=discount_cost_rule
)
@@ -662,24 +694,24 @@ def discount_cost_rule(model, j, t):
def bulk_contract_disjunct_rule(disjunct, j, t, buy):
model = disjunct.model()
if buy == 'BelowMin':
- disjunct.amount = Constraint(
+ disjunct.amount = pyo.Constraint(
expr=model.AmountPurchased_Bulk[j, t] <= model.MinAmount_Bulk[j, t]
)
- disjunct.price = Constraint(
+ disjunct.price = pyo.Constraint(
expr=model.Cost_Bulk[j, t]
== model.RegPrice_Bulk[j, t] * model.AmountPurchased_Bulk[j, t]
)
elif buy == 'AboveMin':
- disjunct.amount = Constraint(
+ disjunct.amount = pyo.Constraint(
expr=model.AmountPurchased_Bulk[j, t] >= model.MinAmount_Bulk[j, t]
)
- disjunct.price = Constraint(
+ disjunct.price = pyo.Constraint(
expr=model.Cost_Bulk[j, t]
== model.DiscountPrice_Bulk[j, t] * model.AmountPurchased_Bulk[j, t]
)
elif buy == 'NotSelected':
- disjunct.amount = Constraint(expr=model.AmountPurchased_Bulk[j, t] == 0)
- disjunct.price = Constraint(expr=model.Cost_Bulk[j, t] == 0)
+ disjunct.amount = pyo.Constraint(expr=model.AmountPurchased_Bulk[j, t] == 0)
+ disjunct.price = pyo.Constraint(expr=model.Cost_Bulk[j, t] == 0)
else:
raise RuntimeError("Unrecognized choice for bulk contract: %s" % buy)
@@ -704,10 +736,10 @@ def bulk_contract_rule(model, j, t):
def FD_1mo_contract(disjunct, j, t):
model = disjunct.model()
- disjunct.amount1 = Constraint(
+ disjunct.amount1 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t] >= MIN_AMOUNT_FD_1MONTH
)
- disjunct.price1 = Constraint(
+ disjunct.price1 = pyo.Constraint(
expr=model.Cost_FD[j, t]
== model.Prices_Length[j, 1, t] * model.AmountPurchased_FD[j, t]
)
@@ -718,19 +750,19 @@ def FD_1mo_contract(disjunct, j, t):
def FD_2mo_contract(disjunct, j, t):
model = disjunct.model()
- disjunct.amount1 = Constraint(
+ disjunct.amount1 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t] >= model.MinAmount_Length[j, 2]
)
- disjunct.price1 = Constraint(
+ disjunct.price1 = pyo.Constraint(
expr=model.Cost_FD[j, t]
== model.Prices_Length[j, 2, t] * model.AmountPurchased_FD[j, t]
)
# only enforce these if we aren't in the last time period
if t < model.TimePeriods[-1]:
- disjunct.amount2 = Constraint(
+ disjunct.amount2 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t + 1] >= model.MinAmount_Length[j, 2]
)
- disjunct.price2 = Constraint(
+ disjunct.price2 = pyo.Constraint(
expr=model.Cost_FD[j, t + 1]
== model.Prices_Length[j, 2, t] * model.AmountPurchased_FD[j, t + 1]
)
@@ -744,27 +776,27 @@ def FD_3mo_contract(disjunct, j, t):
# NOTE: I think there is a mistake in the GAMS file in line 327.
# they use the bulk minamount rather than the length one.
# I am doing the same here for validation purposes.
- disjunct.amount1 = Constraint(
+ disjunct.amount1 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t] >= model.MinAmount_Bulk[j, 3]
)
- disjunct.cost1 = Constraint(
+ disjunct.cost1 = pyo.Constraint(
expr=model.Cost_FD[j, t]
== model.Prices_Length[j, 3, t] * model.AmountPurchased_FD[j, t]
)
# check we aren't in one of the last two time periods
if t < model.TimePeriods[-1]:
- disjunct.amount2 = Constraint(
+ disjunct.amount2 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t + 1] >= model.MinAmount_Length[j, 3]
)
- disjunct.cost2 = Constraint(
+ disjunct.cost2 = pyo.Constraint(
expr=model.Cost_FD[j, t + 1]
== model.Prices_Length[j, 3, t] * model.AmountPurchased_FD[j, t + 1]
)
if t < model.TimePeriods[-2]:
- disjunct.amount3 = Constraint(
+ disjunct.amount3 = pyo.Constraint(
expr=model.AmountPurchased_FD[j, t + 2] >= model.MinAmount_Length[j, 3]
)
- disjunct.cost3 = Constraint(
+ disjunct.cost3 = pyo.Constraint(
expr=model.Cost_FD[j, t + 2]
== model.Prices_Length[j, 3, t] * model.AmountPurchased_FD[j, t + 2]
)
@@ -775,14 +807,18 @@ def FD_3mo_contract(disjunct, j, t):
def FD_no_contract(disjunct, j, t):
model = disjunct.model()
- disjunct.amount1 = Constraint(expr=model.AmountPurchased_FD[j, t] == 0)
- disjunct.cost1 = Constraint(expr=model.Cost_FD[j, t] == 0)
+ disjunct.amount1 = pyo.Constraint(expr=model.AmountPurchased_FD[j, t] == 0)
+ disjunct.cost1 = pyo.Constraint(expr=model.Cost_FD[j, t] == 0)
if t < model.TimePeriods[-1]:
- disjunct.amount2 = Constraint(expr=model.AmountPurchased_FD[j, t + 1] == 0)
- disjunct.cost2 = Constraint(expr=model.Cost_FD[j, t + 1] == 0)
+ disjunct.amount2 = pyo.Constraint(
+ expr=model.AmountPurchased_FD[j, t + 1] == 0
+ )
+ disjunct.cost2 = pyo.Constraint(expr=model.Cost_FD[j, t + 1] == 0)
if t < model.TimePeriods[-2]:
- disjunct.amount3 = Constraint(expr=model.AmountPurchased_FD[j, t + 2] == 0)
- disjunct.cost3 = Constraint(expr=model.Cost_FD[j, t + 2] == 0)
+ disjunct.amount3 = pyo.Constraint(
+ expr=model.AmountPurchased_FD[j, t + 2] == 0
+ )
+ disjunct.cost3 = pyo.Constraint(expr=model.Cost_FD[j, t + 2] == 0)
model.FD_no_contract = Disjunct(
model.RawMaterials, model.TimePeriods, rule=FD_no_contract
@@ -805,8 +841,8 @@ def FD_contract(model, j, t):
if __name__ == "__main__":
m = build_model().create_instance('medTermPurchasing_Literal_Hull.dat')
- TransformationFactory('gdp.bigm').apply_to(m)
- SolverFactory('gams').solve(
+ pyo.TransformationFactory('gdp.bigm').apply_to(m)
+ pyo.SolverFactory('gams').solve(
m, solver='baron', tee=True, add_options=['option optcr=1e-6;']
)
m.profit.display()
diff --git a/examples/gdp/nine_process/small_process.py b/examples/gdp/nine_process/small_process.py
index 2abffef1af6..6431966dcc5 100644
--- a/examples/gdp/nine_process/small_process.py
+++ b/examples/gdp/nine_process/small_process.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-"""Small process synthesis-inspired toy GDP example.
-
-"""
+"""Small process synthesis-inspired toy GDP example."""
from pyomo.core import ConcreteModel, RangeSet, Var, Constraint, Objective
from pyomo.core.expr.current import exp, log, sqrt
diff --git a/examples/gdp/simple1.py b/examples/gdp/simple1.py
index de41c0bfd00..4ac28153ad7 100644
--- a/examples/gdp/simple1.py
+++ b/examples/gdp/simple1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -15,26 +15,26 @@
# This model does not work with existing transformations.
# See simple2.py and simple3.py for variants that work.
-from pyomo.core import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
def build_model():
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
# x >= 0 _|_ y>=0
- model.x = Var(bounds=(0, None))
- model.y = Var(bounds=(0, None))
+ model.x = pyo.Var(bounds=(0, None))
+ model.y = pyo.Var(bounds=(0, None))
# Two conditions
def _d(disjunct, flag):
model = disjunct.model()
if flag:
# x == 0
- disjunct.c = Constraint(expr=model.x == 0)
+ disjunct.c = pyo.Constraint(expr=model.x == 0)
else:
# y == 0
- disjunct.c = Constraint(expr=model.y == 0)
+ disjunct.c = pyo.Constraint(expr=model.y == 0)
model.d = Disjunct([0, 1], rule=_d)
@@ -44,7 +44,7 @@ def _c(model):
model.c = Disjunction(rule=_c)
- model.C = Constraint(expr=model.x + model.y <= 1)
+ model.C = pyo.Constraint(expr=model.x + model.y <= 1)
- model.o = Objective(expr=2 * model.x + 3 * model.y, sense=maximize)
+ model.o = pyo.Objective(expr=2 * model.x + 3 * model.y, sense=pyo.maximize)
return model
diff --git a/examples/gdp/simple2.py b/examples/gdp/simple2.py
index b066d705036..d5efd07565c 100644
--- a/examples/gdp/simple2.py
+++ b/examples/gdp/simple2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,26 +14,26 @@
#
# Specifying variable bounds
-from pyomo.core import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
def build_model():
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
# x >= 0 _|_ y>=0
- model.x = Var(bounds=(0, 100))
- model.y = Var(bounds=(0, 100))
+ model.x = pyo.Var(bounds=(0, 100))
+ model.y = pyo.Var(bounds=(0, 100))
# Two conditions
def _d(disjunct, flag):
model = disjunct.model()
if flag:
# x == 0
- disjunct.c = Constraint(expr=model.x == 0)
+ disjunct.c = pyo.Constraint(expr=model.x == 0)
else:
# y == 0
- disjunct.c = Constraint(expr=model.y == 0)
+ disjunct.c = pyo.Constraint(expr=model.y == 0)
model.d = Disjunct([0, 1], rule=_d)
@@ -43,7 +43,7 @@ def _c(model):
model.c = Disjunction(rule=_c)
- model.C = Constraint(expr=model.x + model.y <= 1)
+ model.C = pyo.Constraint(expr=model.x + model.y <= 1)
- model.o = Objective(expr=2 * model.x + 3 * model.y, sense=maximize)
+ model.o = pyo.Objective(expr=2 * model.x + 3 * model.y, sense=pyo.maximize)
return model
diff --git a/examples/gdp/simple3.py b/examples/gdp/simple3.py
index 890daf8882b..b7d80ce6436 100644
--- a/examples/gdp/simple3.py
+++ b/examples/gdp/simple3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,27 +14,27 @@
#
# Specifying BigM suffix values for the gdp.bigm transformation
-from pyomo.core import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
def build_model():
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
# x >= 0 _|_ y>=0
- model.x = Var(bounds=(0, None))
- model.y = Var(bounds=(0, None))
+ model.x = pyo.Var(bounds=(0, None))
+ model.y = pyo.Var(bounds=(0, None))
# Two conditions
def _d(disjunct, flag):
model = disjunct.model()
if flag:
# x == 0
- disjunct.c = Constraint(expr=model.x == 0)
+ disjunct.c = pyo.Constraint(expr=model.x == 0)
else:
# y == 0
- disjunct.c = Constraint(expr=model.y == 0)
- disjunct.BigM = Suffix()
+ disjunct.c = pyo.Constraint(expr=model.y == 0)
+ disjunct.BigM = pyo.Suffix()
disjunct.BigM[disjunct.c] = 1
model.d = Disjunct([0, 1], rule=_d)
@@ -45,8 +45,8 @@ def _c(model):
model.c = Disjunction(rule=_c)
- model.C = Constraint(expr=model.x + model.y <= 1)
+ model.C = pyo.Constraint(expr=model.x + model.y <= 1)
- model.o = Objective(expr=2 * model.x + 3 * model.y, sense=maximize)
+ model.o = pyo.Objective(expr=2 * model.x + 3 * model.y, sense=pyo.maximize)
return model
diff --git a/examples/gdp/small_lit/basic_step.py b/examples/gdp/small_lit/basic_step.py
index 2d9da97167c..a31739be26f 100644
--- a/examples/gdp/small_lit/basic_step.py
+++ b/examples/gdp/small_lit/basic_step.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,10 +9,10 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-""" Example from Section 3.2 in paper of Pseudo Basic Steps
+"""Example from Section 3.2 in paper of Pseudo Basic Steps
Ref:
- Pseudo basic steps: bound improvement guarantees from Lagrangian
+ Pseudo basic steps: bound improvement guarantees from Lagrangian
decomposition in convex disjunctive programming
Papageorgiou and Trespalacios, 2017
@@ -21,38 +21,38 @@
Pyomo model implementation by @RomeoV
"""
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct
from pyomo.gdp.basic_step import apply_basic_step
def build_gdp_model():
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.x1 = Var(bounds=(-1, 6), initialize=0)
- model.x2 = Var(bounds=(0, 7), initialize=3.5)
+ model.x1 = pyo.Var(bounds=(-1, 6), initialize=0)
+ model.x2 = pyo.Var(bounds=(0, 7), initialize=3.5)
- model.objective = Objective(expr=0.2 * model.x1 + model.x2)
- model.disjunction_set = RangeSet(1, 3)
+ model.objective = pyo.Objective(expr=0.2 * model.x1 + model.x2)
+ model.disjunction_set = pyo.RangeSet(1, 3)
model.disjuncts = Disjunct([1, 2, 3], [1, 2])
- model.disjuncts[1, 1].c = Constraint(
+ model.disjuncts[1, 1].c = pyo.Constraint(
expr=model.x1**2 + (1 / 4) * (model.x2 - 5) ** 2 <= 1
)
- model.disjuncts[2, 1].c = Constraint(
+ model.disjuncts[2, 1].c = pyo.Constraint(
expr=model.x1**2 + (1 / 4) * (model.x2 - 2) ** 2 <= 1
)
- model.disjuncts[3, 1].c = Constraint(
+ model.disjuncts[3, 1].c = pyo.Constraint(
expr=model.x1**2 + (1 / 4) * (model.x2 - 3.5) ** 2 <= 1
)
- model.disjuncts[1, 2].c = Constraint(
+ model.disjuncts[1, 2].c = pyo.Constraint(
expr=(model.x1 - 5) ** 2 + (1 / 4) * (model.x2 - 2) ** 2 <= 1
)
- model.disjuncts[2, 2].c = Constraint(
+ model.disjuncts[2, 2].c = pyo.Constraint(
expr=(model.x1 - 5) ** 2 + (1 / 4) * (model.x2 - 5) ** 2 <= 1
)
- model.disjuncts[3, 2].c = Constraint(
+ model.disjuncts[3, 2].c = pyo.Constraint(
expr=(model.x1 - 5) ** 2 + (1 / 4) * (model.x2 - 3.5) ** 2 <= 1
)
@@ -65,9 +65,9 @@ def disjunctions(model, i):
def solve_base_model():
m_base = build_gdp_model()
- m_hull = TransformationFactory('gdp.hull').create_using(m_base)
- # m_bigm = TransformationFactory('gdp.bigm').create_using(m_base, bigM=100)
- solver = SolverFactory('gams')
+ m_hull = pyo.TransformationFactory('gdp.hull').create_using(m_base)
+ # m_bigm = pyo.TransformationFactory('gdp.bigm').create_using(m_base, bigM=100)
+ solver = pyo.SolverFactory('gams')
solver.solve(m_hull, solver='baron')
# m_hull.pprint()
m_hull.objective.display()
@@ -83,11 +83,11 @@ def solve_basic_step_model():
# with open('pprint.log','w') as outputfile:
# m_base.disjunctions.pprint(outputfile)
- # m_bs_hull = TransformationFactory('gdp.hull').create_using(m_base)
- m_bigm = TransformationFactory('gdp.bigm').create_using(m_base, bigM=100)
+ # m_bs_hull = pyo.TransformationFactory('gdp.hull').create_using(m_base)
+ m_bigm = pyo.TransformationFactory('gdp.bigm').create_using(m_base, bigM=100)
m_bigm.pprint()
- solver = SolverFactory('gams')
+ solver = pyo.SolverFactory('gams')
solver.solve(m_bigm, tee=True, solver='baron')
m_bigm.objective.display()
diff --git a/examples/gdp/small_lit/contracts_problem.py b/examples/gdp/small_lit/contracts_problem.py
index 0c59d2264ee..26b4f6e53bc 100644
--- a/examples/gdp/small_lit/contracts_problem.py
+++ b/examples/gdp/small_lit/contracts_problem.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/small_lit/ex1_Lee.py b/examples/gdp/small_lit/ex1_Lee.py
index abbf470a1c3..64168318e9a 100644
--- a/examples/gdp/small_lit/ex1_Lee.py
+++ b/examples/gdp/small_lit/ex1_Lee.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,7 +13,7 @@
Taken from Example 1 of the paper "New Algorithms for Nonlinear Generalized Disjunctive Programming" by Lee and Grossmann
This GDP problem has one disjunction containing three terms, and exactly one of them must be true. The literature can be found here:
-http://egon.cheme.cmu.edu/Papers/LeeNewAlgo.pdf
+https://egon.cheme.cmu.edu/Papers/LeeNewAlgo.pdf
"""
diff --git a/examples/gdp/small_lit/ex_633_trespalacios.py b/examples/gdp/small_lit/ex_633_trespalacios.py
index b0c5fbd85ac..abf8c262fa0 100644
--- a/examples/gdp/small_lit/ex_633_trespalacios.py
+++ b/examples/gdp/small_lit/ex_633_trespalacios.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -26,28 +26,28 @@
"""
-from pyomo.environ import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunction
def build_simple_nonconvex_gdp():
"""Build the Analytical Problem."""
- m = ConcreteModel(name="Example 6.3.3")
+ m = pyo.ConcreteModel(name="Example 6.3.3")
# Variables x1 and x2
- m.x1 = Var(bounds=(0, 5), doc="variable x1")
- m.x2 = Var(bounds=(0, 3), doc="variable x2")
- m.obj = Objective(expr=5 + 0.2 * m.x1 - m.x2, doc="Minimize objective")
+ m.x1 = pyo.Var(bounds=(0, 5), doc="variable x1")
+ m.x2 = pyo.Var(bounds=(0, 3), doc="variable x2")
+ m.obj = pyo.Objective(expr=5 + 0.2 * m.x1 - m.x2, doc="Minimize objective")
m.disjunction1 = Disjunction(
expr=[
[
- m.x2 <= 0.4 * exp(m.x1 / 2.0),
+ m.x2 <= 0.4 * pyo.exp(m.x1 / 2.0),
m.x2 <= 0.5 * (m.x1 - 2.5) ** 2 + 0.3,
m.x2 <= 6.5 / (m.x1 / 0.3 + 2.0) + 1.0,
],
[
- m.x2 <= 0.3 * exp(m.x1 / 1.8),
+ m.x2 <= 0.3 * pyo.exp(m.x1 / 1.8),
m.x2 <= 0.7 * (m.x1 / 1.2 - 2.1) ** 2 + 0.3,
m.x2 <= 6.5 / (m.x1 / 0.8 + 1.1),
],
@@ -56,12 +56,12 @@ def build_simple_nonconvex_gdp():
m.disjunction2 = Disjunction(
expr=[
[
- m.x2 <= 0.9 * exp(m.x1 / 2.1),
+ m.x2 <= 0.9 * pyo.exp(m.x1 / 2.1),
m.x2 <= 1.3 * (m.x1 / 1.5 - 1.8) ** 2 + 0.3,
m.x2 <= 6.5 / (m.x1 / 0.8 + 1.1),
],
[
- m.x2 <= 0.4 * exp(m.x1 / 1.5),
+ m.x2 <= 0.4 * pyo.exp(m.x1 / 1.5),
m.x2 <= 1.2 * (m.x1 - 2.5) ** 2 + 0.3,
m.x2 <= 6.0 / (m.x1 / 0.6 + 1.0) + 0.5,
],
@@ -74,7 +74,7 @@ def build_simple_nonconvex_gdp():
if __name__ == "__main__":
model = build_simple_nonconvex_gdp()
model.pprint()
- res = SolverFactory('gdpopt.gloa').solve(model, tee=True)
+ res = pyo.SolverFactory('gdpopt.gloa').solve(model, tee=True)
model.display()
print(res)
diff --git a/examples/gdp/small_lit/nonconvex_HEN.py b/examples/gdp/small_lit/nonconvex_HEN.py
index 05fad970b84..e24e5cc2a32 100644
--- a/examples/gdp/small_lit/nonconvex_HEN.py
+++ b/examples/gdp/small_lit/nonconvex_HEN.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/stickies.py b/examples/gdp/stickies.py
index 73b537ff13d..95278ded7f2 100644
--- a/examples/gdp/stickies.py
+++ b/examples/gdp/stickies.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,11 +12,8 @@
import os
from pyomo.common.fileutils import this_file_dir
-from pyomo.environ import *
-from pyomo.gdp import *
-
-# from pyomo.opt import SolverFactory
-# from pyomo.core.base import Transformation
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
''' Layout optimization for screening systems in waste paper recovery:
@@ -30,9 +27,9 @@
def build_model():
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.BigM = Suffix(direction=Suffix.LOCAL)
+ model.BigM = pyo.Suffix(direction=pyo.Suffix.LOCAL)
model.BigM[None] = 1000
DATFILE = "stickies1.dat"
@@ -42,27 +39,27 @@ def build_model():
#######################
# J
- model.Components = Set()
+ model.Components = pyo.Set()
# fiber
- model.GoodComponents = Set()
+ model.GoodComponents = pyo.Set()
# stickies
- model.BadComponents = Set()
+ model.BadComponents = pyo.Set()
# N: total nodes in the system
- model.Nodes = Set()
+ model.Nodes = pyo.Set()
# S: possible screens
- model.Screens = Set()
+ model.Screens = pyo.Set()
def screen_node_filter(model, s, n):
return s != n
- model.ScreenNodePairs = Set(
+ model.ScreenNodePairs = pyo.Set(
initialize=model.Screens * model.Nodes, dimen=2, filter=screen_node_filter
)
def screen_filter(model, s, sprime):
return s != sprime
- model.ScreenPairs = Set(
+ model.ScreenPairs = pyo.Set(
initialize=model.Screens * model.Screens, dimen=2, filter=screen_filter
)
@@ -71,24 +68,24 @@ def screen_filter(model, s, sprime):
######################
# exponent coefficient for cost in screen s (alpha(s))
- model.ExpScreenCostCoeff = Param(model.Screens)
+ model.ExpScreenCostCoeff = pyo.Param(model.Screens)
# beta(s, j)
- model.AcceptanceFactor = Param(model.Screens, model.Components)
+ model.AcceptanceFactor = pyo.Param(model.Screens, model.Components)
# C_s^1
- model.ScreenCostCoeff1 = Param(model.Screens)
+ model.ScreenCostCoeff1 = pyo.Param(model.Screens)
# C_s^2
- model.ScreenCostCoeff2 = Param(model.Screens, default=0)
+ model.ScreenCostCoeff2 = pyo.Param(model.Screens, default=0)
# max percentage inlet stickies accepted in total flow (C_{st}^{up}, q(kb))
- model.AcceptedLeftover = Param(model.BadComponents)
+ model.AcceptedLeftover = pyo.Param(model.BadComponents)
# F_j^0, m_src(k)
- model.InitialComponentFlow = Param(model.Components)
+ model.InitialComponentFlow = pyo.Param(model.Components)
# m_src_lo(k)
- model.InitialComponentFlowLB = Param(model.Components, default=0)
+ model.InitialComponentFlowLB = pyo.Param(model.Components, default=0)
# constants for objective function (W^1, W^2, W^3)
- model.FiberWeight = Param()
- model.StickiesWeight = Param()
- model.CostWeight = Param()
+ model.FiberWeight = pyo.Param()
+ model.StickiesWeight = pyo.Param()
+ model.CostWeight = pyo.Param()
## Bounds on variables
@@ -96,27 +93,29 @@ def screen_filter(model, s, sprime):
def flow_ub_rule(model, s):
return sum(model.InitialComponentFlow[k] for k in model.Components)
- model.ScreenFlowLB = Param(model.Screens)
- model.ScreenFlowUB = Param(model.Screens, initialize=flow_ub_rule)
+ model.ScreenFlowLB = pyo.Param(model.Screens)
+ model.ScreenFlowUB = pyo.Param(model.Screens, initialize=flow_ub_rule)
# m_in_lo(ss, k): lower bound of individual flow into nodes.
- model.InletComponentFlowLB = Param(model.Components, model.Nodes, default=0)
+ model.InletComponentFlowLB = pyo.Param(model.Components, model.Nodes, default=0)
def component_flow_ub_rule(model, k, n):
return model.InitialComponentFlow[k]
# m_in_up(ss, k)
- model.InletComponentFlowUB = Param(
+ model.InletComponentFlowUB = pyo.Param(
model.Components, model.Nodes, initialize=component_flow_ub_rule
)
# r_lo(s)
- model.RejectRateLB = Param(model.Screens)
+ model.RejectRateLB = pyo.Param(model.Screens)
# r_up(s)
- model.RejectRateUB = Param(model.Screens)
+ model.RejectRateUB = pyo.Param(model.Screens)
# m_rej_lo(s, k)
- model.RejectedComponentFlowLB = Param(model.Components, model.Screens, default=0)
+ model.RejectedComponentFlowLB = pyo.Param(
+ model.Components, model.Screens, default=0
+ )
def rejected_component_flow_bound(model, k, s):
return model.InitialComponentFlow[k] * (
@@ -124,12 +123,14 @@ def rejected_component_flow_bound(model, k, s):
)
# m_rej_up(s, k)
- model.RejectedComponentFlowUB = Param(
+ model.RejectedComponentFlowUB = pyo.Param(
model.Components, model.Screens, initialize=rejected_component_flow_bound
)
# m_acc_lo(s, k): lower bound of accepted individual flow
- model.AcceptedComponentFlowLB = Param(model.Components, model.Screens, default=0)
+ model.AcceptedComponentFlowLB = pyo.Param(
+ model.Components, model.Screens, default=0
+ )
def accepted_component_flow_bound(model, k, s):
return model.InitialComponentFlow[k] * (
@@ -137,7 +138,7 @@ def accepted_component_flow_bound(model, k, s):
)
# m_acc_up(s, k)
- model.AcceptedComponentFlowUB = Param(
+ model.AcceptedComponentFlowUB = pyo.Param(
model.Components, model.Screens, initialize=accepted_component_flow_bound
)
@@ -146,8 +147,8 @@ def accepted_component_flow_bound(model, k, s):
######################
# c_s, C(s), cost of selecting screen
- model.screenCost = Var(
- model.Screens, within=NonNegativeReals
+ model.screenCost = pyo.Var(
+ model.Screens, within=pyo.NonNegativeReals
) # , bounds=get_screen_cost_bounds)
# total inlet flow into screen s (f_s, F_IN(s))
@@ -156,18 +157,18 @@ def accepted_component_flow_bound(model, k, s):
def get_inlet_flow_bounds(model, s):
return (0, model.ScreenFlowUB[s])
- model.inletScreenFlow = Var(
- model.Screens, within=NonNegativeReals, bounds=get_inlet_flow_bounds
+ model.inletScreenFlow = pyo.Var(
+ model.Screens, within=pyo.NonNegativeReals, bounds=get_inlet_flow_bounds
)
# inlet flow of component j into node n, (f_{n,j}^I, M_IN)
def get_inlet_component_flow_bounds(model, j, n):
return (model.InletComponentFlowLB[j, n], model.InletComponentFlowUB[j, n])
- model.inletComponentFlow = Var(
+ model.inletComponentFlow = pyo.Var(
model.Components,
model.Nodes,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
bounds=get_inlet_component_flow_bounds,
)
@@ -178,10 +179,10 @@ def get_accepted_component_flow_bounds(model, j, s):
model.AcceptedComponentFlowUB[j, s],
)
- model.acceptedComponentFlow = Var(
+ model.acceptedComponentFlow = pyo.Var(
model.Components,
model.Screens,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
bounds=get_accepted_component_flow_bounds,
)
@@ -192,10 +193,10 @@ def rej_component_flow_bounds(model, k, s):
model.RejectedComponentFlowUB[k, s],
)
- model.rejectedComponentFlow = Var(
+ model.rejectedComponentFlow = pyo.Var(
model.Components,
model.Screens,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
bounds=rej_component_flow_bounds,
)
@@ -203,11 +204,11 @@ def rej_component_flow_bounds(model, k, s):
def get_accepted_node_flow_bounds(model, j, s, n):
return (0, model.AcceptedComponentFlowUB[j, s])
- model.acceptedNodeFlow = Var(
+ model.acceptedNodeFlow = pyo.Var(
model.Components,
model.Screens,
model.Nodes,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
bounds=get_accepted_node_flow_bounds,
)
@@ -215,11 +216,11 @@ def get_accepted_node_flow_bounds(model, j, s, n):
def get_rejected_node_flow_bounds(model, j, s, n):
return (0, model.RejectedComponentFlowUB[j, s])
- model.rejectedNodeFlow = Var(
+ model.rejectedNodeFlow = pyo.Var(
model.Components,
model.Screens,
model.Nodes,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
bounds=get_rejected_node_flow_bounds,
)
@@ -227,14 +228,16 @@ def get_rejected_node_flow_bounds(model, j, s, n):
def get_src_flow_bounds(model, j, n):
return (0, model.InitialComponentFlow[j])
- model.flowFromSource = Var(model.Components, model.Nodes, within=NonNegativeReals)
+ model.flowFromSource = pyo.Var(
+ model.Components, model.Nodes, within=pyo.NonNegativeReals
+ )
# reject rate of screen s (r_s)
def get_rej_rate_bounds(model, s):
return (model.RejectRateLB[s], model.RejectRateUB[s])
- model.rejectRate = Var(
- model.Screens, within=NonNegativeReals, bounds=get_rej_rate_bounds
+ model.rejectRate = pyo.Var(
+ model.Screens, within=pyo.NonNegativeReals, bounds=get_rej_rate_bounds
)
######################
@@ -251,7 +254,7 @@ def calc_cost_rule(model):
screenCost = model.CostWeight * sum(model.screenCost[s] for s in model.Screens)
return lostFiberCost + stickiesCost + screenCost
- model.min_cost = Objective(rule=calc_cost_rule)
+ model.min_cost = pyo.Objective(rule=calc_cost_rule)
######################
# Constraints
@@ -263,7 +266,7 @@ def stickies_bound_rule(model, j):
<= model.AcceptedLeftover[j] * model.InitialComponentFlow[j]
)
- model.stickies_bound = Constraint(model.BadComponents, rule=stickies_bound_rule)
+ model.stickies_bound = pyo.Constraint(model.BadComponents, rule=stickies_bound_rule)
def inlet_flow_rule(model, s, j):
return (
@@ -271,14 +274,16 @@ def inlet_flow_rule(model, s, j):
== model.acceptedComponentFlow[j, s] + model.rejectedComponentFlow[j, s]
)
- model.inlet_flow = Constraint(model.Screens, model.Components, rule=inlet_flow_rule)
+ model.inlet_flow = pyo.Constraint(
+ model.Screens, model.Components, rule=inlet_flow_rule
+ )
def total_inlet_flow_rule(model, s):
return model.inletScreenFlow[s] == sum(
model.inletComponentFlow[j, s] for j in model.Components
)
- model.total_inlet_flow = Constraint(model.Screens, rule=total_inlet_flow_rule)
+ model.total_inlet_flow = pyo.Constraint(model.Screens, rule=total_inlet_flow_rule)
def inlet_flow_balance_rule(model, n, j):
return model.inletComponentFlow[j, n] == model.flowFromSource[j, n] + sum(
@@ -287,7 +292,7 @@ def inlet_flow_balance_rule(model, n, j):
if s != n
)
- model.inlet_flow_balance = Constraint(
+ model.inlet_flow_balance = pyo.Constraint(
model.Nodes, model.Components, rule=inlet_flow_balance_rule
)
@@ -296,7 +301,7 @@ def source_flow_rule(model, j):
model.flowFromSource[j, n] for n in model.Nodes
)
- model.source_flow = Constraint(model.Components, rule=source_flow_rule)
+ model.source_flow = pyo.Constraint(model.Components, rule=source_flow_rule)
#################
## Disjunctions
@@ -311,22 +316,22 @@ def rejected_flow_rule(disjunct, j):
] * (model.rejectRate[s] ** model.AcceptanceFactor[s, j])
if selectScreen:
- disjunct.inlet_flow_bounds = Constraint(
+ disjunct.inlet_flow_bounds = pyo.Constraint(
expr=model.ScreenFlowLB[s] <= model.inletScreenFlow[s]
) # <= \
# model.ScreenFlowUB[s])
- disjunct.rejected_flow = Constraint(
+ disjunct.rejected_flow = pyo.Constraint(
model.Components, rule=rejected_flow_rule
)
- disjunct.screen_cost = Constraint(
+ disjunct.screen_cost = pyo.Constraint(
expr=model.screenCost[s]
== model.ScreenCostCoeff1[s]
* (model.inletScreenFlow[s] ** model.ExpScreenCostCoeff[s])
+ model.ScreenCostCoeff2[s] * (1 - model.rejectRate[s])
)
else:
- disjunct.no_flow = Constraint(expr=model.inletScreenFlow[s] == 0)
- disjunct.no_cost = Constraint(expr=model.screenCost[s] == 0)
+ disjunct.no_flow = pyo.Constraint(expr=model.inletScreenFlow[s] == 0)
+ disjunct.no_cost = pyo.Constraint(expr=model.screenCost[s] == 0)
model.screen_selection_disjunct = Disjunct(
[0, 1], model.Screens, rule=screen_disjunct_rule
@@ -349,9 +354,11 @@ def no_flow_rule(disjunct, j):
return model.acceptedNodeFlow[j, s, n] == 0
if acceptFlow:
- disjunct.flow_balance = Constraint(model.Components, rule=flow_balance_rule)
+ disjunct.flow_balance = pyo.Constraint(
+ model.Components, rule=flow_balance_rule
+ )
else:
- disjunct.no_flow = Constraint(model.Components, rule=no_flow_rule)
+ disjunct.no_flow = pyo.Constraint(model.Components, rule=no_flow_rule)
model.flow_acceptance_disjunct = Disjunct(
model.ScreenNodePairs, [0, 1], rule=accepted_flow_disjunct_rule
@@ -376,9 +383,11 @@ def no_reject_rule(disjunct, j):
return model.rejectedNodeFlow[j, s, n] == 0
if rejectFlow:
- disjunct.flow_balance = Constraint(model.Components, rule=flow_balance_rule)
+ disjunct.flow_balance = pyo.Constraint(
+ model.Components, rule=flow_balance_rule
+ )
else:
- disjunct.no_reject = Constraint(model.Components, rule=no_reject_rule)
+ disjunct.no_reject = pyo.Constraint(model.Components, rule=no_reject_rule)
model.flow_rejection_disjunct = Disjunct(
model.ScreenNodePairs, [0, 1], rule=rejected_flow_disjunct_rule
@@ -408,13 +417,13 @@ def sourceFlow_balance_rule2(disjunct, j):
def no_sourceFlow_rule(disjunct, j, nprime):
return model.flowFromSource[j, nprime] == 0
- disjunct.flow_balance1 = Constraint(
+ disjunct.flow_balance1 = pyo.Constraint(
model.Components, rule=sourceFlow_balance_rule1
)
- disjunct.flow_balance2 = Constraint(
+ disjunct.flow_balance2 = pyo.Constraint(
model.Components, rule=sourceFlow_balance_rule2
)
- disjunct.no_flow = Constraint(
+ disjunct.no_flow = pyo.Constraint(
model.Components, model.Nodes - [n], rule=no_sourceFlow_rule
)
@@ -445,7 +454,7 @@ def log1_rule(model, s):
if s != n
)
- model.log1 = Constraint(model.Screens, rule=log1_rule)
+ model.log1 = pyo.Constraint(model.Screens, rule=log1_rule)
def log2_rule(model, s):
return model.screen_selection_disjunct[1, s].binary_indicator_var == sum(
@@ -454,7 +463,7 @@ def log2_rule(model, s):
if s != n
)
- model.log2 = Constraint(model.Screens, rule=log2_rule)
+ model.log2 = pyo.Constraint(model.Screens, rule=log2_rule)
def log3_rule(model, s):
return model.screen_selection_disjunct[1, s].binary_indicator_var >= sum(
@@ -463,7 +472,7 @@ def log3_rule(model, s):
if s != sprime
)
- model.log3 = Constraint(model.Screens, rule=log3_rule)
+ model.log3 = pyo.Constraint(model.Screens, rule=log3_rule)
def log4_rule(model, s):
return model.screen_selection_disjunct[1, s].binary_indicator_var >= sum(
@@ -472,7 +481,7 @@ def log4_rule(model, s):
if s != sprime
)
- model.log4 = Constraint(model.Screens, rule=log4_rule)
+ model.log4 = pyo.Constraint(model.Screens, rule=log4_rule)
def log6_rule(model, s, sprime):
return (
@@ -481,7 +490,7 @@ def log6_rule(model, s, sprime):
<= 1
)
- model.log6 = Constraint(model.ScreenPairs, rule=log6_rule)
+ model.log6 = pyo.Constraint(model.ScreenPairs, rule=log6_rule)
def log7_rule(model, s, sprime):
return (
@@ -490,7 +499,7 @@ def log7_rule(model, s, sprime):
<= 1
)
- model.log7 = Constraint(model.ScreenPairs, rule=log7_rule)
+ model.log7 = pyo.Constraint(model.ScreenPairs, rule=log7_rule)
def log8_rule(model, s, n):
return (
@@ -499,7 +508,7 @@ def log8_rule(model, s, n):
<= 1
)
- model.log8 = Constraint(model.ScreenNodePairs, rule=log8_rule)
+ model.log8 = pyo.Constraint(model.ScreenNodePairs, rule=log8_rule)
def log9_rule(model, s, sprime):
return (
@@ -508,7 +517,7 @@ def log9_rule(model, s, sprime):
<= 1
)
- model.log9 = Constraint(model.ScreenPairs, rule=log9_rule)
+ model.log9 = pyo.Constraint(model.ScreenPairs, rule=log9_rule)
# These are the above logical constraints implemented correctly (I think)
# However, this doesn't match what is actually coded in gams and makes the
@@ -518,93 +527,93 @@ def log9_rule(model, s, sprime):
# def flow_existence_rule1(model, s, n):
# return model.screen_selection_disjunct[1, s].indicator_var >= \
# model.flow_acceptance_disjunct[s, n, 1].indicator_var
- # model.flow_existence1 = Constraint(model.ScreenNodePairs,
+ # model.flow_existence1 = pyo.Constraint(model.ScreenNodePairs,
# rule=flow_existence_rule1)
# def flow_existence_rule2(model, s, n):
# return model.screen_selection_disjunct[1, s].indicator_var >= \
# model.flow_rejection_disjunct[s, n, 1].indicator_var
- # model.flow_existence2 = Constraint(model.ScreenNodePairs,
+ # model.flow_existence2 = pyo.Constraint(model.ScreenNodePairs,
# rule=flow_existence_rule2)
# # YA_{s,s'} v YR_{s',s} implies Y_s
# def screen_flow_existence_rule1(model, s, sprime):
# return model.screen_selection_disjunct[1, s].indicator_var >= \
# model.flow_acceptance_disjunct[s, sprime, 1].indicator_var
- # model.screen_flow_existence1 = Constraint(model.ScreenPairs,
+ # model.screen_flow_existence1 = pyo.Constraint(model.ScreenPairs,
# rule=screen_flow_existence_rule1)
# def screen_flow_existence_rule2(model, s, sprime):
# return model.screen_selection_disjunct[1,s].indicator_var >= \
# model.flow_rejection_disjunct[sprime, s, 1].indicator_var
- # model.screen_flow_existence2 = Constraint(model.ScreenPairs,
+ # model.screen_flow_existence2 = pyo.Constraint(model.ScreenPairs,
# rule=screen_flow_existence_rule2)
# # YA_{s', s} XOR YA_{s, s'}
# def accept_rule1(model, s, sprime):
# return 1 <= model.flow_acceptance_disjunct[s, sprime, 1].indicator_var + \
# model.flow_acceptance_disjunct[sprime, s, 1].indicator_var
- # model.accept1 = Constraint(model.ScreenPairs, rule=accept_rule1)
+ # model.accept1 = pyo.Constraint(model.ScreenPairs, rule=accept_rule1)
# def accept_rule2(model, s, sprime):
# return 1 >= model.flow_acceptance_disjunct[s, sprime, 1].indicator_var - \
# model.flow_acceptance_disjunct[sprime, s, 1].indicator_var
- # model.accept2 = Constraint(model.ScreenPairs, rule=accept_rule2)
+ # model.accept2 = pyo.Constraint(model.ScreenPairs, rule=accept_rule2)
# def accept_rule3(model, s, sprime):
# return 1 >= model.flow_acceptance_disjunct[sprime, s, 1].indicator_var - \
# model.flow_acceptance_disjunct[s, sprime, 1].indicator_var
- # model.accept3 = Constraint(model.ScreenPairs, rule=accept_rule3)
+ # model.accept3 = pyo.Constraint(model.ScreenPairs, rule=accept_rule3)
# def accept_rule4(model, s, sprime):
# return 1 <= 2 - model.flow_acceptance_disjunct[sprime,s,1].indicator_var - \
# model.flow_acceptance_disjunct[s, sprime, 1].indicator_var
- # model.accept4 = Constraint(model.ScreenPairs, rule=accept_rule4)
+ # model.accept4 = pyo.Constraint(model.ScreenPairs, rule=accept_rule4)
# # YR_{s', s} XOR YR_{s, s'}
# def reject_rule1(model, s, sprime):
# return 1 <= model.flow_rejection_disjunct[s, sprime, 1].indicator_var + \
# model.flow_rejection_disjunct[sprime, s, 1].indicator_var
- # model.reject1 = Constraint(model.ScreenPairs, rule=reject_rule1)
+ # model.reject1 = pyo.Constraint(model.ScreenPairs, rule=reject_rule1)
# def reject_rule2(model, s, sprime):
# return 1 >= model.flow_rejection_disjunct[s, sprime, 1].indicator_var - \
# model.flow_rejection_disjunct[sprime, s, 1].indicator_var
- # model.reject2 = Constraint(model.ScreenPairs, rule=reject_rule2)
+ # model.reject2 = pyo.Constraint(model.ScreenPairs, rule=reject_rule2)
# def reject_rule3(model, s, sprime):
# return 1 >= model.flow_rejection_disjunct[sprime, s, 1].indicator_var - \
# model.flow_rejection_disjunct[s, sprime, 1].indicator_var
- # model.reject3 = Constraint(model.ScreenPairs, rule=reject_rule3)
+ # model.reject3 = pyo.Constraint(model.ScreenPairs, rule=reject_rule3)
# def reject_rule4(model, s, sprime):
# return 1 <= 2 - model.flow_rejection_disjunct[sprime,s,1].indicator_var - \
# model.flow_rejection_disjunct[s, sprime, 1].indicator_var
- # model.reject4 = Constraint(model.ScreenPairs, rule=reject_rule4)
+ # model.reject4 = pyo.Constraint(model.ScreenPairs, rule=reject_rule4)
# # YA_{s,n} XOR YR_{s,n}
# def accept_or_reject_rule1(model, s, n):
# return 1 <= model.flow_acceptance_disjunct[s, n, 1].indicator_var + \
# model.flow_rejection_disjunct[s, n, 1].indicator_var
- # model.accept_or_reject1 = Constraint(model.ScreenNodePairs,
+ # model.accept_or_reject1 = pyo.Constraint(model.ScreenNodePairs,
# rule=accept_or_reject_rule1)
# def accept_or_reject_rule2(model, s, n):
# return 1 >= model.flow_acceptance_disjunct[s, n, 1].indicator_var - \
# model.flow_rejection_disjunct[s, n, 1].indicator_var
- # model.accept_or_reject2 = Constraint(model.ScreenNodePairs,
+ # model.accept_or_reject2 = pyo.Constraint(model.ScreenNodePairs,
# rule=accept_or_reject_rule2)
# def accept_or_reject_rule3(model, s, n):
# return 1 >= model.flow_rejection_disjunct[s, n, 1].indicator_var - \
# model.flow_acceptance_disjunct[s, n, 1].indicator_var
- # model.accept_or_reject3 = Constraint(model.ScreenNodePairs,
+ # model.accept_or_reject3 = pyo.Constraint(model.ScreenNodePairs,
# rule=accept_or_reject_rule3)
# def accept_or_reject_rule4(model, s, n):
# return 1 <= 2 - model.flow_acceptance_disjunct[s, n, 1].indicator_var - \
# model.flow_rejection_disjunct[s, n, 1].indicator_var
- # model.accept_or_reject4 = Constraint(model.ScreenNodePairs,
+ # model.accept_or_reject4 = pyo.Constraint(model.ScreenNodePairs,
# rule=accept_or_reject_rule4)
instance = model.create_instance(os.path.join(this_file_dir(), DATFILE))
@@ -718,11 +727,11 @@ def log9_rule(model, s, sprime):
instance = build_model()
# bigm transformation!
- bigM = TransformationFactory('gdp.bigm')
+ bigM = pyo.TransformationFactory('gdp.bigm')
bigM.apply_to(instance)
# solve the model
- opt = SolverFactory('baron')
+ opt = pyo.SolverFactory('baron')
opt.options["MaxTime"] = 32400
results = opt.solve(instance, tee=True)
diff --git a/examples/gdp/strip_packing/stripPacking.py b/examples/gdp/strip_packing/stripPacking.py
index 39f7208b838..3094c3117bb 100644
--- a/examples/gdp/strip_packing/stripPacking.py
+++ b/examples/gdp/strip_packing/stripPacking.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,24 +9,24 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
-from pyomo.gdp import *
+import pyomo.environ as pyo
+from pyomo.gdp import Disjunct, Disjunction
# Strip-packing example from http://minlp.org/library/lib.php?lib=GDP
# This model packs a set of rectangles without rotation or overlap within a
# strip of a given width, minimizing the length of the strip.
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.RECTANGLES = Set(ordered=True)
+model.RECTANGLES = pyo.Set(ordered=True)
# height and width of each rectangle
-model.Heights = Param(model.RECTANGLES)
-model.Lengths = Param(model.RECTANGLES)
+model.Heights = pyo.Param(model.RECTANGLES)
+model.Lengths = pyo.Param(model.RECTANGLES)
# width of strip
-model.StripWidth = Param()
+model.StripWidth = pyo.Param()
# upperbound on length (default is sum of lengths of rectangles)
@@ -34,17 +34,17 @@ def sumLengths(model):
return sum(model.Lengths[i] for i in model.RECTANGLES)
-model.LengthUB = Param(initialize=sumLengths)
+model.LengthUB = pyo.Param(initialize=sumLengths)
# rectangle relations
-model.RecRelations = Set(initialize=['LeftOf', 'RightOf', 'Above', 'Below'])
+model.RecRelations = pyo.Set(initialize=['LeftOf', 'RightOf', 'Above', 'Below'])
# x and y coordinates of each of the rectangles
-model.x = Var(model.RECTANGLES, bounds=(0, model.LengthUB))
-model.y = Var(model.RECTANGLES, bounds=(0, model.StripWidth))
+model.x = pyo.Var(model.RECTANGLES, bounds=(0, model.LengthUB))
+model.y = pyo.Var(model.RECTANGLES, bounds=(0, model.StripWidth))
# length of strip (this will be the objective)
-model.Lt = Var(within=NonNegativeReals)
+model.Lt = pyo.Var(within=pyo.NonNegativeReals)
# generate the list of possible rectangle conflicts (which are any pair)
@@ -52,7 +52,7 @@ def rec_pairs_filter(model, i, j):
return i < j
-model.RectanglePairs = Set(
+model.RectanglePairs = pyo.Set(
initialize=model.RECTANGLES * model.RECTANGLES, dimen=2, filter=rec_pairs_filter
)
@@ -62,24 +62,26 @@ def strip_ends_after_last_rec_rule(model, i):
return model.Lt >= model.x[i] + model.Lengths[i]
-model.strip_ends_after_last_rec = Constraint(
+model.strip_ends_after_last_rec = pyo.Constraint(
model.RECTANGLES, rule=strip_ends_after_last_rec_rule
)
# constraints to prevent rectangles from going off strip
def no_recs_off_end_rule(model, i):
- return inequality(0, model.x[i], model.LengthUB - model.Lengths[i])
+ return pyo.inequality(0, model.x[i], model.LengthUB - model.Lengths[i])
-model.no_recs_off_end = Constraint(model.RECTANGLES, rule=no_recs_off_end_rule)
+model.no_recs_off_end = pyo.Constraint(model.RECTANGLES, rule=no_recs_off_end_rule)
def no_recs_off_bottom_rule(model, i):
- return inequality(model.Heights[i], model.y[i], model.StripWidth)
+ return pyo.inequality(model.Heights[i], model.y[i], model.StripWidth)
-model.no_recs_off_bottom = Constraint(model.RECTANGLES, rule=no_recs_off_bottom_rule)
+model.no_recs_off_bottom = pyo.Constraint(
+ model.RECTANGLES, rule=no_recs_off_bottom_rule
+)
# Disjunctions to prevent overlap between rectangles
@@ -87,16 +89,16 @@ def no_overlap_disjunct_rule(disjunct, i, j, recRelation):
model = disjunct.model()
# left
if recRelation == 'LeftOf':
- disjunct.c = Constraint(expr=model.x[i] + model.Lengths[i] <= model.x[j])
+ disjunct.c = pyo.Constraint(expr=model.x[i] + model.Lengths[i] <= model.x[j])
# right
elif recRelation == 'RightOf':
- disjunct.c = Constraint(expr=model.x[j] + model.Lengths[j] <= model.x[i])
+ disjunct.c = pyo.Constraint(expr=model.x[j] + model.Lengths[j] <= model.x[i])
# above
elif recRelation == 'Above':
- disjunct.c = Constraint(expr=model.y[i] - model.Heights[i] >= model.y[j])
+ disjunct.c = pyo.Constraint(expr=model.y[i] - model.Heights[i] >= model.y[j])
# below
elif recRelation == 'Below':
- disjunct.c = Constraint(expr=model.y[j] - model.Heights[j] >= model.y[i])
+ disjunct.c = pyo.Constraint(expr=model.y[j] - model.Heights[j] >= model.y[i])
else:
raise RuntimeError("Unrecognized rectangle relationship: %s" % recRelation)
@@ -115,4 +117,4 @@ def no_overlap(model, i, j):
model.disj = Disjunction(model.RectanglePairs, rule=no_overlap)
# minimize length
-model.length = Objective(expr=model.Lt)
+model.length = pyo.Objective(expr=model.Lt)
diff --git a/examples/gdp/strip_packing/strip_packing_8rect.py b/examples/gdp/strip_packing/strip_packing_8rect.py
index 2bd7c4840ca..1169ceb150a 100644
--- a/examples/gdp/strip_packing/strip_packing_8rect.py
+++ b/examples/gdp/strip_packing/strip_packing_8rect.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/strip_packing/strip_packing_concrete.py b/examples/gdp/strip_packing/strip_packing_concrete.py
index b0907cdea61..57423237748 100644
--- a/examples/gdp/strip_packing/strip_packing_concrete.py
+++ b/examples/gdp/strip_packing/strip_packing_concrete.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/gdp/two_rxn_lee/two_rxn_model.py b/examples/gdp/two_rxn_lee/two_rxn_model.py
index 98e4cc2e878..3207e21e30c 100644
--- a/examples/gdp/two_rxn_lee/two_rxn_model.py
+++ b/examples/gdp/two_rxn_lee/two_rxn_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,19 +11,17 @@
"""Two reactor model from literature. See README.md."""
-from pyomo.core import ConcreteModel, Constraint, Objective, Param, Var, maximize
-
-# from pyomo.environ import * # NOQA
+import pyomo.environ as pyo
from pyomo.gdp import Disjunction
def build_model(use_mccormick=False):
"""Build the GDP model."""
- m = ConcreteModel()
- m.F = Var(bounds=(0, 8), doc="Flow into reactor")
- m.X = Var(bounds=(0, 1), doc="Reactor conversion")
- m.d = Param(initialize=2, doc="Max product demand")
- m.c = Param(
+ m = pyo.ConcreteModel()
+ m.F = pyo.Var(bounds=(0, 8), doc="Flow into reactor")
+ m.X = pyo.Var(bounds=(0, 1), doc="Reactor conversion")
+ m.d = pyo.Param(initialize=2, doc="Max product demand")
+ m.c = pyo.Param(
[1, 2, 'I', 'II'],
doc="Costs",
initialize={
@@ -33,23 +31,23 @@ def build_model(use_mccormick=False):
'II': 1.5, # Cost of reactor II
},
)
- m.alpha = Param(
+ m.alpha = pyo.Param(
['I', 'II'], doc="Reactor coefficient", initialize={'I': -8, 'II': -10}
)
- m.beta = Param(
+ m.beta = pyo.Param(
['I', 'II'], doc="Reactor coefficient", initialize={'I': 9, 'II': 15}
)
- m.X_LB = Param(
+ m.X_LB = pyo.Param(
['I', 'II'],
doc="Reactor conversion lower bound",
initialize={'I': 0.2, 'II': 0.7},
)
- m.X_UB = Param(
+ m.X_UB = pyo.Param(
['I', 'II'],
doc="Reactor conversion upper bound",
initialize={'I': 0.95, 'II': 0.99},
)
- m.C_rxn = Var(bounds=(1.5, 2.5), doc="Cost of reactor")
+ m.C_rxn = pyo.Var(bounds=(1.5, 2.5), doc="Cost of reactor")
m.reactor_choice = Disjunction(
expr=[
# Disjunct 1: Choose reactor I
@@ -70,21 +68,23 @@ def build_model(use_mccormick=False):
xor=True,
)
if use_mccormick:
- m.P = Var(bounds=(0, 8), doc="McCormick approximation of F*X")
- m.mccormick_1 = Constraint(
+ m.P = pyo.Var(bounds=(0, 8), doc="McCormick approximation of F*X")
+ m.mccormick_1 = pyo.Constraint(
expr=m.P <= m.F.lb * m.X + m.F * m.X.ub - m.F.lb * m.X.ub,
doc="McCormick overestimator",
)
- m.mccormick_2 = Constraint(
+ m.mccormick_2 = pyo.Constraint(
expr=m.P <= m.F.ub * m.X + m.F * m.X.lb - m.F.ub * m.X.lb,
doc="McCormick underestimator",
)
- m.max_demand = Constraint(expr=m.P <= m.d, doc="product demand")
- m.profit = Objective(expr=m.c[1] * m.P - m.c[2] * m.F - m.C_rxn, sense=maximize)
+ m.max_demand = pyo.Constraint(expr=m.P <= m.d, doc="product demand")
+ m.profit = pyo.Objective(
+ expr=m.c[1] * m.P - m.c[2] * m.F - m.C_rxn, sense=pyo.maximize
+ )
else:
- m.max_demand = Constraint(expr=m.F * m.X <= m.d, doc="product demand")
- m.profit = Objective(
- expr=m.c[1] * m.F * m.X - m.c[2] * m.F - m.C_rxn, sense=maximize
+ m.max_demand = pyo.Constraint(expr=m.F * m.X <= m.d, doc="product demand")
+ m.profit = pyo.Objective(
+ expr=m.c[1] * m.F * m.X - m.c[2] * m.F - m.C_rxn, sense=pyo.maximize
)
return m
diff --git a/examples/kernel/blocks.py b/examples/kernel/blocks.py
index db1cb6655c2..612302fd392 100644
--- a/examples/kernel/blocks.py
+++ b/examples/kernel/blocks.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/conic.py b/examples/kernel/conic.py
index 5ee66a00ee9..ab2ba0c72bb 100644
--- a/examples/kernel/conic.py
+++ b/examples/kernel/conic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/constraints.py b/examples/kernel/constraints.py
index 69823a6ebbe..4f6941b3095 100644
--- a/examples/kernel/constraints.py
+++ b/examples/kernel/constraints.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/containers.py b/examples/kernel/containers.py
index 9ec749b8c3e..15a1fd5193b 100644
--- a/examples/kernel/containers.py
+++ b/examples/kernel/containers.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/expressions.py b/examples/kernel/expressions.py
index faef8d1d4ad..3695d9648d3 100644
--- a/examples/kernel/expressions.py
+++ b/examples/kernel/expressions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/mosek/geometric1.py b/examples/kernel/mosek/geometric1.py
index 8148e707819..1fa18c20e53 100644
--- a/examples/kernel/mosek/geometric1.py
+++ b/examples/kernel/mosek/geometric1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/mosek/geometric2.py b/examples/kernel/mosek/geometric2.py
index 3fb62c86312..77c44826709 100644
--- a/examples/kernel/mosek/geometric2.py
+++ b/examples/kernel/mosek/geometric2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/mosek/maximum_volume_cuboid.py b/examples/kernel/mosek/maximum_volume_cuboid.py
index df200cc801c..128f832e81e 100644
--- a/examples/kernel/mosek/maximum_volume_cuboid.py
+++ b/examples/kernel/mosek/maximum_volume_cuboid.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/mosek/power1.py b/examples/kernel/mosek/power1.py
index a6d6ebbe47d..fb47d35335f 100644
--- a/examples/kernel/mosek/power1.py
+++ b/examples/kernel/mosek/power1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/mosek/semidefinite.py b/examples/kernel/mosek/semidefinite.py
index 6be47d85451..97169d90ba2 100644
--- a/examples/kernel/mosek/semidefinite.py
+++ b/examples/kernel/mosek/semidefinite.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/objectives.py b/examples/kernel/objectives.py
index 27a41f4edb5..9f03ee211e7 100644
--- a/examples/kernel/objectives.py
+++ b/examples/kernel/objectives.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/parameters.py b/examples/kernel/parameters.py
index e9e412525bb..bb1d96d664d 100644
--- a/examples/kernel/parameters.py
+++ b/examples/kernel/parameters.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/piecewise_functions.py b/examples/kernel/piecewise_functions.py
index 73a7f680725..87d34eda5f6 100644
--- a/examples/kernel/piecewise_functions.py
+++ b/examples/kernel/piecewise_functions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/piecewise_nd_functions.py b/examples/kernel/piecewise_nd_functions.py
index 7de37fcbfc6..4525c77303f 100644
--- a/examples/kernel/piecewise_nd_functions.py
+++ b/examples/kernel/piecewise_nd_functions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/special_ordered_sets.py b/examples/kernel/special_ordered_sets.py
index abacc3d4205..b9ee3f24ca5 100644
--- a/examples/kernel/special_ordered_sets.py
+++ b/examples/kernel/special_ordered_sets.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/suffixes.py b/examples/kernel/suffixes.py
index ae95fbbdd09..cf15aab3edc 100644
--- a/examples/kernel/suffixes.py
+++ b/examples/kernel/suffixes.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/kernel/variables.py b/examples/kernel/variables.py
index 36865b58183..f02f82c42d7 100644
--- a/examples/kernel/variables.py
+++ b/examples/kernel/variables.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/bard1.py b/examples/mpec/bard1.py
index 59955eefb8e..3c092374fec 100644
--- a/examples/mpec/bard1.py
+++ b/examples/mpec/bard1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/df.py b/examples/mpec/df.py
index 7bb25b11e07..6a1adf08dc0 100644
--- a/examples/mpec/df.py
+++ b/examples/mpec/df.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/indexed.py b/examples/mpec/indexed.py
index 0aff5de5b20..000ae57e27d 100644
--- a/examples/mpec/indexed.py
+++ b/examples/mpec/indexed.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/linear1.py b/examples/mpec/linear1.py
index f24fd357e62..408d8a6b910 100644
--- a/examples/mpec/linear1.py
+++ b/examples/mpec/linear1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/munson1.py b/examples/mpec/munson1.py
index 99c240b5c06..7c37d443753 100644
--- a/examples/mpec/munson1.py
+++ b/examples/mpec/munson1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/munson1.yml b/examples/mpec/munson1.yml
index 02fb0e09884..544a1cdf7a2 100644
--- a/examples/mpec/munson1.yml
+++ b/examples/mpec/munson1.yml
@@ -24,7 +24,7 @@ runtime:
logfile: null # Redirect output to the specified file.
catch errors: true # Trigger failures for exceptions to print
# the program stack.
- disable gc: false # Disable the garbage collecter.
+ disable gc: false # Disable the garbage collector.
interactive: false # After executing Pyomo, launch an
# interactive Python shell. If IPython is
# installed, this shell is an IPython
diff --git a/examples/mpec/munson1a.py b/examples/mpec/munson1a.py
index 67f8f318531..864b8b1565f 100644
--- a/examples/mpec/munson1a.py
+++ b/examples/mpec/munson1a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/munson1b.py b/examples/mpec/munson1b.py
index 46fff90a785..6a79e4de08b 100644
--- a/examples/mpec/munson1b.py
+++ b/examples/mpec/munson1b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/munson1c.py b/examples/mpec/munson1c.py
index dee5b224e75..a2a73d53aa7 100644
--- a/examples/mpec/munson1c.py
+++ b/examples/mpec/munson1c.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/munson1d.py b/examples/mpec/munson1d.py
index 157177f2eb0..7af4ae83e85 100644
--- a/examples/mpec/munson1d.py
+++ b/examples/mpec/munson1d.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/mpec/scholtes4.py b/examples/mpec/scholtes4.py
index 8d574dd1916..27bfd7f772a 100644
--- a/examples/mpec/scholtes4.py
+++ b/examples/mpec/scholtes4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/performance/dae/run_stochpdegas1_automatic.py b/examples/performance/dae/run_stochpdegas1_automatic.py
index fffa1a71ae1..994a231c361 100644
--- a/examples/performance/dae/run_stochpdegas1_automatic.py
+++ b/examples/performance/dae/run_stochpdegas1_automatic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,15 +11,14 @@
import time
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
from stochpdegas1_automatic import model
start = time.time()
instance = model.create_instance('stochpdegas_automatic.dat')
# discretize model
-discretizer = TransformationFactory('dae.finite_difference')
+discretizer = pyo.TransformationFactory('dae.finite_difference')
discretizer.apply_to(instance, nfe=1, wrt=instance.DIS, scheme='FORWARD')
discretizer.apply_to(instance, nfe=47, wrt=instance.TIME, scheme='BACKWARD')
@@ -37,7 +36,7 @@ def supcost_rule(m, k):
)
-instance.supcost = Expression(instance.SCEN, rule=supcost_rule)
+instance.supcost = pyo.Expression(instance.SCEN, rule=supcost_rule)
def boostcost_rule(m, k):
@@ -48,7 +47,7 @@ def boostcost_rule(m, k):
)
-instance.boostcost = Expression(instance.SCEN, rule=boostcost_rule)
+instance.boostcost = pyo.Expression(instance.SCEN, rule=boostcost_rule)
def trackcost_rule(m, k):
@@ -59,7 +58,7 @@ def trackcost_rule(m, k):
)
-instance.trackcost = Expression(instance.SCEN, rule=trackcost_rule)
+instance.trackcost = pyo.Expression(instance.SCEN, rule=trackcost_rule)
def sspcost_rule(m, k):
@@ -70,7 +69,7 @@ def sspcost_rule(m, k):
)
-instance.sspcost = Expression(instance.SCEN, rule=sspcost_rule)
+instance.sspcost = pyo.Expression(instance.SCEN, rule=sspcost_rule)
def ssfcost_rule(m, k):
@@ -81,7 +80,7 @@ def ssfcost_rule(m, k):
)
-instance.ssfcost = Expression(instance.SCEN, rule=ssfcost_rule)
+instance.ssfcost = pyo.Expression(instance.SCEN, rule=ssfcost_rule)
def cost_rule(m, k):
@@ -90,28 +89,28 @@ def cost_rule(m, k):
)
-instance.cost = Expression(instance.SCEN, rule=cost_rule)
+instance.cost = pyo.Expression(instance.SCEN, rule=cost_rule)
def mcost_rule(m):
return (1.0 / m.S) * sum(m.cost[k] for k in m.SCEN)
-instance.mcost = Expression(rule=mcost_rule)
+instance.mcost = pyo.Expression(rule=mcost_rule)
def eqcvar_rule(m, k):
return m.cost[k] - m.nu <= m.phi[k]
-instance.eqcvar = Constraint(instance.SCEN, rule=eqcvar_rule)
+instance.eqcvar = pyo.Constraint(instance.SCEN, rule=eqcvar_rule)
def obj_rule(m):
return (1.0 - m.cvar_lambda) * m.mcost + m.cvar_lambda * m.cvarcost
-instance.obj = Objective(rule=obj_rule)
+instance.obj = pyo.Objective(rule=obj_rule)
endTime = time.time() - start
print('%f seconds required to construct' % endTime)
@@ -131,13 +130,13 @@ def obj_rule(m):
% (
i,
sum(
- sum(0.5 * value(instance.pow[i, j, k]) for j in instance.LINK_A)
+ sum(0.5 * pyo.value(instance.pow[i, j, k]) for j in instance.LINK_A)
for k in instance.TIME.get_finite_elements()
),
)
)
- solver = SolverFactory('ipopt')
+ solver = pyo.SolverFactory('ipopt')
results = solver.solve(instance, tee=True)
for i in instance.SCEN:
@@ -146,7 +145,7 @@ def obj_rule(m):
% (
i,
sum(
- sum(0.5 * value(instance.pow[i, j, k]) for j in instance.LINK_A)
+ sum(0.5 * pyo.value(instance.pow[i, j, k]) for j in instance.LINK_A)
for k in instance.TIME.get_finite_elements()
),
)
diff --git a/examples/performance/dae/stochpdegas1_automatic.py b/examples/performance/dae/stochpdegas1_automatic.py
index ce6132e6cf5..06426f558c4 100644
--- a/examples/performance/dae/stochpdegas1_automatic.py
+++ b/examples/performance/dae/stochpdegas1_automatic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,105 +14,109 @@
#
-from pyomo.environ import *
-from pyomo.dae import *
+import pyomo.environ as pyo
+from pyomo.dae import ContinuousSet, DerivativeVar
-model = AbstractModel()
+model = pyo.AbstractModel()
# sets
-model.TF = Param(within=NonNegativeReals)
+model.TF = pyo.Param(within=pyo.NonNegativeReals)
def _tinit(m):
- return [0.5, value(m.TF)]
+ return [0.5, pyo.value(m.TF)]
# What it should be to match description in paper
- # return [0,value(m.TF)]
+ # return [0,pyo.value(m.TF)]
model.TIME = ContinuousSet(initialize=_tinit)
model.DIS = ContinuousSet(bounds=(0.0, 1.0))
-model.S = Param(within=PositiveIntegers)
-model.SCEN = RangeSet(1, model.S)
+model.S = pyo.Param(within=pyo.PositiveIntegers)
+model.SCEN = pyo.RangeSet(1, model.S)
# links
-model.LINK = Set()
-model.lstartloc = Param(model.LINK)
-model.lendloc = Param(model.LINK)
-model.ldiam = Param(model.LINK, within=PositiveReals, mutable=True)
-model.llength = Param(model.LINK, within=PositiveReals, mutable=True)
-model.ltype = Param(model.LINK)
+model.LINK = pyo.Set()
+model.lstartloc = pyo.Param(model.LINK)
+model.lendloc = pyo.Param(model.LINK)
+model.ldiam = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.llength = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.ltype = pyo.Param(model.LINK)
def link_a_init_rule(m):
return (l for l in m.LINK if m.ltype[l] == "a")
-model.LINK_A = Set(initialize=link_a_init_rule)
+model.LINK_A = pyo.Set(initialize=link_a_init_rule)
def link_p_init_rule(m):
return (l for l in m.LINK if m.ltype[l] == "p")
-model.LINK_P = Set(initialize=link_p_init_rule)
+model.LINK_P = pyo.Set(initialize=link_p_init_rule)
# nodes
-model.NODE = Set()
-model.pmin = Param(model.NODE, within=PositiveReals, mutable=True)
-model.pmax = Param(model.NODE, within=PositiveReals, mutable=True)
+model.NODE = pyo.Set()
+model.pmin = pyo.Param(model.NODE, within=pyo.PositiveReals, mutable=True)
+model.pmax = pyo.Param(model.NODE, within=pyo.PositiveReals, mutable=True)
# supply
-model.SUP = Set()
-model.sloc = Param(model.SUP)
-model.smin = Param(model.SUP, within=NonNegativeReals, mutable=True)
-model.smax = Param(model.SUP, within=NonNegativeReals, mutable=True)
-model.scost = Param(model.SUP, within=NonNegativeReals)
+model.SUP = pyo.Set()
+model.sloc = pyo.Param(model.SUP)
+model.smin = pyo.Param(model.SUP, within=pyo.NonNegativeReals, mutable=True)
+model.smax = pyo.Param(model.SUP, within=pyo.NonNegativeReals, mutable=True)
+model.scost = pyo.Param(model.SUP, within=pyo.NonNegativeReals)
# demand
-model.DEM = Set()
-model.dloc = Param(model.DEM)
-model.d = Param(model.DEM, within=PositiveReals, mutable=True)
+model.DEM = pyo.Set()
+model.dloc = pyo.Param(model.DEM)
+model.d = pyo.Param(model.DEM, within=pyo.PositiveReals, mutable=True)
# physical data
-model.eps = Param(initialize=0.025, within=PositiveReals)
-model.z = Param(initialize=0.80, within=PositiveReals)
-model.rhon = Param(initialize=0.72, within=PositiveReals)
-model.R = Param(initialize=8314.0, within=PositiveReals)
-model.M = Param(initialize=18.0, within=PositiveReals)
-model.pi = Param(initialize=3.14, within=PositiveReals)
-model.nu2 = Param(within=PositiveReals, mutable=True)
-model.lam = Param(model.LINK, within=PositiveReals, mutable=True)
-model.A = Param(model.LINK, within=NonNegativeReals, mutable=True)
-model.Tgas = Param(initialize=293.15, within=PositiveReals)
-model.Cp = Param(initialize=2.34, within=PositiveReals)
-model.Cv = Param(initialize=1.85, within=PositiveReals)
-model.gam = Param(initialize=model.Cp / model.Cv, within=PositiveReals)
-model.om = Param(initialize=(model.gam - 1.0) / model.gam, within=PositiveReals)
+model.eps = pyo.Param(initialize=0.025, within=pyo.PositiveReals)
+model.z = pyo.Param(initialize=0.80, within=pyo.PositiveReals)
+model.rhon = pyo.Param(initialize=0.72, within=pyo.PositiveReals)
+model.R = pyo.Param(initialize=8314.0, within=pyo.PositiveReals)
+model.M = pyo.Param(initialize=18.0, within=pyo.PositiveReals)
+model.pi = pyo.Param(initialize=3.14, within=pyo.PositiveReals)
+model.nu2 = pyo.Param(within=pyo.PositiveReals, mutable=True)
+model.lam = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.A = pyo.Param(model.LINK, within=pyo.NonNegativeReals, mutable=True)
+model.Tgas = pyo.Param(initialize=293.15, within=pyo.PositiveReals)
+model.Cp = pyo.Param(initialize=2.34, within=pyo.PositiveReals)
+model.Cv = pyo.Param(initialize=1.85, within=pyo.PositiveReals)
+model.gam = pyo.Param(initialize=model.Cp / model.Cv, within=pyo.PositiveReals)
+model.om = pyo.Param(initialize=(model.gam - 1.0) / model.gam, within=pyo.PositiveReals)
# scaling and constants
-model.ffac = Param(
- within=PositiveReals, initialize=(1.0e6 * model.rhon) / (24.0 * 3600.0)
+model.ffac = pyo.Param(
+ within=pyo.PositiveReals, initialize=(1.0e6 * model.rhon) / (24.0 * 3600.0)
)
-model.ffac2 = Param(within=PositiveReals, initialize=(3600.0) / (1.0e4 * model.rhon))
-model.pfac = Param(within=PositiveReals, initialize=1.0e5)
-model.pfac2 = Param(within=PositiveReals, initialize=1.0e-5)
-model.dfac = Param(within=PositiveReals, initialize=1.0e-3)
-model.lfac = Param(within=PositiveReals, initialize=1.0e3)
+model.ffac2 = pyo.Param(
+ within=pyo.PositiveReals, initialize=(3600.0) / (1.0e4 * model.rhon)
+)
+model.pfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e5)
+model.pfac2 = pyo.Param(within=pyo.PositiveReals, initialize=1.0e-5)
+model.dfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e-3)
+model.lfac = pyo.Param(within=pyo.PositiveReals, initialize=1.0e3)
-model.c1 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c2 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c3 = Param(model.LINK, within=PositiveReals, mutable=True)
-model.c4 = Param(within=PositiveReals, mutable=True)
+model.c1 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c2 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c3 = pyo.Param(model.LINK, within=pyo.PositiveReals, mutable=True)
+model.c4 = pyo.Param(within=pyo.PositiveReals, mutable=True)
# cost factors
-model.ce = Param(initialize=0.1, within=NonNegativeReals)
-model.cd = Param(initialize=1.0e6, within=NonNegativeReals)
-model.cT = Param(initialize=1.0e6, within=NonNegativeReals)
-model.cs = Param(initialize=0.0, within=NonNegativeReals)
-model.TDEC = Param(within=PositiveReals)
+model.ce = pyo.Param(initialize=0.1, within=pyo.NonNegativeReals)
+model.cd = pyo.Param(initialize=1.0e6, within=pyo.NonNegativeReals)
+model.cT = pyo.Param(initialize=1.0e6, within=pyo.NonNegativeReals)
+model.cs = pyo.Param(initialize=0.0, within=pyo.NonNegativeReals)
+model.TDEC = pyo.Param(within=pyo.PositiveReals)
# define stochastic info
-model.rand_d = Param(model.SCEN, model.DEM, within=NonNegativeReals, mutable=True)
+model.rand_d = pyo.Param(
+ model.SCEN, model.DEM, within=pyo.NonNegativeReals, mutable=True
+)
# convert units for input data
@@ -138,12 +142,12 @@ def rescale_rule(m):
m.pmax[i] = m.pmax[i] * m.pfac * m.pfac2 # from bar to Pascals and then to bar
-model.rescale = BuildAction(rule=rescale_rule)
+model.rescale = pyo.BuildAction(rule=rescale_rule)
def compute_constants(m):
for i in m.LINK:
- m.lam[i] = (2.0 * log10(3.7 * m.ldiam[i] / (m.eps * m.dfac))) ** (-2.0)
+ m.lam[i] = (2.0 * pyo.log10(3.7 * m.ldiam[i] / (m.eps * m.dfac))) ** (-2.0)
m.A[i] = (1.0 / 4.0) * m.pi * m.ldiam[i] * m.ldiam[i]
m.nu2 = m.gam * m.z * m.R * m.Tgas / m.M
m.c1[i] = (m.pfac2 / m.ffac2) * (m.nu2 / m.A[i])
@@ -157,7 +161,7 @@ def compute_constants(m):
m.c4 = (1 / m.ffac2) * (m.Cp * m.Tgas)
-model.compute_constants = BuildAction(rule=compute_constants)
+model.compute_constants = pyo.BuildAction(rule=compute_constants)
# set stochastic demands
@@ -172,7 +176,7 @@ def compute_demands_rule(m):
m.rand_d[k, j] = 1.3 * m.d[j]
-model.compute_demands = BuildAction(rule=compute_demands_rule)
+model.compute_demands = pyo.BuildAction(rule=compute_demands_rule)
def stochd_init(m, k, j, t):
@@ -191,11 +195,11 @@ def stochd_init(m, k, j, t):
return m.d[j]
-model.stochd = Param(
+model.stochd = pyo.Param(
model.SCEN,
model.DEM,
model.TIME,
- within=PositiveReals,
+ within=pyo.PositiveReals,
mutable=True,
default=stochd_init,
)
@@ -203,39 +207,43 @@ def stochd_init(m, k, j, t):
# define temporal variables
def p_bounds_rule(m, k, j, t):
- return (value(m.pmin[j]), value(m.pmax[j]))
+ return (pyo.value(m.pmin[j]), pyo.value(m.pmax[j]))
-model.p = Var(model.SCEN, model.NODE, model.TIME, bounds=p_bounds_rule, initialize=50.0)
-model.dp = Var(
+model.p = pyo.Var(
+ model.SCEN, model.NODE, model.TIME, bounds=p_bounds_rule, initialize=50.0
+)
+model.dp = pyo.Var(
model.SCEN, model.LINK_A, model.TIME, bounds=(0.0, 100.0), initialize=10.0
)
-model.fin = Var(
+model.fin = pyo.Var(
model.SCEN, model.LINK, model.TIME, bounds=(1.0, 500.0), initialize=100.0
)
-model.fout = Var(
+model.fout = pyo.Var(
model.SCEN, model.LINK, model.TIME, bounds=(1.0, 500.0), initialize=100.0
)
def s_bounds_rule(m, k, j, t):
- return (0.01, value(m.smax[j]))
+ return (0.01, pyo.value(m.smax[j]))
-model.s = Var(model.SCEN, model.SUP, model.TIME, bounds=s_bounds_rule, initialize=10.0)
-model.dem = Var(model.SCEN, model.DEM, model.TIME, initialize=100.0)
-model.pow = Var(
+model.s = pyo.Var(
+ model.SCEN, model.SUP, model.TIME, bounds=s_bounds_rule, initialize=10.0
+)
+model.dem = pyo.Var(model.SCEN, model.DEM, model.TIME, initialize=100.0)
+model.pow = pyo.Var(
model.SCEN, model.LINK_A, model.TIME, bounds=(0.0, 3000.0), initialize=1000.0
)
-model.slack = Var(
+model.slack = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(0.0, None), initialize=10.0
)
# define spatio-temporal variables
-model.px = Var(
+model.px = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(10.0, 100.0), initialize=50.0
)
-model.fx = Var(
+model.fx = pyo.Var(
model.SCEN, model.LINK, model.TIME, model.DIS, bounds=(1.0, 100.0), initialize=100.0
)
@@ -257,19 +265,19 @@ def powereq_rule(m, j, i, t):
)
-model.powereq = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=powereq_rule)
+model.powereq = pyo.Constraint(model.SCEN, model.LINK_A, model.TIME, rule=powereq_rule)
# cvar model
-model.cvar_lambda = Param(within=NonNegativeReals)
-model.nu = Var(initialize=100.0)
-model.phi = Var(model.SCEN, bounds=(0.0, None), initialize=100.0)
+model.cvar_lambda = pyo.Param(within=pyo.NonNegativeReals)
+model.nu = pyo.Var(initialize=100.0)
+model.phi = pyo.Var(model.SCEN, bounds=(0.0, None), initialize=100.0)
def cvarcost_rule(m):
return (1.0 / m.S) * sum((m.phi[k] / (1.0 - 0.95) + m.nu) for k in m.SCEN)
-model.cvarcost = Expression(rule=cvarcost_rule)
+model.cvarcost = pyo.Expression(rule=cvarcost_rule)
# node balances
@@ -283,7 +291,7 @@ def nodeeq_rule(m, k, i, t):
)
-model.nodeeq = Constraint(model.SCEN, model.NODE, model.TIME, rule=nodeeq_rule)
+model.nodeeq = pyo.Constraint(model.SCEN, model.NODE, model.TIME, rule=nodeeq_rule)
# boundary conditions flow
@@ -291,51 +299,57 @@ def flow_start_rule(m, j, i, t):
return m.fx[j, i, t, m.DIS.first()] == m.fin[j, i, t]
-model.flow_start = Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_start_rule)
+model.flow_start = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, rule=flow_start_rule
+)
def flow_end_rule(m, j, i, t):
return m.fx[j, i, t, m.DIS.last()] == m.fout[j, i, t]
-model.flow_end = Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_end_rule)
+model.flow_end = pyo.Constraint(model.SCEN, model.LINK, model.TIME, rule=flow_end_rule)
# First PDE for gas network model
def flow_rule(m, j, i, t, k):
if t == m.TIME.first() or k == m.DIS.last():
- return Constraint.Skip # Do not apply pde at initial time or final location
+ return pyo.Constraint.Skip # Do not apply pde at initial time or final location
return (
m.dpxdt[j, i, t, k] / 3600 + m.c1[i] / m.llength[i] * m.dfxdx[j, i, t, k] == 0
)
-model.flow = Constraint(model.SCEN, model.LINK, model.TIME, model.DIS, rule=flow_rule)
+model.flow = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, model.DIS, rule=flow_rule
+)
# Second PDE for gas network model
def press_rule(m, j, i, t, k):
if t == m.TIME.first() or k == m.DIS.last():
- return Constraint.Skip # Do not apply pde at initial time or final location
+ return pyo.Constraint.Skip # Do not apply pde at initial time or final location
return (
m.dfxdt[j, i, t, k] / 3600
== -m.c2[i] / m.llength[i] * m.dpxdx[j, i, t, k] - m.slack[j, i, t, k]
)
-model.press = Constraint(model.SCEN, model.LINK, model.TIME, model.DIS, rule=press_rule)
+model.press = pyo.Constraint(
+ model.SCEN, model.LINK, model.TIME, model.DIS, rule=press_rule
+)
def slackeq_rule(m, j, i, t, k):
if t == m.TIME.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
m.slack[j, i, t, k] * m.px[j, i, t, k]
== m.c3[i] * m.fx[j, i, t, k] * m.fx[j, i, t, k]
)
-model.slackeq = Constraint(
+model.slackeq = pyo.Constraint(
model.SCEN, model.LINK, model.TIME, model.DIS, rule=slackeq_rule
)
@@ -345,7 +359,7 @@ def presspas_start_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.first()] == m.p[j, m.lstartloc[i], t]
-model.presspas_start = Constraint(
+model.presspas_start = pyo.Constraint(
model.SCEN, model.LINK_P, model.TIME, rule=presspas_start_rule
)
@@ -354,7 +368,7 @@ def presspas_end_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.last()] == m.p[j, m.lendloc[i], t]
-model.presspas_end = Constraint(
+model.presspas_end = pyo.Constraint(
model.SCEN, model.LINK_P, model.TIME, rule=presspas_end_rule
)
@@ -364,7 +378,7 @@ def pressact_start_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.first()] == m.p[j, m.lstartloc[i], t] + m.dp[j, i, t]
-model.pressact_start = Constraint(
+model.pressact_start = pyo.Constraint(
model.SCEN, model.LINK_A, model.TIME, rule=pressact_start_rule
)
@@ -373,7 +387,7 @@ def pressact_end_rule(m, j, i, t):
return m.px[j, i, t, m.DIS.last()] == m.p[j, m.lendloc[i], t]
-model.pressact_end = Constraint(
+model.pressact_end = pyo.Constraint(
model.SCEN, model.LINK_A, model.TIME, rule=pressact_end_rule
)
@@ -383,7 +397,7 @@ def suppress_rule(m, k, j, t):
return m.p[k, m.sloc[j], t] == m.pmin[m.sloc[j]]
-model.suppress = Constraint(model.SCEN, model.SUP, model.TIME, rule=suppress_rule)
+model.suppress = pyo.Constraint(model.SCEN, model.SUP, model.TIME, rule=suppress_rule)
# discharge pressure for compressors
@@ -391,22 +405,24 @@ def dispress_rule(m, j, i, t):
return m.p[j, m.lstartloc[i], t] + m.dp[j, i, t] <= m.pmax[m.lstartloc[i]]
-model.dispress = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=dispress_rule)
+model.dispress = pyo.Constraint(
+ model.SCEN, model.LINK_A, model.TIME, rule=dispress_rule
+)
# ss constraints
def flow_ss_rule(m, j, i, k):
if k == m.DIS.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dfxdx[j, i, m.TIME.first(), k] / m.llength[i] == 0.0
-model.flow_ss = Constraint(model.SCEN, model.LINK, model.DIS, rule=flow_ss_rule)
+model.flow_ss = pyo.Constraint(model.SCEN, model.LINK, model.DIS, rule=flow_ss_rule)
def pres_ss_rule(m, j, i, k):
if k == m.DIS.last():
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
0.0
== -m.c2[i] / m.llength[i] * m.dpxdx[j, i, m.TIME.first(), k]
@@ -414,27 +430,29 @@ def pres_ss_rule(m, j, i, k):
)
-model.pres_ss = Constraint(model.SCEN, model.LINK, model.DIS, rule=pres_ss_rule)
+model.pres_ss = pyo.Constraint(model.SCEN, model.LINK, model.DIS, rule=pres_ss_rule)
# non-anticipativity constraints
def nonantdq_rule(m, j, i, t):
if j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if t >= m.TDEC + 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dp[j, i, t] == m.dp[1, i, t]
-model.nonantdq = Constraint(model.SCEN, model.LINK_A, model.TIME, rule=nonantdq_rule)
+model.nonantdq = pyo.Constraint(
+ model.SCEN, model.LINK_A, model.TIME, rule=nonantdq_rule
+)
def nonantde_rule(m, j, i, t):
if j == 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
if t >= m.TDEC + 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.dem[j, i, t] == m.dem[1, i, t]
-model.nonantde = Constraint(model.SCEN, model.DEM, model.TIME, rule=nonantde_rule)
+model.nonantde = pyo.Constraint(model.SCEN, model.DEM, model.TIME, rule=nonantde_rule)
diff --git a/examples/performance/jump/clnlbeam.py b/examples/performance/jump/clnlbeam.py
index 410068a6753..d00047e927f 100644
--- a/examples/performance/jump/clnlbeam.py
+++ b/examples/performance/jump/clnlbeam.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.N = Param(within=PositiveIntegers)
+model.N = pyo.Param(within=pyo.PositiveIntegers)
model.h = 1.0 / model.N
-model.VarIdx = RangeSet(model.N + 1)
+model.VarIdx = pyo.RangeSet(model.N + 1)
-model.t = Var(
- model.VarIdx, bounds=(-1.0, 1.0), initialize=lambda m, i: 0.05 * cos(i * m.h)
+model.t = pyo.Var(
+ model.VarIdx, bounds=(-1.0, 1.0), initialize=lambda m, i: 0.05 * pyo.cos(i * m.h)
)
-model.x = Var(
- model.VarIdx, bounds=(-0.05, 0.05), initialize=lambda m, i: 0.05 * cos(i * m.h)
+model.x = pyo.Var(
+ model.VarIdx, bounds=(-0.05, 0.05), initialize=lambda m, i: 0.05 * pyo.cos(i * m.h)
)
-model.u = Var(model.VarIdx, initialize=0.01)
+model.u = pyo.Var(model.VarIdx, initialize=0.01)
alpha = 350
@@ -35,27 +35,29 @@ def c_rule(m):
if i == m.N + 1:
continue
ex += 0.5 * m.h * (m.u[i + 1] ** 2 + m.u[i] ** 2) + 0.5 * alpha * m.h * (
- cos(m.t[i + 1]) + cos(m.t[i])
+ pyo.cos(m.t[i + 1]) + pyo.cos(m.t[i])
)
return ex
-model.c = Objective(rule=c_rule)
+model.c = pyo.Objective(rule=c_rule)
def cons1_rule(m, i):
if i == m.N + 1:
- return Constraint.Skip
- return m.x[i + 1] - m.x[i] - (0.5 * m.h) * (sin(m.t[i + 1]) + sin(m.t[i])) == 0
+ return pyo.Constraint.Skip
+ return (
+ m.x[i + 1] - m.x[i] - (0.5 * m.h) * (pyo.sin(m.t[i + 1]) + pyo.sin(m.t[i])) == 0
+ )
-model.cons1 = Constraint(model.VarIdx, rule=cons1_rule)
+model.cons1 = pyo.Constraint(model.VarIdx, rule=cons1_rule)
def cons2_rule(m, i):
if i == m.N + 1:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return m.t[i + 1] - m.t[i] - (0.5 * m.h) * m.u[i + 1] - (0.5 * m.h) * m.u[i] == 0
-model.cons2 = Constraint(model.VarIdx, rule=cons2_rule)
+model.cons2 = pyo.Constraint(model.VarIdx, rule=cons2_rule)
diff --git a/examples/performance/jump/facility.py b/examples/performance/jump/facility.py
index fa0c306d6e5..462116aab3a 100644
--- a/examples/performance/jump/facility.py
+++ b/examples/performance/jump/facility.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,36 +9,36 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.G = 25 # Param(within=PositiveIntegers)
-model.F = 25 # Param(within=PositiveIntegers)
+model.G = 25 # pyo.Param(within=pyo.PositiveIntegers)
+model.F = 25 # pyo.Param(within=pyo.PositiveIntegers)
-model.Grid = RangeSet(0, model.G)
-model.Facs = RangeSet(1, model.F)
-model.Dims = RangeSet(1, 2)
+model.Grid = pyo.RangeSet(0, model.G)
+model.Facs = pyo.RangeSet(1, model.F)
+model.Dims = pyo.RangeSet(1, 2)
-model.d = Var()
-model.y = Var(model.Facs, model.Dims, bounds=(0.0, 1.0))
-model.z = Var(model.Grid, model.Grid, model.Facs, within=Binary)
-model.s = Var(model.Grid, model.Grid, model.Facs, bounds=(0.0, None))
-model.r = Var(model.Grid, model.Grid, model.Facs, model.Dims)
+model.d = pyo.Var()
+model.y = pyo.Var(model.Facs, model.Dims, bounds=(0.0, 1.0))
+model.z = pyo.Var(model.Grid, model.Grid, model.Facs, within=pyo.Binary)
+model.s = pyo.Var(model.Grid, model.Grid, model.Facs, bounds=(0.0, None))
+model.r = pyo.Var(model.Grid, model.Grid, model.Facs, model.Dims)
def obj_rule(mod):
return 1.0 * mod.d
-model.obj = Objective(rule=obj_rule)
+model.obj = pyo.Objective(rule=obj_rule)
def assmt_rule(mod, i, j):
return sum([mod.z[i, j, f] for f in mod.Facs]) == 1
-model.assmt = Constraint(model.Grid, model.Grid, rule=assmt_rule)
+model.assmt = pyo.Constraint(model.Grid, model.Grid, rule=assmt_rule)
M = 2 * 1.414
@@ -47,25 +47,29 @@ def quadrhs_rule(mod, i, j, f):
return mod.s[i, j, f] == mod.d + M * (1 - mod.z[i, j, f])
-model.quadrhs = Constraint(model.Grid, model.Grid, model.Facs, rule=quadrhs_rule)
+model.quadrhs = pyo.Constraint(model.Grid, model.Grid, model.Facs, rule=quadrhs_rule)
def quaddistk1_rule(mod, i, j, f):
return mod.r[i, j, f, 1] == (1.0 * i) / mod.G - mod.y[f, 1]
-model.quaddistk1 = Constraint(model.Grid, model.Grid, model.Facs, rule=quaddistk1_rule)
+model.quaddistk1 = pyo.Constraint(
+ model.Grid, model.Grid, model.Facs, rule=quaddistk1_rule
+)
def quaddistk2_rule(mod, i, j, f):
return mod.r[i, j, f, 2] == (1.0 * j) / mod.G - mod.y[f, 2]
-model.quaddistk2 = Constraint(model.Grid, model.Grid, model.Facs, rule=quaddistk2_rule)
+model.quaddistk2 = pyo.Constraint(
+ model.Grid, model.Grid, model.Facs, rule=quaddistk2_rule
+)
def quaddist_rule(mod, i, j, f):
return mod.r[i, j, f, 1] ** 2 + mod.r[i, j, f, 2] ** 2 <= mod.s[i, j, f] ** 2
-model.quaddist = Constraint(model.Grid, model.Grid, model.Facs, rule=quaddist_rule)
+model.quaddist = pyo.Constraint(model.Grid, model.Grid, model.Facs, rule=quaddist_rule)
diff --git a/examples/performance/jump/lqcp.py b/examples/performance/jump/lqcp.py
index b8ef096d7be..db7e5b3b774 100644
--- a/examples/performance/jump/lqcp.py
+++ b/examples/performance/jump/lqcp.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,9 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
model.n = 1000
model.m = 1000
@@ -21,11 +21,11 @@
model.h2 = model.dx**2
model.a = 0.001
-model.ns = RangeSet(0, model.n)
-model.ms = RangeSet(0, model.n)
+model.ns = pyo.RangeSet(0, model.n)
+model.ms = pyo.RangeSet(0, model.n)
-model.y = Var(model.ms, model.ns, bounds=(0.0, 1.0))
-model.u = Var(model.ms, bounds=(-1.0, 1.0))
+model.y = pyo.Var(model.ms, model.ns, bounds=(0.0, 1.0))
+model.u = pyo.Var(model.ms, bounds=(-1.0, 1.0))
def yt(j, dx):
@@ -43,7 +43,7 @@ def rule(model):
)
-model.obj = Objective(rule=rule)
+model.obj = pyo.Objective(rule=rule)
def pde_rule(model, i, j):
@@ -57,8 +57,8 @@ def pde_rule(model, i, j):
) / model.h2
-model.pde = Constraint(
- RangeSet(0, model.n - 1), RangeSet(1, model.n - 1), rule=pde_rule
+model.pde = pyo.Constraint(
+ pyo.RangeSet(0, model.n - 1), pyo.RangeSet(1, model.n - 1), rule=pde_rule
)
@@ -66,14 +66,14 @@ def ic_rule(model, j):
return model.y[0, j] == 0
-model.ic = Constraint(model.ns, rule=ic_rule)
+model.ic = pyo.Constraint(model.ns, rule=ic_rule)
def bc1_rule(model, i):
return model.y[i, 2] - 4 * model.y[i, 1] + 3 * model.y[i, 0] == 0
-model.bc1 = Constraint(RangeSet(1, model.n), rule=bc1_rule)
+model.bc1 = pyo.Constraint(pyo.RangeSet(1, model.n), rule=bc1_rule)
def bc2_rule(model, i):
@@ -82,4 +82,4 @@ def bc2_rule(model, i):
] == (2 * model.dx) * (model.u[i] - model.y[i, model.n - 0])
-model.bc2 = Constraint(RangeSet(1, model.n), rule=bc2_rule)
+model.bc2 = pyo.Constraint(pyo.RangeSet(1, model.n), rule=bc2_rule)
diff --git a/examples/performance/jump/opf_66200bus.py b/examples/performance/jump/opf_66200bus.py
index 702ff59a61c..6af5071eb50 100644
--- a/examples/performance/jump/opf_66200bus.py
+++ b/examples/performance/jump/opf_66200bus.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
class Bus:
@@ -97,9 +97,9 @@ class Branch:
assert b.to >= 0 and b.to < nbus
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.bus_voltage = Var(
+model.bus_voltage = pyo.Var(
range(nbus),
bounds=lambda model, i: (
bus_voltage_min[bus[i].bustype],
@@ -107,17 +107,17 @@ class Branch:
),
initialize=1,
)
-model.bus_b_shunt = Var(
+model.bus_b_shunt = pyo.Var(
range(nbus),
bounds=lambda model, i: (bus[i].b_shunt_min, bus[i].b_shunt_max),
initialize=lambda model, i: bus[i].b_shunt0,
)
-model.bus_angle = Var(range(nbus), initialize=0)
+model.bus_angle = pyo.Var(range(nbus), initialize=0)
-model.branch_tap = Var(
+model.branch_tap = pyo.Var(
range(nbranch), bounds=(branch_tap_min, branch_tap_max), initialize=1
)
-model.branch_def = Var(
+model.branch_def = pyo.Var(
range(nbranch),
bounds=lambda model, i: (branch[i].def_min, branch[i].def_max),
initialize=lambda model, i: branch[i].def0,
@@ -134,13 +134,15 @@ def Gself(k):
def Gout(i):
return (
- -branch[i].g * cos(model.branch_def[i]) + branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ + branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
def Gin(i):
return (
- -branch[i].g * cos(model.branch_def[i]) - branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ - branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
@@ -157,17 +159,19 @@ def Bself(k):
def Bin(i):
return (
- branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
def Bout(i):
return (
- -branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ -branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
-model.obj = Objective(
+model.obj = pyo.Objective(
expr=sum(
(
bus[k].p_load
@@ -175,8 +179,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -184,8 +190,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -200,7 +208,7 @@ def Bout(i):
def p_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].p_gen
@@ -209,8 +217,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -218,8 +226,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -228,12 +236,12 @@ def p_load_rule(model, k):
)
-model.p_load_constr = Constraint(range(nbus), rule=p_load_rule)
+model.p_load_constr = pyo.Constraint(range(nbus), rule=p_load_rule)
def q_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_gen
@@ -242,8 +250,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -251,8 +259,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -261,12 +269,12 @@ def q_load_rule(model, k):
)
-model.q_load_constr = Constraint(range(nbus), rule=q_load_rule)
+model.q_load_constr = pyo.Constraint(range(nbus), rule=q_load_rule)
def q_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_min,
@@ -275,8 +283,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -284,8 +292,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -294,12 +302,12 @@ def q_inj_rule(model, k):
)
-model.q_inj_rule = Constraint(range(nbus), rule=q_inj_rule)
+model.q_inj_rule = pyo.Constraint(range(nbus), rule=q_inj_rule)
def p_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
0,
@@ -308,8 +316,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -317,8 +325,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -327,7 +335,7 @@ def p_inj_rule(model, k):
)
-model.p_inj_rule = Constraint(range(nbus), rule=p_inj_rule)
+model.p_inj_rule = pyo.Constraint(range(nbus), rule=p_inj_rule)
for i in range(nbus):
diff --git a/examples/performance/jump/opf_6620bus.py b/examples/performance/jump/opf_6620bus.py
index 34b910f43c0..bf02b63b5e8 100644
--- a/examples/performance/jump/opf_6620bus.py
+++ b/examples/performance/jump/opf_6620bus.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
class Bus:
@@ -97,9 +97,9 @@ class Branch:
assert b.to >= 0 and b.to < nbus
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.bus_voltage = Var(
+model.bus_voltage = pyo.Var(
range(nbus),
bounds=lambda model, i: (
bus_voltage_min[bus[i].bustype],
@@ -107,17 +107,17 @@ class Branch:
),
initialize=1,
)
-model.bus_b_shunt = Var(
+model.bus_b_shunt = pyo.Var(
range(nbus),
bounds=lambda model, i: (bus[i].b_shunt_min, bus[i].b_shunt_max),
initialize=lambda model, i: bus[i].b_shunt0,
)
-model.bus_angle = Var(range(nbus), initialize=0)
+model.bus_angle = pyo.Var(range(nbus), initialize=0)
-model.branch_tap = Var(
+model.branch_tap = pyo.Var(
range(nbranch), bounds=(branch_tap_min, branch_tap_max), initialize=1
)
-model.branch_def = Var(
+model.branch_def = pyo.Var(
range(nbranch),
bounds=lambda model, i: (branch[i].def_min, branch[i].def_max),
initialize=lambda model, i: branch[i].def0,
@@ -134,13 +134,15 @@ def Gself(k):
def Gout(i):
return (
- -branch[i].g * cos(model.branch_def[i]) + branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ + branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
def Gin(i):
return (
- -branch[i].g * cos(model.branch_def[i]) - branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ - branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
@@ -157,17 +159,19 @@ def Bself(k):
def Bin(i):
return (
- branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
def Bout(i):
return (
- -branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ -branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
-model.obj = Objective(
+model.obj = pyo.Objective(
expr=sum(
(
bus[k].p_load
@@ -175,8 +179,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -184,8 +190,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -200,7 +208,7 @@ def Bout(i):
def p_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].p_gen
@@ -209,8 +217,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -218,8 +226,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -228,12 +236,12 @@ def p_load_rule(model, k):
)
-model.p_load_constr = Constraint(range(nbus), rule=p_load_rule)
+model.p_load_constr = pyo.Constraint(range(nbus), rule=p_load_rule)
def q_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_gen
@@ -242,8 +250,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -251,8 +259,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -261,12 +269,12 @@ def q_load_rule(model, k):
)
-model.q_load_constr = Constraint(range(nbus), rule=q_load_rule)
+model.q_load_constr = pyo.Constraint(range(nbus), rule=q_load_rule)
def q_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_min,
@@ -275,8 +283,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -284,8 +292,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -294,12 +302,12 @@ def q_inj_rule(model, k):
)
-model.q_inj_rule = Constraint(range(nbus), rule=q_inj_rule)
+model.q_inj_rule = pyo.Constraint(range(nbus), rule=q_inj_rule)
def p_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
0,
@@ -308,8 +316,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -317,8 +325,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -327,7 +335,7 @@ def p_inj_rule(model, k):
)
-model.p_inj_rule = Constraint(range(nbus), rule=p_inj_rule)
+model.p_inj_rule = pyo.Constraint(range(nbus), rule=p_inj_rule)
for i in range(nbus):
diff --git a/examples/performance/jump/opf_662bus.py b/examples/performance/jump/opf_662bus.py
index 8a768ca16e0..672aa0e679b 100644
--- a/examples/performance/jump/opf_662bus.py
+++ b/examples/performance/jump/opf_662bus.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
class Bus:
@@ -97,9 +97,9 @@ class Branch:
assert b.to >= 0 and b.to < nbus
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.bus_voltage = Var(
+model.bus_voltage = pyo.Var(
range(nbus),
bounds=lambda model, i: (
bus_voltage_min[bus[i].bustype],
@@ -107,17 +107,17 @@ class Branch:
),
initialize=1,
)
-model.bus_b_shunt = Var(
+model.bus_b_shunt = pyo.Var(
range(nbus),
bounds=lambda model, i: (bus[i].b_shunt_min, bus[i].b_shunt_max),
initialize=lambda model, i: bus[i].b_shunt0,
)
-model.bus_angle = Var(range(nbus), initialize=0)
+model.bus_angle = pyo.Var(range(nbus), initialize=0)
-model.branch_tap = Var(
+model.branch_tap = pyo.Var(
range(nbranch), bounds=(branch_tap_min, branch_tap_max), initialize=1
)
-model.branch_def = Var(
+model.branch_def = pyo.Var(
range(nbranch),
bounds=lambda model, i: (branch[i].def_min, branch[i].def_max),
initialize=lambda model, i: branch[i].def0,
@@ -134,13 +134,15 @@ def Gself(k):
def Gout(i):
return (
- -branch[i].g * cos(model.branch_def[i]) + branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ + branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
def Gin(i):
return (
- -branch[i].g * cos(model.branch_def[i]) - branch[i].b * sin(model.branch_def[i])
+ -branch[i].g * pyo.cos(model.branch_def[i])
+ - branch[i].b * pyo.sin(model.branch_def[i])
) * model.branch_tap[i]
@@ -157,17 +159,19 @@ def Bself(k):
def Bin(i):
return (
- branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
def Bout(i):
return (
- -branch[i].g * sin(model.branch_def[i]) - branch[i].b * cos(model.branch_def[i])
+ -branch[i].g * pyo.sin(model.branch_def[i])
+ - branch[i].b * pyo.cos(model.branch_def[i])
) * model.branch_tap[i]
-model.obj = Objective(
+model.obj = pyo.Objective(
expr=sum(
(
bus[k].p_load
@@ -175,8 +179,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -184,8 +190,10 @@ def Bout(i):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i)
+ * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i)
+ * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -200,7 +208,7 @@ def Bout(i):
def p_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].p_gen
@@ -209,8 +217,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -218,8 +226,8 @@ def p_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -228,12 +236,12 @@ def p_load_rule(model, k):
)
-model.p_load_constr = Constraint(range(nbus), rule=p_load_rule)
+model.p_load_constr = pyo.Constraint(range(nbus), rule=p_load_rule)
def q_load_rule(model, k):
if bus[k].bustype != 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_gen
@@ -242,8 +250,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -251,8 +259,8 @@ def q_load_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -261,12 +269,12 @@ def q_load_rule(model, k):
)
-model.q_load_constr = Constraint(range(nbus), rule=q_load_rule)
+model.q_load_constr = pyo.Constraint(range(nbus), rule=q_load_rule)
def q_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
bus[k].q_min,
@@ -275,8 +283,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- - Bin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ - Bin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -284,8 +292,8 @@ def q_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
- - Bout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ - Bout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -294,12 +302,12 @@ def q_inj_rule(model, k):
)
-model.q_inj_rule = Constraint(range(nbus), rule=q_inj_rule)
+model.q_inj_rule = pyo.Constraint(range(nbus), rule=q_inj_rule)
def p_inj_rule(model, k):
if not (bus[k].bustype == 2 or bus[k].bustype == 3):
- return Constraint.Skip
+ return pyo.Constraint.Skip
return (
0,
@@ -308,8 +316,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].frm]
* (
- Gin(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
- + Bin(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ Gin(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].frm])
+ + Bin(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].frm])
)
for i in in_lines[k]
)
@@ -317,8 +325,8 @@ def p_inj_rule(model, k):
model.bus_voltage[k]
* model.bus_voltage[branch[i].to]
* (
- Gout(i) * cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
- + Bout(i) * sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ Gout(i) * pyo.cos(model.bus_angle[k] - model.bus_angle[branch[i].to])
+ + Bout(i) * pyo.sin(model.bus_angle[k] - model.bus_angle[branch[i].to])
)
for i in out_lines[k]
)
@@ -327,7 +335,7 @@ def p_inj_rule(model, k):
)
-model.p_inj_rule = Constraint(range(nbus), rule=p_inj_rule)
+model.p_inj_rule = pyo.Constraint(range(nbus), rule=p_inj_rule)
for i in range(nbus):
diff --git a/examples/performance/misc/bilinear1_100.py b/examples/performance/misc/bilinear1_100.py
index d86091c4c76..90ee4e7e4cc 100644
--- a/examples/performance/misc/bilinear1_100.py
+++ b/examples/performance/misc/bilinear1_100.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,21 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A, bounds=(1, 2))
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A, bounds=(1, 2))
expr = 0
for i in model.A:
if not (i + 1) in model.A:
continue
expr += i * (model.x[i] * model.x[i + 1] + 1)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
return model
diff --git a/examples/performance/misc/bilinear1_100000.py b/examples/performance/misc/bilinear1_100000.py
index 0fa2eafedc6..5dc26bedc60 100644
--- a/examples/performance/misc/bilinear1_100000.py
+++ b/examples/performance/misc/bilinear1_100000.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,21 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A, bounds=(1, 2))
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A, bounds=(1, 2))
expr = 0
for i in model.A:
if not (i + 1) in model.A:
continue
expr += i * (model.x[i] * model.x[i + 1] + 1)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
return model
diff --git a/examples/performance/misc/bilinear2_100.py b/examples/performance/misc/bilinear2_100.py
index 227bfe000e0..9c21d19f986 100644
--- a/examples/performance/misc/bilinear2_100.py
+++ b/examples/performance/misc/bilinear2_100.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,21 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A, bounds=(1, 2))
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A, bounds=(1, 2))
- with nonlinear_expression as expr:
+ with pyo.nonlinear_expression as expr:
for i in model.A:
if not (i + 1) in model.A:
continue
expr += i * (model.x[i] * model.x[i + 1] + 1)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
return model
diff --git a/examples/performance/misc/bilinear2_100000.py b/examples/performance/misc/bilinear2_100000.py
index 9d2a4d6fb7c..805fccc9a9a 100644
--- a/examples/performance/misc/bilinear2_100000.py
+++ b/examples/performance/misc/bilinear2_100000.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,21 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A, bounds=(1, 2))
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A, bounds=(1, 2))
- with nonlinear_expression as expr:
+ with pyo.nonlinear_expression as expr:
for i in model.A:
if not (i + 1) in model.A:
continue
expr += i * (model.x[i] * model.x[i + 1] + 1)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
return model
diff --git a/examples/performance/misc/diag1_100.py b/examples/performance/misc/diag1_100.py
index 369d81982f0..97034c8b679 100644
--- a/examples/performance/misc/diag1_100.py
+++ b/examples/performance/misc/diag1_100.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A)
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A)
expr = sum(i * model.x[i] for i in model.A)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
def c_rule(model, i):
return (N - i + 1) * model.x[i] >= N
- model.c = Constraint(model.A)
+ model.c = pyo.Constraint(model.A)
return model
diff --git a/examples/performance/misc/diag1_100000.py b/examples/performance/misc/diag1_100000.py
index 536758fda5d..8a94c85419c 100644
--- a/examples/performance/misc/diag1_100000.py
+++ b/examples/performance/misc/diag1_100000.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A)
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A)
expr = sum(i * model.x[i] for i in model.A)
- model.obj = Objective(expr=expr)
+ model.obj = pyo.Objective(expr=expr)
def c_rule(model, i):
return (N - i + 1) * model.x[i] >= N
- model.c = Constraint(model.A)
+ model.c = pyo.Constraint(model.A)
return model
diff --git a/examples/performance/misc/diag2_100.py b/examples/performance/misc/diag2_100.py
index 6ad47528ff2..c3ef1eacfaa 100644
--- a/examples/performance/misc/diag2_100.py
+++ b/examples/performance/misc/diag2_100.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A)
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A)
- expr = Sum(i * model.x[i] for i in model.A)
- model.obj = Objective(expr=expr)
+ expr = pyo.quicksum(i * model.x[i] for i in model.A)
+ model.obj = pyo.Objective(expr=expr)
def c_rule(model, i):
return (N - i + 1) * model.x[i] >= N
- model.c = Constraint(model.A)
+ model.c = pyo.Constraint(model.A)
return model
diff --git a/examples/performance/misc/diag2_100000.py b/examples/performance/misc/diag2_100000.py
index b95e2dd1d6f..e59f765a5b9 100644
--- a/examples/performance/misc/diag2_100000.py
+++ b/examples/performance/misc/diag2_100000.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def create_model(N):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
- model.A = RangeSet(N)
- model.x = Var(model.A)
+ model.A = pyo.RangeSet(N)
+ model.x = pyo.Var(model.A)
- expr = Sum(i * model.x[i] for i in model.A)
- model.obj = Objective(expr=expr)
+ expr = pyo.quicksum(i * model.x[i] for i in model.A)
+ model.obj = pyo.Objective(expr=expr)
def c_rule(model, i):
return (N - i + 1) * model.x[i] >= N
- model.c = Constraint(model.A)
+ model.c = pyo.Constraint(model.A)
return model
diff --git a/examples/performance/misc/set1.py b/examples/performance/misc/set1.py
index 8a8b84fdcc3..fb251b784b3 100644
--- a/examples/performance/misc/set1.py
+++ b/examples/performance/misc/set1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,25 +9,25 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.d = Param(default=10)
+model.d = pyo.Param(default=10)
def A_rule(model):
- return range(0, value(model.d))
+ return range(0, pyo.value(model.d))
-model.A = Set()
+model.A = pyo.Set()
def B_rule(model):
- return range(1, value(model.d) + 1)
+ return range(1, pyo.value(model.d) + 1)
-model.B = Set()
+model.B = pyo.Set()
if 1 > 0:
model.X1 = model.A * model.B
@@ -36,7 +36,7 @@ def B_rule(model):
model.X4 = model.B - model.A
model.X5 = model.B & model.A
-model.Y = Set(initialize=model.B - model.A)
+model.Y = pyo.Set(initialize=model.B - model.A)
model.Y.add('foo')
if 1 > 0:
diff --git a/examples/performance/misc/sparse1.py b/examples/performance/misc/sparse1.py
index b4883d379bc..7f80ae9d83b 100644
--- a/examples/performance/misc/sparse1.py
+++ b/examples/performance/misc/sparse1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,21 +12,21 @@
#
# This is a performance test that we cannot easily execute right now
#
-from pyomo.environ import *
+import pyomo.environ as pyo
def f(N):
- M = ConcreteModel()
- M.A = Set(initialize=range(N))
- M.x = Var()
- M.o = Objective(expr=M.x)
+ M = pyo.ConcreteModel()
+ M.A = pyo.Set(initialize=range(N))
+ M.x = pyo.Var()
+ M.o = pyo.Objective(expr=M.x)
def rule(m, i):
if i == 3 or i == 5:
return M.x >= i
- return Constraint.Skip
+ return pyo.Constraint.Skip
- M.c = Constraint(M.A, rule=rule)
+ M.c = pyo.Constraint(M.A, rule=rule)
return M
diff --git a/examples/performance/pmedian/pmedian1.py b/examples/performance/pmedian/pmedian1.py
index a22540efdd5..a9f708be85f 100644
--- a/examples/performance/pmedian/pmedian1.py
+++ b/examples/performance/pmedian/pmedian1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def pyomo_create_model(options=None, model_options=None):
@@ -18,28 +18,30 @@ def pyomo_create_model(options=None, model_options=None):
random.seed(1000)
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.N = Param(within=PositiveIntegers)
+ model.N = pyo.Param(within=pyo.PositiveIntegers)
- model.Locations = RangeSet(1, model.N)
+ model.Locations = pyo.RangeSet(1, model.N)
- model.P = Param(within=RangeSet(1, model.N))
+ model.P = pyo.Param(within=pyo.RangeSet(1, model.N))
- model.M = Param(within=PositiveIntegers)
+ model.M = pyo.Param(within=pyo.PositiveIntegers)
- model.Customers = RangeSet(1, model.M)
+ model.Customers = pyo.RangeSet(1, model.M)
- model.d = Param(
+ model.d = pyo.Param(
model.Locations,
model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
- within=Reals,
+ within=pyo.Reals,
)
- model.x = Var(model.Locations, model.Customers, bounds=(0.0, 1.0), initialize=0.0)
+ model.x = pyo.Var(
+ model.Locations, model.Customers, bounds=(0.0, 1.0), initialize=0.0
+ )
- model.y = Var(model.Locations, bounds=(0.0, 1.0), initialize=0.0)
+ model.y = pyo.Var(model.Locations, bounds=(0.0, 1.0), initialize=0.0)
def rule(model):
return sum(
@@ -48,21 +50,21 @@ def rule(model):
for m in model.Customers
)
- model.obj = Objective(rule=rule)
+ model.obj = pyo.Objective(rule=rule)
def rule(model, m):
return (sum(model.x[n, m] for n in model.Locations), 1.0)
- model.single_x = Constraint(model.Customers, rule=rule)
+ model.single_x = pyo.Constraint(model.Customers, rule=rule)
def rule(model, n, m):
return (None, model.x[n, m] - model.y[n], 0.0)
- model.bound_y = Constraint(model.Locations, model.Customers, rule=rule)
+ model.bound_y = pyo.Constraint(model.Locations, model.Customers, rule=rule)
def rule(model):
return (sum(model.y[n] for n in model.Locations) - model.P, 0.0)
- model.num_facilities = Constraint(rule=rule)
+ model.num_facilities = pyo.Constraint(rule=rule)
return model
diff --git a/examples/performance/pmedian/pmedian2.py b/examples/performance/pmedian/pmedian2.py
index ff25a6c15eb..a9f708be85f 100644
--- a/examples/performance/pmedian/pmedian2.py
+++ b/examples/performance/pmedian/pmedian2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def pyomo_create_model(options=None, model_options=None):
@@ -18,51 +18,53 @@ def pyomo_create_model(options=None, model_options=None):
random.seed(1000)
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.N = Param(within=PositiveIntegers)
+ model.N = pyo.Param(within=pyo.PositiveIntegers)
- model.Locations = RangeSet(1, model.N)
+ model.Locations = pyo.RangeSet(1, model.N)
- model.P = Param(within=RangeSet(1, model.N))
+ model.P = pyo.Param(within=pyo.RangeSet(1, model.N))
- model.M = Param(within=PositiveIntegers)
+ model.M = pyo.Param(within=pyo.PositiveIntegers)
- model.Customers = RangeSet(1, model.M)
+ model.Customers = pyo.RangeSet(1, model.M)
- model.d = Param(
+ model.d = pyo.Param(
model.Locations,
model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
- within=Reals,
+ within=pyo.Reals,
)
- model.x = Var(model.Locations, model.Customers, bounds=(0.0, 1.0), initialize=0.0)
+ model.x = pyo.Var(
+ model.Locations, model.Customers, bounds=(0.0, 1.0), initialize=0.0
+ )
- model.y = Var(model.Locations, bounds=(0.0, 1.0), initialize=0.0)
+ model.y = pyo.Var(model.Locations, bounds=(0.0, 1.0), initialize=0.0)
def rule(model):
- return Sum(
+ return sum(
model.d[n, m] * model.x[n, m]
for n in model.Locations
for m in model.Customers
)
- model.obj = Objective(rule=rule)
+ model.obj = pyo.Objective(rule=rule)
def rule(model, m):
- return (Sum(model.x[n, m] for n in model.Locations), 1.0)
+ return (sum(model.x[n, m] for n in model.Locations), 1.0)
- model.single_x = Constraint(model.Customers, rule=rule)
+ model.single_x = pyo.Constraint(model.Customers, rule=rule)
def rule(model, n, m):
return (None, model.x[n, m] - model.y[n], 0.0)
- model.bound_y = Constraint(model.Locations, model.Customers, rule=rule)
+ model.bound_y = pyo.Constraint(model.Locations, model.Customers, rule=rule)
def rule(model):
- return (Sum(model.y[n] for n in model.Locations) - model.P, 0.0)
+ return (sum(model.y[n] for n in model.Locations) - model.P, 0.0)
- model.num_facilities = Constraint(rule=rule)
+ model.num_facilities = pyo.Constraint(rule=rule)
return model
diff --git a/examples/pyomo/amplbook2/diet.py b/examples/pyomo/amplbook2/diet.py
index cc52eacae20..78b2da63b80 100644
--- a/examples/pyomo/amplbook2/diet.py
+++ b/examples/pyomo/amplbook2/diet.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,53 +11,53 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.NUTR = Set()
+model.NUTR = pyo.Set()
-model.FOOD = Set()
+model.FOOD = pyo.Set()
-model.cost = Param(model.FOOD, within=NonNegativeReals)
+model.cost = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
def f_max_valid(model, value, j):
return value > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_valid)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_valid)
-model.n_min = Param(model.NUTR, within=NonNegativeReals)
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals)
def paramn_max(model, value, i):
return value > model.n_min[i]
-model.n_max = Param(model.NUTR, validate=paramn_max)
+model.n_max = pyo.Param(model.NUTR, validate=paramn_max)
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds)
def Objective_rule(model):
- return sum_product(model.cost, model.Buy)
+ return pyo.sum_product(model.cost, model.Buy)
-model.totalcost = Objective(rule=Objective_rule)
+model.totalcost = pyo.Objective(rule=Objective_rule)
def Diet_rule(model, i):
@@ -67,4 +67,4 @@ def Diet_rule(model, i):
return (model.n_min[i], expr, model.n_max[i])
-model.Diet = Constraint(model.NUTR, rule=Diet_rule)
+model.Diet = pyo.Constraint(model.NUTR, rule=Diet_rule)
diff --git a/examples/pyomo/amplbook2/dieti.py b/examples/pyomo/amplbook2/dieti.py
index 45d403dd810..00d611048d7 100644
--- a/examples/pyomo/amplbook2/dieti.py
+++ b/examples/pyomo/amplbook2/dieti.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,53 +11,53 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.NUTR = Set()
+model.NUTR = pyo.Set()
-model.FOOD = Set()
+model.FOOD = pyo.Set()
-model.cost = Param(model.FOOD, within=NonNegativeReals)
+model.cost = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
def f_max_valid(model, value, j):
return value > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_valid)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_valid)
-model.n_min = Param(model.NUTR, within=NonNegativeReals)
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals)
def paramn_max(model, value, i):
return value > model.n_min[i]
-model.n_max = Param(model.NUTR, validate=paramn_max)
+model.n_max = pyo.Param(model.NUTR, validate=paramn_max)
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds, domain=Integers)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds, domain=pyo.Integers)
def Objective_rule(model):
- return sum_product(model.cost, model.Buy)
+ return pyo.sum_product(model.cost, model.Buy)
-model.totalcost = Objective(rule=Objective_rule)
+model.totalcost = pyo.Objective(rule=Objective_rule)
def Diet_rule(model, i):
@@ -67,4 +67,4 @@ def Diet_rule(model, i):
return (model.n_min[i], expr, model.n_max[i])
-model.Diet = Constraint(model.NUTR, rule=Diet_rule)
+model.Diet = pyo.Constraint(model.NUTR, rule=Diet_rule)
diff --git a/examples/pyomo/amplbook2/econ2min.py b/examples/pyomo/amplbook2/econ2min.py
index fb870e02364..908e5cf34b1 100644
--- a/examples/pyomo/amplbook2/econ2min.py
+++ b/examples/pyomo/amplbook2/econ2min.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,43 +12,43 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
# ***********************************
-model.PROD = Set(doc='products')
+model.PROD = pyo.Set(doc='products')
-model.ACT = Set(doc='activities')
+model.ACT = pyo.Set(doc='activities')
# ***********************************
-model.cost = Param(
- model.ACT, within=PositiveReals, doc='cost per unit of each activity'
+model.cost = pyo.Param(
+ model.ACT, within=pyo.PositiveReals, doc='cost per unit of each activity'
)
-model.demand = Param(
- model.PROD, within=NonNegativeReals, doc='units of demand for each product'
+model.demand = pyo.Param(
+ model.PROD, within=pyo.NonNegativeReals, doc='units of demand for each product'
)
-model.io = Param(
+model.io = pyo.Param(
model.PROD,
model.ACT,
- within=NonNegativeReals,
+ within=pyo.NonNegativeReals,
doc='units of each product from 1 unit of each activity',
)
-model.level_min = Param(
- model.ACT, within=NonNegativeReals, doc='min allowed level for each activity'
+model.level_min = pyo.Param(
+ model.ACT, within=pyo.NonNegativeReals, doc='min allowed level for each activity'
)
-model.level_max = Param(
- model.ACT, within=NonNegativeReals, doc='max allowed level for each activity'
+model.level_max = pyo.Param(
+ model.ACT, within=pyo.NonNegativeReals, doc='max allowed level for each activity'
)
# ***********************************
@@ -58,16 +58,16 @@ def Level_bounds(model, i):
return (model.level_min[i], model.level_max[i])
-model.Level = Var(model.ACT, bounds=Level_bounds, doc='level for each activity')
+model.Level = pyo.Var(model.ACT, bounds=Level_bounds, doc='level for each activity')
# ***********************************
def Total_Cost_rule(model):
- return sum_product(model.cost, model.Level)
+ return pyo.sum_product(model.cost, model.Level)
-model.Total_Cost = Objective(rule=Total_Cost_rule, doc='minimize total cost')
+model.Total_Cost = pyo.Objective(rule=Total_Cost_rule, doc='minimize total cost')
def Demand_rule(model, i):
@@ -77,6 +77,6 @@ def Demand_rule(model, i):
return model.demand[i] < expr
-model.Demand = Constraint(
+model.Demand = pyo.Constraint(
model.PROD, rule=Demand_rule, doc='total level for each activity exceeds demand'
)
diff --git a/examples/pyomo/amplbook2/econmin.py b/examples/pyomo/amplbook2/econmin.py
index d9c95758d4d..ff70fcca094 100644
--- a/examples/pyomo/amplbook2/econmin.py
+++ b/examples/pyomo/amplbook2/econmin.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,40 +11,40 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
# ***********************************
-model.PROD = Set()
+model.PROD = pyo.Set()
-model.ACT = Set()
+model.ACT = pyo.Set()
# ***********************************
-model.cost = Param(model.ACT, within=PositiveReals)
+model.cost = pyo.Param(model.ACT, within=pyo.PositiveReals)
-model.demand = Param(model.PROD, within=NonNegativeReals)
+model.demand = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
-model.io = Param(model.PROD, model.ACT, within=NonNegativeReals)
+model.io = pyo.Param(model.PROD, model.ACT, within=pyo.NonNegativeReals)
# ***********************************
-model.Level = Var(model.ACT)
+model.Level = pyo.Var(model.ACT)
# ***********************************
def Total_Cost_rule(model):
- return sum_product(model.cost, model.Level)
+ return pyo.sum_product(model.cost, model.Level)
-model.Total_Cost = Objective(rule=Total_Cost_rule)
+model.Total_Cost = pyo.Objective(rule=Total_Cost_rule)
def Demand_rule(model, i):
@@ -54,4 +54,4 @@ def Demand_rule(model, i):
return expr > model.demand[i]
-model.Demand = Constraint(model.PROD, rule=Demand_rule)
+model.Demand = pyo.Constraint(model.PROD, rule=Demand_rule)
diff --git a/examples/pyomo/amplbook2/prod.py b/examples/pyomo/amplbook2/prod.py
index 236f7254b29..be1898c9b18 100644
--- a/examples/pyomo/amplbook2/prod.py
+++ b/examples/pyomo/amplbook2/prod.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,22 +10,22 @@
# ___________________________________________________________________________
# Imports
-from pyomo.core import *
+import pyomo.environ as pyo
# Create the model object
-model = AbstractModel()
+model = pyo.AbstractModel()
# Sets
-model.P = Set()
+model.P = pyo.Set()
# Parameters
-model.a = Param(model.P)
-model.b = Param()
-model.c = Param(model.P)
-model.u = Param(model.P)
+model.a = pyo.Param(model.P)
+model.b = pyo.Param()
+model.c = pyo.Param(model.P)
+model.u = pyo.Param(model.P)
# Variables
-model.X = Var(model.P)
+model.X = pyo.Var(model.P)
# Objective
@@ -33,15 +33,15 @@ def Objective_rule(model):
return sum([model.c[j] * model.X[j] for j in model.P])
-model.Total_Profit = Objective(rule=Objective_rule, sense=maximize)
+model.Total_Profit = pyo.Objective(rule=Objective_rule, sense=pyo.maximize)
# Time Constraint
def Time_rule(model):
- return sum_product(model.X, denom=model.a) <= model.b
+ return pyo.sum_product(model.X, denom=model.a) <= model.b
-model.Time = Constraint(rule=Time_rule)
+model.Time = pyo.Constraint(rule=Time_rule)
# Limit Constraint
@@ -49,4 +49,4 @@ def Limit_rule(model, j):
return (0, model.X[j], model.u[j])
-model.Limit = Constraint(model.P, rule=Limit_rule)
+model.Limit = pyo.Constraint(model.P, rule=Limit_rule)
diff --git a/examples/pyomo/amplbook2/steel.py b/examples/pyomo/amplbook2/steel.py
index 8c5c9b2a1d3..3d00d79f486 100644
--- a/examples/pyomo/amplbook2/steel.py
+++ b/examples/pyomo/amplbook2/steel.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,37 +12,37 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.PROD = Set()
+model.PROD = pyo.Set()
-model.rate = Param(model.PROD, within=PositiveReals)
+model.rate = pyo.Param(model.PROD, within=pyo.PositiveReals)
-model.avail = Param(within=NonNegativeReals)
+model.avail = pyo.Param(within=pyo.NonNegativeReals)
-model.profit = Param(model.PROD)
+model.profit = pyo.Param(model.PROD)
-model.market = Param(model.PROD, within=NonNegativeReals)
+model.market = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
def Make_bounds(model, i):
return (0, model.market[i])
-model.Make = Var(model.PROD, bounds=Make_bounds)
+model.Make = pyo.Var(model.PROD, bounds=Make_bounds)
def Objective_rule(model):
- return sum_product(model.profit, model.Make)
+ return pyo.sum_product(model.profit, model.Make)
-model.Total_Profit = Objective(rule=Objective_rule, sense=maximize)
+model.Total_Profit = pyo.Objective(rule=Objective_rule, sense=pyo.maximize)
def Time_rule(model):
@@ -53,7 +53,7 @@ def Time_rule(model):
def XTime_rule(model):
- return sum_product(model.Make, denom=(model.rate,)) < model.avail
+ return pyo.sum_product(model.Make, denom=(model.rate,)) < model.avail
-# model.Time = Constraint(rule=Time_rule)
+# model.Time = pyo.Constraint(rule=Time_rule)
diff --git a/examples/pyomo/amplbook2/steel3.py b/examples/pyomo/amplbook2/steel3.py
index dd3b3ac202f..d5544d04865 100644
--- a/examples/pyomo/amplbook2/steel3.py
+++ b/examples/pyomo/amplbook2/steel3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,43 +12,43 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.PROD = Set()
+model.PROD = pyo.Set()
-model.rate = Param(model.PROD, within=PositiveReals)
+model.rate = pyo.Param(model.PROD, within=pyo.PositiveReals)
-model.avail = Param(within=NonNegativeReals)
+model.avail = pyo.Param(within=pyo.NonNegativeReals)
-model.profit = Param(model.PROD)
+model.profit = pyo.Param(model.PROD)
-model.commit = Param(model.PROD, within=NonNegativeReals)
+model.commit = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
-model.market = Param(model.PROD, within=NonNegativeReals)
+model.market = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
def Make_bounds(model, i):
return (model.commit[i], model.market[i])
-model.Make = Var(model.PROD, bounds=Make_bounds)
+model.Make = pyo.Var(model.PROD, bounds=Make_bounds)
def Objective_rule(model):
- return sum_product(model.profit, model.Make)
+ return pyo.sum_product(model.profit, model.Make)
-model.totalprofit = Objective(rule=Objective_rule, sense=maximize)
+model.totalprofit = pyo.Objective(rule=Objective_rule, sense=pyo.maximize)
def Time_rule(model):
- return sum_product(model.Make, denom=(model.rate)) < model.avail
+ return pyo.sum_product(model.Make, denom=(model.rate)) < model.avail
-model.Time = Constraint(rule=Time_rule)
+model.Time = pyo.Constraint(rule=Time_rule)
diff --git a/examples/pyomo/amplbook2/steel4.py b/examples/pyomo/amplbook2/steel4.py
index 10cb0979d24..45d20400575 100644
--- a/examples/pyomo/amplbook2/steel4.py
+++ b/examples/pyomo/amplbook2/steel4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,41 +12,41 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.PROD = Set()
+model.PROD = pyo.Set()
-model.STAGE = Set()
+model.STAGE = pyo.Set()
-model.rate = Param(model.PROD, model.STAGE, within=PositiveReals)
+model.rate = pyo.Param(model.PROD, model.STAGE, within=pyo.PositiveReals)
-model.avail = Param(model.STAGE, within=NonNegativeReals)
+model.avail = pyo.Param(model.STAGE, within=pyo.NonNegativeReals)
-model.profit = Param(model.PROD)
+model.profit = pyo.Param(model.PROD)
-model.commit = Param(model.PROD, within=NonNegativeReals)
+model.commit = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
-model.market = Param(model.PROD, within=NonNegativeReals)
+model.market = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
def Make_bounds(model, i):
return (model.commit[i], model.market[i])
-model.Make = Var(model.PROD, bounds=Make_bounds)
+model.Make = pyo.Var(model.PROD, bounds=Make_bounds)
def Objective_rule(model):
- return sum_product(model.profit, model.Make)
+ return pyo.sum_product(model.profit, model.Make)
-model.Total_Profit = Objective(rule=Objective_rule, sense=maximize)
+model.Total_Profit = pyo.Objective(rule=Objective_rule, sense=pyo.maximize)
def Timelim_rule(model, s):
@@ -56,4 +56,4 @@ def Timelim_rule(model, s):
return timeexpr < model.avail[s]
-model.Time = Constraint(model.STAGE, rule=Timelim_rule)
+model.Time = pyo.Constraint(model.STAGE, rule=Timelim_rule)
diff --git a/examples/pyomo/benders/master.py b/examples/pyomo/benders/master.py
index 372810dc024..fabf235b857 100644
--- a/examples/pyomo/benders/master.py
+++ b/examples/pyomo/benders/master.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,81 +12,85 @@
### Pyomo master for AMPL Bender's example, available
### from http://www.ampl.com/NEW/LOOP2/stoch2.mod
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel(name="Master")
+model = pyo.AbstractModel(name="Master")
##############################################################################
-model.NUMSCEN = Param(within=PositiveIntegers)
+model.NUMSCEN = pyo.Param(within=pyo.PositiveIntegers)
-model.SCEN = RangeSet(model.NUMSCEN)
+model.SCEN = pyo.RangeSet(model.NUMSCEN)
# products
-model.PROD = Set()
+model.PROD = pyo.Set()
# number of weeks
-model.T = Param(within=PositiveIntegers)
+model.T = pyo.Param(within=pyo.PositiveIntegers)
# derived set containing all valid week indices and subsets of interest.
-model.WEEKS = RangeSet(model.T)
+model.WEEKS = pyo.RangeSet(model.T)
-model.TWOPLUSWEEKS = RangeSet(2, model.T)
+model.TWOPLUSWEEKS = pyo.RangeSet(2, model.T)
# tons per hour produced
-model.rate = Param(model.PROD, within=PositiveReals)
+model.rate = pyo.Param(model.PROD, within=pyo.PositiveReals)
# hours available in week
-model.avail = Param(model.WEEKS, within=NonNegativeReals)
+model.avail = pyo.Param(model.WEEKS, within=pyo.NonNegativeReals)
# limit on tons sold in week
-model.market = Param(model.PROD, model.WEEKS, within=NonNegativeReals)
+model.market = pyo.Param(model.PROD, model.WEEKS, within=pyo.NonNegativeReals)
# cost per ton produced
-model.prodcost = Param(model.PROD, within=NonNegativeReals)
+model.prodcost = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
# carrying cost/ton of inventory
-model.invcost = Param(model.PROD, within=NonNegativeReals)
+model.invcost = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
# initial inventory
-model.inv0 = Param(model.PROD, within=NonNegativeReals)
+model.inv0 = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
# projected revenue/ton, per scenario.
-model.revenue = Param(model.PROD, model.WEEKS, model.SCEN, within=NonNegativeReals)
+model.revenue = pyo.Param(
+ model.PROD, model.WEEKS, model.SCEN, within=pyo.NonNegativeReals
+)
def prob_validator(model, value, s):
return (value >= 0) and (value <= 1.0)
-model.prob = Param(model.SCEN, validate=prob_validator)
+model.prob = pyo.Param(model.SCEN, validate=prob_validator)
##############################################################################
-model.Make1 = Var(model.PROD, within=NonNegativeReals)
+model.Make1 = pyo.Var(model.PROD, within=pyo.NonNegativeReals)
-model.Inv1 = Var(model.PROD, within=NonNegativeReals)
+model.Inv1 = pyo.Var(model.PROD, within=pyo.NonNegativeReals)
def sell_bounds(model, p):
return (0, model.market[p, 1])
-model.Sell1 = Var(model.PROD, within=NonNegativeReals, bounds=sell_bounds)
+model.Sell1 = pyo.Var(model.PROD, within=pyo.NonNegativeReals, bounds=sell_bounds)
-model.Min_Stage2_Profit = Var(within=NonNegativeReals)
+model.Min_Stage2_Profit = pyo.Var(within=pyo.NonNegativeReals)
##############################################################################
-model.CUTS = Set(within=PositiveIntegers, ordered=True)
+model.CUTS = pyo.Set(within=pyo.PositiveIntegers, ordered=True)
-model.time_price = Param(
+model.time_price = pyo.Param(
model.TWOPLUSWEEKS, model.SCEN, model.CUTS, default=0.0, mutable=True
)
-model.bal2_price = Param(model.PROD, model.SCEN, model.CUTS, default=0.0, mutable=True)
+model.bal2_price = pyo.Param(
+ model.PROD, model.SCEN, model.CUTS, default=0.0, mutable=True
+)
-model.sell_lim_price = Param(
+model.sell_lim_price = pyo.Param(
model.PROD, model.TWOPLUSWEEKS, model.SCEN, model.CUTS, default=0.0, mutable=True
)
@@ -100,17 +104,17 @@ def time1_rule(model):
)
-model.Time1 = Constraint(rule=time1_rule)
+model.Time1 = pyo.Constraint(rule=time1_rule)
def balance1_rule(model, p):
return model.Make1[p] + model.inv0[p] - (model.Sell1[p] + model.Inv1[p]) == 0.0
-model.Balance1 = Constraint(model.PROD, rule=balance1_rule)
+model.Balance1 = pyo.Constraint(model.PROD, rule=balance1_rule)
# cuts are generated on-the-fly, so no rules are necessary.
-model.Cut_Defn = ConstraintList()
+model.Cut_Defn = pyo.ConstraintList()
def expected_profit_rule(model):
@@ -128,4 +132,4 @@ def expected_profit_rule(model):
)
-model.Expected_Profit = Objective(rule=expected_profit_rule, sense=maximize)
+model.Expected_Profit = pyo.Objective(rule=expected_profit_rule, sense=pyo.maximize)
diff --git a/examples/pyomo/benders/runbenders b/examples/pyomo/benders/runbenders
index 1d360ca985a..7bc4248a9fc 100755
--- a/examples/pyomo/benders/runbenders
+++ b/examples/pyomo/benders/runbenders
@@ -6,7 +6,6 @@
#
# Python imports
-from pyomo.environ import *
from pyomo.common.fileutils import import_file
from pyomo.opt.base import SolverFactory
from pyomo.opt.parallel import SolverManagerFactory
diff --git a/examples/pyomo/benders/subproblem.py b/examples/pyomo/benders/subproblem.py
index ae46dad2d41..eadafce89ab 100644
--- a/examples/pyomo/benders/subproblem.py
+++ b/examples/pyomo/benders/subproblem.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,61 +12,65 @@
### Pyomo sub-problem for AMPL Bender's example, available
### from http://www.ampl.com/NEW/LOOP2/stoch2.mod
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel(name="SubProblem")
+model = pyo.AbstractModel(name="SubProblem")
# Declare suffixes
-model.rc = Suffix(direction=Suffix.IMPORT)
-model.lrc = Suffix(direction=Suffix.IMPORT)
-model.urc = Suffix(direction=Suffix.IMPORT)
-model.dual = Suffix(direction=Suffix.IMPORT)
+model.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.lrc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.urc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
# products
-model.PROD = Set()
+model.PROD = pyo.Set()
# number of weeks
-model.T = Param(within=PositiveIntegers)
+model.T = pyo.Param(within=pyo.PositiveIntegers)
# derived set containing all valid week indices and subsets of interest.
def weeks_rule(model):
- return list(sequence(model.T()))
+ return list(pyo.sequence(model.T()))
-model.WEEKS = Set(initialize=weeks_rule, within=PositiveIntegers)
+model.WEEKS = pyo.Set(initialize=weeks_rule, within=pyo.PositiveIntegers)
def two_plus_weeks_rule(model):
- return list(sequence(2, model.T()))
+ return list(pyo.sequence(2, model.T()))
-model.TWOPLUSWEEKS = Set(initialize=two_plus_weeks_rule, within=PositiveIntegers)
+model.TWOPLUSWEEKS = pyo.Set(
+ initialize=two_plus_weeks_rule, within=pyo.PositiveIntegers
+)
def three_plus_weeks_rule(model):
- return list(sequence(3, model.T()))
+ return list(pyo.sequence(3, model.T()))
-model.THREEPLUSWEEKS = Set(initialize=three_plus_weeks_rule, within=PositiveIntegers)
+model.THREEPLUSWEEKS = pyo.Set(
+ initialize=three_plus_weeks_rule, within=pyo.PositiveIntegers
+)
# tons per hour produced
-model.rate = Param(model.PROD, within=PositiveReals)
+model.rate = pyo.Param(model.PROD, within=pyo.PositiveReals)
# hours available in week
-model.avail = Param(model.WEEKS, within=NonNegativeReals)
+model.avail = pyo.Param(model.WEEKS, within=pyo.NonNegativeReals)
# limit on tons sold in week
-model.market = Param(model.PROD, model.WEEKS, within=NonNegativeReals)
+model.market = pyo.Param(model.PROD, model.WEEKS, within=pyo.NonNegativeReals)
# cost per ton produced
-model.prodcost = Param(model.PROD, within=NonNegativeReals)
+model.prodcost = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
# carrying cost/ton of inventory
-model.invcost = Param(model.PROD, within=NonNegativeReals)
+model.invcost = pyo.Param(model.PROD, within=pyo.NonNegativeReals)
# projected revenue/ton
-model.revenue = Param(model.PROD, model.WEEKS, within=NonNegativeReals)
+model.revenue = pyo.Param(model.PROD, model.WEEKS, within=pyo.NonNegativeReals)
# scenario probability
@@ -74,16 +78,16 @@ def unit_interval_validate(model, value):
return (value >= 0.0) and (value <= 1.0)
-model.prob = Param(validate=unit_interval_validate)
+model.prob = pyo.Param(validate=unit_interval_validate)
# inventory at end of first period.
-model.inv1 = Param(model.PROD, within=NonNegativeReals, mutable=True)
+model.inv1 = pyo.Param(model.PROD, within=pyo.NonNegativeReals, mutable=True)
# tons produced
-model.Make = Var(model.PROD, model.TWOPLUSWEEKS, domain=NonNegativeReals)
+model.Make = pyo.Var(model.PROD, model.TWOPLUSWEEKS, domain=pyo.NonNegativeReals)
# tons inventoried
-model.Inv = Var(model.PROD, model.TWOPLUSWEEKS, domain=NonNegativeReals)
+model.Inv = pyo.Var(model.PROD, model.TWOPLUSWEEKS, domain=pyo.NonNegativeReals)
# tons sold
@@ -91,8 +95,8 @@ def sell_bounds(model, p, t):
return (0, model.market[p, t])
-model.Sell = Var(
- model.PROD, model.TWOPLUSWEEKS, within=NonNegativeReals, bounds=sell_bounds
+model.Sell = pyo.Var(
+ model.PROD, model.TWOPLUSWEEKS, within=pyo.NonNegativeReals, bounds=sell_bounds
)
@@ -104,7 +108,7 @@ def time_rule(model, t):
)
-model.Time = Constraint(model.TWOPLUSWEEKS, rule=time_rule)
+model.Time = pyo.Constraint(model.TWOPLUSWEEKS, rule=time_rule)
def balance2_rule(model, p):
@@ -113,7 +117,7 @@ def balance2_rule(model, p):
) == 0.0
-model.Balance2 = Constraint(model.PROD, rule=balance2_rule)
+model.Balance2 = pyo.Constraint(model.PROD, rule=balance2_rule)
def balance_rule(model, p, t):
@@ -122,7 +126,7 @@ def balance_rule(model, p, t):
) == 0.0
-model.Balance = Constraint(model.PROD, model.THREEPLUSWEEKS, rule=balance_rule)
+model.Balance = pyo.Constraint(model.PROD, model.THREEPLUSWEEKS, rule=balance_rule)
# the manual distribution of model.prob is ugly, but at the moment necessary; Pyomo
@@ -139,4 +143,4 @@ def exp_stage2_profit_rule(model):
)
-model.Exp_Stage2_Profit = Objective(rule=exp_stage2_profit_rule, sense=maximize)
+model.Exp_Stage2_Profit = pyo.Objective(rule=exp_stage2_profit_rule, sense=pyo.maximize)
diff --git a/examples/pyomo/callbacks/sc.py b/examples/pyomo/callbacks/sc.py
index 0882815c6b7..8cbf3336fc9 100644
--- a/examples/pyomo/callbacks/sc.py
+++ b/examples/pyomo/callbacks/sc.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
from pyomo.common.collections import Bunch
-from pyomo.core import *
+import pyomo.environ as pyo
import math
import random
@@ -138,11 +138,11 @@ def S_rule(model):
#
# CREATE MODEL
#
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
#
# (i,j) in S if element i in set j
#
- model.S = Set(dimen=2, initialize=S_rule)
+ model.S = pyo.Set(dimen=2, initialize=S_rule)
#
# Dynamically create the I and J index sets, since
@@ -151,28 +151,28 @@ def S_rule(model):
def I_rule(model):
return set((i for (i, j) in model.S))
- model.I = Set(initialize=I_rule)
+ model.I = pyo.Set(initialize=I_rule)
def J_rule(model):
return set((j for (i, j) in model.S))
- model.J = Set(initialize=J_rule)
+ model.J = pyo.Set(initialize=J_rule)
#
# Weights
#
- model.w = Param(model.J, within=NonNegativeReals, initialize=1.0)
+ model.w = pyo.Param(model.J, within=pyo.NonNegativeReals, initialize=1.0)
#
# Set selection binary variables
#
- model.x = Var(model.J, within=Binary)
+ model.x = pyo.Var(model.J, within=pyo.Binary)
#
# Objective
#
def cost_rule(model):
- return sum_product(model.w, model.x)
+ return pyo.sum_product(model.w, model.x)
- model.cost = Objective(rule=cost_rule)
+ model.cost = pyo.Objective(rule=cost_rule)
#
# Constraint
@@ -189,7 +189,7 @@ def cover_rule(model, i):
# return Constraint.Skip
return expr >= 1
- model.cover = Constraint(model.I, rule=cover_rule)
+ model.cover = pyo.Constraint(model.I, rule=cover_rule)
#
print_model_stats(model_options, model)
diff --git a/examples/pyomo/callbacks/sc_callback.py b/examples/pyomo/callbacks/sc_callback.py
index cacc438b380..f60f1537655 100644
--- a/examples/pyomo/callbacks/sc_callback.py
+++ b/examples/pyomo/callbacks/sc_callback.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,8 +10,7 @@
# ___________________________________________________________________________
-from pyomo.core import *
-from sc import *
+from sc import pyomo_callback
@pyomo_callback('solve-callback')
diff --git a/examples/pyomo/callbacks/sc_script.py b/examples/pyomo/callbacks/sc_script.py
index d3044e4d667..143e5665157 100644
--- a/examples/pyomo/callbacks/sc_script.py
+++ b/examples/pyomo/callbacks/sc_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,9 +10,7 @@
# ___________________________________________________________________________
-from pyomo.opt import *
-from pyomo.core import *
-
+import pyomo.environ as pyo
import sc
model = sc.pyomo_create_model()
@@ -32,7 +30,7 @@ def node_callback(solver, model):
instance = model.create()
-opt = SolverFactory('_cplex_direct')
+opt = pyo.SolverFactory('_cplex_direct')
opt.set_callback('cut-callback', cut_callback)
opt.set_callback('node-callback', node_callback)
opt.set_callback('solve-callback', solve_callback)
diff --git a/examples/pyomo/callbacks/scalability/run.py b/examples/pyomo/callbacks/scalability/run.py
index cf95076fcc3..23633357cbb 100644
--- a/examples/pyomo/callbacks/scalability/run.py
+++ b/examples/pyomo/callbacks/scalability/run.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomo/callbacks/tsp.py b/examples/pyomo/callbacks/tsp.py
index 8526a540b66..0299f84f589 100644
--- a/examples/pyomo/callbacks/tsp.py
+++ b/examples/pyomo/callbacks/tsp.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,11 +14,12 @@
#
import re
import math
-from pyomo.core import *
+import pyomo.environ as pyo
+from sc import pyomo_callback
def pyomo_create_model(options=None, model_options=None):
- model = ConcreteModel()
+ model = pyo.ConcreteModel()
#
# Read from the 'points' file
#
@@ -38,22 +39,22 @@ def pyomo_create_model(options=None, model_options=None):
#
#
# Number of points
- model.N = Param(within=PositiveIntegers, initialize=N)
+ model.N = pyo.Param(within=pyo.PositiveIntegers, initialize=N)
#
# Index set for points
- model.POINTS = RangeSet(1, model.N)
+ model.POINTS = pyo.RangeSet(1, model.N)
#
# (x,y) location
def x_rule(model, i):
return x[i - 1]
- model.x = Param(model.POINTS)
+ model.x = pyo.Param(model.POINTS)
def y_rule(model, i):
return y[i - 1]
- model.y = Param(model.POINTS)
+ model.y = pyo.Param(model.POINTS)
#
# Derived data
@@ -63,7 +64,7 @@ def y_rule(model, i):
def LINKS_rule(model):
return set([(i, j) for i in model.POINTS for j in model.POINTS if i < j])
- model.LINKS = Set(dimen=2)
+ model.LINKS = pyo.Set(dimen=2)
#
# Distance between points
@@ -72,17 +73,17 @@ def d_rule(model, i, j):
(model.x[i] - model.x[j]) ** 2 + (model.y[i] - model.y[j]) ** 2
)
- model.d = Param(model.LINKS)
+ model.d = pyo.Param(model.LINKS)
#
# Variables
#
- model.Z = Var(model.LINKS, within=Binary)
+ model.Z = pyo.Var(model.LINKS, within=pyo.Binary)
#
# Constraints
#
#
# Minimize tour length
- model.tour_length = Objective(expr=sum_product(model.d, model.Z))
+ model.tour_length = pyo.Objective(expr=pyo.sum_product(model.d, model.Z))
#
# Each vertex has degree 2
@@ -93,17 +94,17 @@ def Degrees_rule(model, i):
== 2
)
- model.Degrees = Constraint(model.POINTS)
+ model.Degrees = pyo.Constraint(model.POINTS)
#
# NOTE: subtour constraints are added dynamically
#
## Number of subtour elimination cuts
- # model.M = Param(within=PositiveIntegers)
+ # model.M = pyo.Param(within=pyo.PositiveIntegers)
## Number of subtour elimination cuts appended
- # model.numcut = Param(within=NonNegativeIntegers)
- # model.CUTINDICES = RangeSet(1,model.M)
- # model.CUTSET = Set(model.CUTINDICES)
+ # model.numcut = pyo.Param(within=pyo.NonNegativeIntegers)
+ # model.CUTINDICES = pyo.RangeSet(1,model.M)
+ # model.CUTSET = pyo.Set(model.CUTINDICES)
return model
diff --git a/examples/pyomo/columngeneration/cutting_stock.py b/examples/pyomo/columngeneration/cutting_stock.py
index 2d9399c7db4..f6987c2f689 100644
--- a/examples/pyomo/columngeneration/cutting_stock.py
+++ b/examples/pyomo/columngeneration/cutting_stock.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -16,7 +16,7 @@
Bradley, S.P., A.C. Hax, and T.L. Magnanti. 1977. Applied Mathematical Programming,
Addison-Wesley, Reading, MA. Available: http://web.mit.edu/15.053/www/AMP.htm.
-Data from https://en.wikipedia.org/wiki/Cutting_stock_problem
+Data from https://en.wikipedia.org/wiki/Cutting_stock_problem
'''
import pyomo.environ as pyo
diff --git a/examples/pyomo/concrete/Whiskas.py b/examples/pyomo/concrete/Whiskas.py
index 3d3c19e94ac..18f3c47639e 100644
--- a/examples/pyomo/concrete/Whiskas.py
+++ b/examples/pyomo/concrete/Whiskas.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
# Creates a list of the Ingredients
Ingredients = ['CHICKEN', 'BEEF', 'MUTTON', 'RICE', 'WHEAT', 'GEL']
@@ -65,33 +65,33 @@
'GEL': 0.000,
}
-model = ConcreteModel(name="The Whiskas Problem")
+model = pyo.ConcreteModel(name="The Whiskas Problem")
-model.ingredient_vars = Var(
+model.ingredient_vars = pyo.Var(
Ingredients, bounds=(0, None), doc="The amount of each ingredient that is used"
)
-model.obj = Objective(
+model.obj = pyo.Objective(
expr=sum(costs[i] * model.ingredient_vars[i] for i in Ingredients),
doc="Total Cost of Ingredients per can",
)
-model.c0 = Constraint(
+model.c0 = pyo.Constraint(
expr=sum(model.ingredient_vars[i] for i in Ingredients) == 100, doc="PercentagesSum"
)
-model.c1 = Constraint(
+model.c1 = pyo.Constraint(
expr=sum(proteinPercent[i] * model.ingredient_vars[i] for i in Ingredients) >= 8.0,
doc="ProteinRequirement",
)
-model.c2 = Constraint(
+model.c2 = pyo.Constraint(
expr=sum(fatPercent[i] * model.ingredient_vars[i] for i in Ingredients) >= 6.0,
doc="FatRequirement",
)
-model.c3 = Constraint(
+model.c3 = pyo.Constraint(
expr=sum(fibrePercent[i] * model.ingredient_vars[i] for i in Ingredients) <= 2.0,
doc="FibreRequirement",
)
-model.c4 = Constraint(
+model.c4 = pyo.Constraint(
expr=sum(saltPercent[i] * model.ingredient_vars[i] for i in Ingredients) <= 0.4,
doc="SaltRequirement",
)
diff --git a/examples/pyomo/concrete/knapsack-abstract.py b/examples/pyomo/concrete/knapsack-abstract.py
index 9766d902722..791173fc455 100644
--- a/examples/pyomo/concrete/knapsack-abstract.py
+++ b/examples/pyomo/concrete/knapsack-abstract.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,33 +13,33 @@
# Abstract Knapsack Problem
#
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.ITEMS = Set()
+model.ITEMS = pyo.Set()
-model.v = Param(model.ITEMS, within=PositiveReals)
+model.v = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.w = Param(model.ITEMS, within=PositiveReals)
+model.w = pyo.Param(model.ITEMS, within=pyo.PositiveReals)
-model.limit = Param(within=PositiveReals)
+model.limit = pyo.Param(within=pyo.PositiveReals)
-model.x = Var(model.ITEMS, within=Binary)
+model.x = pyo.Var(model.ITEMS, within=pyo.Binary)
def value_rule(model):
return sum(model.v[i] * model.x[i] for i in model.ITEMS)
-model.value = Objective(sense=maximize, rule=value_rule)
+model.value = pyo.Objective(sense=pyo.maximize, rule=value_rule)
def weight_rule(model):
return sum(model.w[i] * model.x[i] for i in model.ITEMS) <= model.limit
-model.weight = Constraint(rule=weight_rule)
+model.weight = pyo.Constraint(rule=weight_rule)
if __name__ == '__main__':
diff --git a/examples/pyomo/concrete/knapsack-concrete.py b/examples/pyomo/concrete/knapsack-concrete.py
index 8966d0b8498..3efe4bd0dec 100644
--- a/examples/pyomo/concrete/knapsack-concrete.py
+++ b/examples/pyomo/concrete/knapsack-concrete.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,19 +13,19 @@
# Knapsack Problem
#
-from pyomo.environ import *
+import pyomo.environ as pyo
v = {'hammer': 8, 'wrench': 3, 'screwdriver': 6, 'towel': 11}
w = {'hammer': 5, 'wrench': 7, 'screwdriver': 4, 'towel': 3}
limit = 14
-M = ConcreteModel()
+M = pyo.ConcreteModel()
-M.ITEMS = Set(initialize=v.keys())
+M.ITEMS = pyo.Set(initialize=v.keys())
-M.x = Var(M.ITEMS, within=Binary)
+M.x = pyo.Var(M.ITEMS, within=pyo.Binary)
-M.value = Objective(expr=sum(v[i] * M.x[i] for i in M.ITEMS), sense=maximize)
+M.value = pyo.Objective(expr=sum(v[i] * M.x[i] for i in M.ITEMS), sense=pyo.maximize)
-M.weight = Constraint(expr=sum(w[i] * M.x[i] for i in M.ITEMS) <= limit)
+M.weight = pyo.Constraint(expr=sum(w[i] * M.x[i] for i in M.ITEMS) <= limit)
diff --git a/examples/pyomo/concrete/rosen.py b/examples/pyomo/concrete/rosen.py
index ae51ae50ac0..c3596e8be0d 100644
--- a/examples/pyomo/concrete/rosen.py
+++ b/examples/pyomo/concrete/rosen.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,11 +10,11 @@
# ___________________________________________________________________________
# rosen.py
-from pyomo.environ import *
+import pyomo.environ as pyo
-M = ConcreteModel()
-M.x = Var()
-M.y = Var()
-M.o = Objective(expr=(M.x - 1) ** 2 + 100 * (M.y - M.x**2) ** 2)
+M = pyo.ConcreteModel()
+M.x = pyo.Var()
+M.y = pyo.Var()
+M.o = pyo.Objective(expr=(M.x - 1) ** 2 + 100 * (M.y - M.x**2) ** 2)
model = M
diff --git a/examples/pyomo/concrete/sodacan.py b/examples/pyomo/concrete/sodacan.py
index 5429b27a9d5..d3e9623f20b 100644
--- a/examples/pyomo/concrete/sodacan.py
+++ b/examples/pyomo/concrete/sodacan.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,11 +10,11 @@
# ___________________________________________________________________________
# sodacan.py
-from pyomo.environ import *
+import pyomo.environ as pyo
from math import pi
-M = ConcreteModel()
-M.r = Var(bounds=(0, None))
-M.h = Var(bounds=(0, None))
-M.o = Objective(expr=2 * pi * M.r * (M.r + M.h))
-M.c = Constraint(expr=pi * M.h * M.r**2 == 355)
+M = pyo.ConcreteModel()
+M.r = pyo.Var(bounds=(0, None))
+M.h = pyo.Var(bounds=(0, None))
+M.o = pyo.Objective(expr=2 * pi * M.r * (M.r + M.h))
+M.c = pyo.Constraint(expr=pi * M.h * M.r**2 == 355)
diff --git a/examples/pyomo/concrete/sodacan_fig.py b/examples/pyomo/concrete/sodacan_fig.py
index b263eaf558d..e216aa31733 100644
--- a/examples/pyomo/concrete/sodacan_fig.py
+++ b/examples/pyomo/concrete/sodacan_fig.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomo/concrete/sp.py b/examples/pyomo/concrete/sp.py
index e82a4bca0a9..91e42ed444d 100644
--- a/examples/pyomo/concrete/sp.py
+++ b/examples/pyomo/concrete/sp.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,27 +10,27 @@
# ___________________________________________________________________________
# sp.py
-from pyomo.environ import *
-from sp_data import * # define c, b, h, and d
+import pyomo.environ as pyo
+from sp_data import c, b, h, d # define c, b, h, and d
scenarios = range(1, 6)
-M = ConcreteModel()
-M.x = Var(within=NonNegativeReals)
+M = pyo.ConcreteModel()
+M.x = pyo.Var(within=pyo.NonNegativeReals)
def b_rule(B, i):
- B.y = Var()
- B.l = Constraint(expr=B.y >= (c - b) * M.x + b * d[i])
- B.u = Constraint(expr=B.y >= (c + h) * M.x + h * d[i])
+ B.y = pyo.Var()
+ B.l = pyo.Constraint(expr=B.y >= (c - b) * M.x + b * d[i])
+ B.u = pyo.Constraint(expr=B.y >= (c + h) * M.x + h * d[i])
return B
-M.B = Block(scenarios, rule=b_rule)
+M.B = pyo.Block(scenarios, rule=b_rule)
def o_rule(M):
return sum(M.B[i].y for i in scenarios) / 5.0
-M.o = Objective(rule=o_rule)
+M.o = pyo.Objective(rule=o_rule)
diff --git a/examples/pyomo/concrete/sp_data.py b/examples/pyomo/concrete/sp_data.py
index 4453a10cead..11356ed7e42 100644
--- a/examples/pyomo/concrete/sp_data.py
+++ b/examples/pyomo/concrete/sp_data.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomo/connectors/network_flow.py b/examples/pyomo/connectors/network_flow.py
index d5587fdf4c8..afa327cdfa3 100644
--- a/examples/pyomo/connectors/network_flow.py
+++ b/examples/pyomo/connectors/network_flow.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,63 +10,67 @@
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
def pipe_rule(pipe, i):
m = pipe.model()
- pipe.flow = Var()
- pipe.pIn = Var(within=NonNegativeReals)
- pipe.pOut = Var(within=NonNegativeReals)
- pipe.pDrop = Constraint(
+ pipe.flow = pyo.Var()
+ pipe.pIn = pyo.Var(within=pyo.NonNegativeReals)
+ pipe.pOut = pyo.Var(within=pyo.NonNegativeReals)
+ pipe.pDrop = pyo.Constraint(
expr=pipe.pIn - pipe.pOut == m.friction * m.pipe_length[i] * pipe.flow
)
- pipe.IN = Connector()
+ pipe.IN = pyo.Connector()
pipe.IN.add(-pipe.flow, "flow")
pipe.IN.add(pipe.pIn, "pressure")
- pipe.OUT = Connector()
+ pipe.OUT = pyo.Connector()
pipe.OUT.add(pipe.flow)
pipe.OUT.add(pipe.pOut, "pressure")
def node_rule(node, i):
def _mass_balance(node, flows):
- return node.model().demands[i] == sum_product(flows)
+ return node.model().demands[i] == pyo.sum_product(flows)
- node.flow = VarList()
- node.pressure = Var(within=NonNegativeReals)
- node.port = Connector()
+ node.flow = pyo.VarList()
+ node.pressure = pyo.Var(within=pyo.NonNegativeReals)
+ node.port = pyo.Connector()
# node.port.add(node.flow,
- # aggregate=lambda n,v: n.model().demands[id] == sum_product(v))
+ # aggregate=lambda n,v: n.model().demands[id] == pyo.sum_product(v))
node.port.add(node.flow, aggregate=_mass_balance)
node.port.add(node.pressure)
def _src_rule(model, pipe):
- return model.nodes[value(model.pipe_links[pipe, 0])].port == model.pipes[pipe].IN
+ return (
+ model.nodes[pyo.value(model.pipe_links[pipe, 0])].port == model.pipes[pipe].IN
+ )
def _sink_rule(model, pipe):
- return model.nodes[value(model.pipe_links[pipe, 1])].port == model.pipes[pipe].OUT
+ return (
+ model.nodes[pyo.value(model.pipe_links[pipe, 1])].port == model.pipes[pipe].OUT
+ )
-model = AbstractModel()
-model.PIPES = Set()
-model.NODES = Set()
+model = pyo.AbstractModel()
+model.PIPES = pyo.Set()
+model.NODES = pyo.Set()
-model.friction = Param(within=NonNegativeReals)
-model.pipe_length = Param(model.PIPES, within=NonNegativeReals)
-model.pipe_links = Param(model.PIPES, [0, 1])
-model.demands = Param(model.NODES, within=Reals, default=0)
+model.friction = pyo.Param(within=pyo.NonNegativeReals)
+model.pipe_length = pyo.Param(model.PIPES, within=pyo.NonNegativeReals)
+model.pipe_links = pyo.Param(model.PIPES, [0, 1])
+model.demands = pyo.Param(model.NODES, within=pyo.Reals, default=0)
-model.pipes = Block(model.PIPES, rule=pipe_rule)
-model.nodes = Block(model.NODES, rule=node_rule)
+model.pipes = pyo.Block(model.PIPES, rule=pipe_rule)
+model.nodes = pyo.Block(model.NODES, rule=node_rule)
# Connect the network
-model.network_src = Constraint(model.PIPES, rule=_src_rule)
-model.network_sink = Constraint(model.PIPES, rule=_sink_rule)
+model.network_src = pyo.Constraint(model.PIPES, rule=_src_rule)
+model.network_sink = pyo.Constraint(model.PIPES, rule=_sink_rule)
# Solve so the minimum pressure in the network is 0
@@ -74,4 +78,4 @@ def _obj(model):
return sum(model.nodes[n].pressure for n in model.NODES)
-model.obj = Objective(rule=_obj)
+model.obj = pyo.Objective(rule=_obj)
diff --git a/examples/pyomo/connectors/network_flow_proposed.py b/examples/pyomo/connectors/network_flow_proposed.py
index f234f2decf4..8844ded504a 100644
--- a/examples/pyomo/connectors/network_flow_proposed.py
+++ b/examples/pyomo/connectors/network_flow_proposed.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,64 +10,68 @@
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
def pipe_rule(model, pipe, id):
- pipe.length = Param(within=NonNegativeReals)
+ pipe.length = pyo.Param(within=pyo.NonNegativeReals)
- pipe.flow = Var()
- pipe.pIn = Var(within=NonNegativeReals)
- pipe.pOut = Var(within=NonNegativeReals)
- pipe.pDrop = Constraint(
+ pipe.flow = pyo.Var()
+ pipe.pIn = pyo.Var(within=pyo.NonNegativeReals)
+ pipe.pOut = pyo.Var(within=pyo.NonNegativeReals)
+ pipe.pDrop = pyo.Constraint(
expr=pipe.pIn - pipe.pOut == model.friction * model.pipe_length[id] * pipe.flow
)
- pipe.IN = Connector()
+ pipe.IN = pyo.Connector()
pipe.IN.add(-1 * pipe.flow, "flow")
pipe.IN.add(pipe.pIn, "pressure")
- pipe.OUT = Connector()
+ pipe.OUT = pyo.Connector()
pipe.OUT.add(pipe.flow)
pipe.OUT.add(pipe.pOut, "pressure")
def node_rule(model, node, id):
def _mass_balance(model, node, flows):
- return node.demand == sum_product(flows)
+ return node.demand == pyo.sum_product(flows)
- node.demand = Param(within=Reals, default=0)
+ node.demand = pyo.Param(within=pyo.Reals, default=0)
- node.flow = VarList()
- node.pressure = Var(within=NonNegativeReals)
- node.port = Connector()
+ node.flow = pyo.VarList()
+ node.pressure = pyo.Var(within=pyo.NonNegativeReals)
+ node.port = pyo.Connector()
# node.port.add( node.flow,
- # aggregate=lambda m,n,v: m.demands[id] == sum_product(v) )
+ # aggregate=lambda m,n,v: m.demands[id] == pyo.sum_product(v) )
node.port.add(node.flow, aggregate=_mass_balance)
node.port.add(node.pressure)
def _src_rule(model, pipe):
- return model.nodes[value(model.pipe_links[pipe, 0])].port == model.pipes[pipe].IN
+ return (
+ model.nodes[pyo.value(model.pipe_links[pipe, 0])].port == model.pipes[pipe].IN
+ )
def _sink_rule(model, pipe):
- return model.nodes[value(model.pipe_links[pipe, 1])].port == model.pipes[pipe].OUT
+ return (
+ model.nodes[pyo.value(model.pipe_links[pipe, 1])].port == model.pipes[pipe].OUT
+ )
-model = AbstractModel()
-model.PIPES = Set()
-model.NODES = Set()
+model = pyo.AbstractModel()
+model.PIPES = pyo.Set()
+model.NODES = pyo.Set()
-model.friction = Param(within=NonNegativeReals)
-model.pipe_links = Param(model.PIPES, RangeSet(2))
+model.friction = pyo.Param(within=pyo.NonNegativeReals)
+model.pipe_links = pyo.Param(model.PIPES, pyo.RangeSet(2))
-model.pipes = Block(model.PIPES, rule=pipe_rule)
-model.nodes = Block(model.NODES, rule=node_rule)
+model.pipes = pyo.Block(model.PIPES, rule=pipe_rule)
+model.nodes = pyo.Block(model.NODES, rule=node_rule)
# Connect the network
-model.network_src = Constraint(model.PIPES, rule=_src_rule)
-model.network_sink = Constraint(model.PIPES, rule=_sink_rule)
+model.network_src = pyo.Constraint(model.PIPES, rule=_src_rule)
+model.network_sink = pyo.Constraint(model.PIPES, rule=_sink_rule)
# Solve so the minimum pressure in the network is 0
@@ -75,4 +79,4 @@ def _obj(model):
return sum(model.nodes[n].pressure for n in model.NODES)
-model.obj = Objective(rule=_obj)
+model.obj = pyo.Objective(rule=_obj)
diff --git a/examples/pyomo/core/block1.py b/examples/pyomo/core/block1.py
index 161fc2ca2f7..cf8386e6a6e 100644
--- a/examples/pyomo/core/block1.py
+++ b/examples/pyomo/core/block1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,12 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-model = ConcreteModel()
-model.x = Var()
+model = pyo.ConcreteModel()
+model.x = pyo.Var()
-model.b = Block()
-model.b.x = Var()
+model.b = pyo.Block()
+model.b.x = pyo.Var()
-model.o = Objective(expr=(model.x - 1.0) ** 2 + (model.b.x - 2.0) ** 2)
+model.o = pyo.Objective(expr=(model.x - 1.0) ** 2 + (model.b.x - 2.0) ** 2)
diff --git a/examples/pyomo/core/integrality1.py b/examples/pyomo/core/integrality1.py
index 0ab3a433dac..6fa103195a7 100644
--- a/examples/pyomo/core/integrality1.py
+++ b/examples/pyomo/core/integrality1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,15 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-M = ConcreteModel()
-M.x1 = Var(within=Boolean)
-M.x2 = Var(within=Boolean)
-M.x3 = Var(within=Boolean)
+M = pyo.ConcreteModel()
+M.x1 = pyo.Var(within=pyo.Boolean)
+M.x2 = pyo.Var(within=pyo.Boolean)
+M.x3 = pyo.Var(within=pyo.Boolean)
-M.o = Objective(expr=M.x1 + M.x2 + M.x3)
-M.c1 = Constraint(expr=4 * M.x1 + M.x2 >= 1)
-M.c2 = Constraint(expr=M.x2 + 4 * M.x3 >= 1)
+M.o = pyo.Objective(expr=M.x1 + M.x2 + M.x3)
+M.c1 = pyo.Constraint(expr=4 * M.x1 + M.x2 >= 1)
+M.c2 = pyo.Constraint(expr=M.x2 + 4 * M.x3 >= 1)
model = M
diff --git a/examples/pyomo/core/integrality2.py b/examples/pyomo/core/integrality2.py
index 6461d36f923..b3edadc7925 100644
--- a/examples/pyomo/core/integrality2.py
+++ b/examples/pyomo/core/integrality2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,13 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
-M = ConcreteModel()
-M.x = Var([1, 2, 3], within=Boolean)
+M = pyo.ConcreteModel()
+M.x = pyo.Var([1, 2, 3], within=pyo.Boolean)
-M.o = Objective(expr=sum_product(M.x))
-M.c1 = Constraint(expr=4 * M.x[1] + M.x[2] >= 1)
-M.c2 = Constraint(expr=M.x[2] + 4 * M.x[3] >= 1)
+M.o = pyo.Objective(expr=pyo.sum_product(M.x))
+M.c1 = pyo.Constraint(expr=4 * M.x[1] + M.x[2] >= 1)
+M.c2 = pyo.Constraint(expr=M.x[2] + 4 * M.x[3] >= 1)
model = M
diff --git a/examples/pyomo/core/simple.py b/examples/pyomo/core/simple.py
index 6976f3d25ad..1c8de769d23 100644
--- a/examples/pyomo/core/simple.py
+++ b/examples/pyomo/core/simple.py
@@ -1,22 +1,23 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________
+
# simple.py
-from pyomo.environ import *
+import pyomo.environ as pyo
-M = ConcreteModel()
-M.x1 = Var()
-M.x2 = Var(bounds=(-1, 1))
-M.x3 = Var(bounds=(1, 2))
-M.o = Objective(
- expr=M.x1**2 + (M.x2 * M.x3) ** 4 + M.x1 * M.x3 + M.x2 * sin(M.x1 + M.x3) + M.x2
+M = pyo.ConcreteModel()
+M.x1 = pyo.Var()
+M.x2 = pyo.Var(bounds=(-1, 1))
+M.x3 = pyo.Var(bounds=(1, 2))
+M.o = pyo.Objective(
+ expr=M.x1**2 + (M.x2 * M.x3) ** 4 + M.x1 * M.x3 + M.x2 * pyo.sin(M.x1 + M.x3) + M.x2
)
model = M
diff --git a/examples/pyomo/core/t1.py b/examples/pyomo/core/t1.py
index 5d5416985a9..eaa3fbef242 100644
--- a/examples/pyomo/core/t1.py
+++ b/examples/pyomo/core/t1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,19 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def pyomo_create_model(options, model_options):
- model = ConcreteModel()
- model.x1 = Var(within=NonNegativeReals)
- model.x2 = Var(within=NonNegativeReals)
- model.x3 = Var(within=NonNegativeReals)
+ model = pyo.ConcreteModel()
+ model.x1 = pyo.Var(within=pyo.NonNegativeReals)
+ model.x2 = pyo.Var(within=pyo.NonNegativeReals)
+ model.x3 = pyo.Var(within=pyo.NonNegativeReals)
- model.o = Objective(expr=6 * model.x1 + 4 * model.x2 + 2 * model.x3, sense=minimize)
+ model.o = pyo.Objective(
+ expr=6 * model.x1 + 4 * model.x2 + 2 * model.x3, sense=pyo.minimize
+ )
- model.c1 = Constraint(expr=4 * model.x1 + 2 * model.x2 + model.x3 >= 5)
- model.c2 = Constraint(expr=model.x1 + model.x2 >= 3)
- model.c3 = Constraint(expr=model.x2 + model.x3 >= 4)
+ model.c1 = pyo.Constraint(expr=4 * model.x1 + 2 * model.x2 + model.x3 >= 5)
+ model.c2 = pyo.Constraint(expr=model.x1 + model.x2 >= 3)
+ model.c3 = pyo.Constraint(expr=model.x2 + model.x3 >= 4)
return model
diff --git a/examples/pyomo/core/t2.py b/examples/pyomo/core/t2.py
index 4d3f1934cbe..0117adb860d 100644
--- a/examples/pyomo/core/t2.py
+++ b/examples/pyomo/core/t2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,19 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
def pyomo_create_model(options, model_options):
- model = ConcreteModel()
- model.x1 = Var(within=NonNegativeReals)
- model.x2 = Var(within=NonPositiveReals)
- model.x3 = Var(within=Reals)
+ model = pyo.ConcreteModel()
+ model.x1 = pyo.Var(within=pyo.NonNegativeReals)
+ model.x2 = pyo.Var(within=pyo.NonPositiveReals)
+ model.x3 = pyo.Var(within=pyo.Reals)
- model.o = Objective(expr=model.x1 + 2 * model.x2 + 3 * model.x3, sense=maximize)
+ model.o = pyo.Objective(
+ expr=model.x1 + 2 * model.x2 + 3 * model.x3, sense=pyo.maximize
+ )
- model.c1 = Constraint(expr=-model.x1 + 3 * model.x2 == 5)
- model.c2 = Constraint(expr=2 * model.x1 - model.x2 + 3 * model.x3 >= 6)
- model.c3 = Constraint(expr=model.x3 <= 4)
+ model.c1 = pyo.Constraint(expr=-model.x1 + 3 * model.x2 == 5)
+ model.c2 = pyo.Constraint(expr=2 * model.x1 - model.x2 + 3 * model.x3 >= 6)
+ model.c3 = pyo.Constraint(expr=model.x3 <= 4)
return model
diff --git a/examples/pyomo/core/t5.py b/examples/pyomo/core/t5.py
index 6b9d94e0ff1..aa973b5401e 100644
--- a/examples/pyomo/core/t5.py
+++ b/examples/pyomo/core/t5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,18 +13,18 @@
# A duality example adapted from
# http://www.stanford.edu/~ashishg/msande111/notes/chapter4.pdf
#
-from pyomo.environ import *
+import pyomo.environ as pyo
def pyomo_create_model(options, model_options):
- model = ConcreteModel()
- model.x1 = Var(within=NonNegativeReals)
- model.x2 = Var(within=NonNegativeReals)
- model.o = Objective(expr=3 * model.x1 + 2.5 * model.x2, sense=maximize)
+ model = pyo.ConcreteModel()
+ model.x1 = pyo.Var(within=pyo.NonNegativeReals)
+ model.x2 = pyo.Var(within=pyo.NonNegativeReals)
+ model.o = pyo.Objective(expr=3 * model.x1 + 2.5 * model.x2, sense=pyo.maximize)
- model.c1 = Constraint(expr=4.44 * model.x1 <= 100)
- model.c2 = Constraint(expr=6.67 * model.x2 <= 100)
- model.c3 = Constraint(expr=4 * model.x1 + 2.86 * model.x2 <= 100)
- model.c4 = Constraint(expr=3 * model.x1 + 6 * model.x2 <= 100)
+ model.c1 = pyo.Constraint(expr=4.44 * model.x1 <= 100)
+ model.c2 = pyo.Constraint(expr=6.67 * model.x2 <= 100)
+ model.c3 = pyo.Constraint(expr=4 * model.x1 + 2.86 * model.x2 <= 100)
+ model.c4 = pyo.Constraint(expr=3 * model.x1 + 6 * model.x2 <= 100)
return model
diff --git a/examples/pyomo/diet/diet-sqlite.py b/examples/pyomo/diet/diet-sqlite.py
index dccd3c338d0..4aa252d7db6 100644
--- a/examples/pyomo/diet/diet-sqlite.py
+++ b/examples/pyomo/diet/diet-sqlite.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomo/diet/diet1.py b/examples/pyomo/diet/diet1.py
index 217f80b9c25..dece6c38eb5 100644
--- a/examples/pyomo/diet/diet1.py
+++ b/examples/pyomo/diet/diet1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
infinity = float('inf')
@@ -20,13 +20,13 @@
# Model
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.FOOD = Set()
+model.FOOD = pyo.Set()
-model.cost = Param(model.FOOD, within=PositiveReals)
+model.cost = pyo.Param(model.FOOD, within=pyo.PositiveReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals, default=0.0)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals, default=0.0)
MAX_FOOD_SUPPLY = 20.0 # McDonald's doesn't stock infinite food
@@ -35,13 +35,13 @@ def f_max_validate(model, value, j):
return model.f_max[j] > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_validate, default=MAX_FOOD_SUPPLY)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_validate, default=MAX_FOOD_SUPPLY)
# Unneeded vars - they're in the .dat file, so we list them here
-model.NUTR = Set()
-model.n_min = Param(model.NUTR, within=NonNegativeReals, default=0.0)
-model.n_max = Param(model.NUTR, default=infinity)
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.NUTR = pyo.Set()
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals, default=0.0)
+model.n_max = pyo.Param(model.NUTR, default=infinity)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
# --------------------------------------------------------
@@ -50,7 +50,7 @@ def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds, within=NonNegativeIntegers)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds, within=pyo.NonNegativeIntegers)
# --------------------------------------------------------
@@ -59,7 +59,7 @@ def Total_Cost_rule(model):
return sum(model.cost[j] * model.Buy[j] for j in model.FOOD)
-model.Total_Cost = Objective(rule=Total_Cost_rule, sense=minimize)
+model.Total_Cost = pyo.Objective(rule=Total_Cost_rule, sense=pyo.minimize)
# --------------------------------------------------------
@@ -75,7 +75,7 @@ def Entree_rule(model):
return sum(model.Buy[e] for e in entrees) >= 1
-model.Entree = Constraint(rule=Entree_rule)
+model.Entree = pyo.Constraint(rule=Entree_rule)
def Side_rule(model):
@@ -83,7 +83,7 @@ def Side_rule(model):
return sum(model.Buy[s] for s in sides) >= 1
-model.Side = Constraint(rule=Side_rule)
+model.Side = pyo.Constraint(rule=Side_rule)
def Drink_rule(model):
@@ -91,4 +91,4 @@ def Drink_rule(model):
return sum(model.Buy[d] for d in drinks) >= 1
-model.Drink = Constraint(rule=Drink_rule)
+model.Drink = pyo.Constraint(rule=Drink_rule)
diff --git a/examples/pyomo/diet/diet2.py b/examples/pyomo/diet/diet2.py
index 291261b0901..383ddebc857 100644
--- a/examples/pyomo/diet/diet2.py
+++ b/examples/pyomo/diet/diet2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
infinity = float('inf')
@@ -20,32 +20,32 @@
# Model
#
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.NUTR = Set()
-model.FOOD = Set()
+model.NUTR = pyo.Set()
+model.FOOD = pyo.Set()
-model.cost = Param(model.FOOD, within=PositiveReals)
+model.cost = pyo.Param(model.FOOD, within=pyo.PositiveReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals, default=0.0)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals, default=0.0)
def f_max_validate(model, value, j):
return model.f_max[j] > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_validate, default=infinity)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_validate, default=infinity)
-model.n_min = Param(model.NUTR, within=NonNegativeReals, default=0.0)
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals, default=0.0)
def n_max_validate(model, value, j):
return value > model.n_min[j]
-model.n_max = Param(model.NUTR, validate=n_max_validate, default=infinity)
+model.n_max = pyo.Param(model.NUTR, validate=n_max_validate, default=infinity)
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
# --------------------------------------------------------
@@ -54,7 +54,7 @@ def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds, within=NonNegativeIntegers)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds, within=pyo.NonNegativeIntegers)
# --------------------------------------------------------
@@ -66,7 +66,7 @@ def Total_Cost_rule(model):
return ans
-model.Total_Cost = Objective(rule=Total_Cost_rule, sense=minimize)
+model.Total_Cost = pyo.Objective(rule=Total_Cost_rule, sense=pyo.minimize)
def Nutr_Amt_rule(model, i):
@@ -76,7 +76,7 @@ def Nutr_Amt_rule(model, i):
return ans
-# model.Nutr_Amt = Objective(model.NUTR, rule=Nutr_Amt_rule)
+# model.Nutr_Amt = pyo.Objective(model.NUTR, rule=Nutr_Amt_rule)
# --------------------------------------------------------
@@ -88,4 +88,4 @@ def Diet_rule(model, i):
return (model.n_min[i], expr, model.n_max[i])
-model.Diet = Constraint(model.NUTR, rule=Diet_rule)
+model.Diet = pyo.Constraint(model.NUTR, rule=Diet_rule)
diff --git a/examples/pyomo/draft/api.py b/examples/pyomo/draft/api.py
index d785f41935e..c758647714d 100644
--- a/examples/pyomo/draft/api.py
+++ b/examples/pyomo/draft/api.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -18,7 +18,7 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
## -------------------------------------------------------------------------
@@ -32,7 +32,7 @@
# objects are contained in a model, which supports the generation of
# problem instances that can be solved.
#
-model = AbstractModel()
+model = pyo.AbstractModel()
#
# Once a model has been setup, a problem instance can be created with the
# create() method:
@@ -55,11 +55,11 @@
#
# Simple constructor of a single set
#
-model.A = Set()
+model.A = pyo.Set()
#
# Creating an array of sets, which are indexed with another set
#
-model.C = Set(model.A, model.A)
+model.C = pyo.Set(model.A, model.A)
#
# Option 'initialize' indicates how values in the set will be constructed.
# This option behaves differently depending on the type of data provided:
@@ -68,15 +68,15 @@
# (3) a function can be used to initial a set (perhaps using model
# information.
#
-model.A = Set(initialize=[1, 4, 9])
-model.B = Set(model.A, initialize={1: [1, 4, 9], 2: [2, 5, 10]})
+model.A = pyo.Set(initialize=[1, 4, 9])
+model.B = pyo.Set(model.A, initialize={1: [1, 4, 9], 2: [2, 5, 10]})
def f(model):
return range(0, 10)
-model.A = Set(initialize=f)
+model.A = pyo.Set(initialize=f)
#
@@ -85,18 +85,18 @@ def f(model):
#
def f(model, i):
if i == 10:
- return Set.End
+ return pyo.Set.End
if i == 0:
return 1
else:
return model.A[i - 1] * (i + 1)
-model.A = Set(ordered=True, initialize=f)
+model.A = pyo.Set(ordered=True, initialize=f)
#
# Option 'within' specifies a set that is used to validate set elements
#
-model.B = Set(within=model.A)
+model.B = pyo.Set(within=model.A)
#
@@ -106,11 +106,11 @@ def f(model, value):
return value in model.A
-model.B = Set(validate=f)
+model.B = pyo.Set(validate=f)
#
# Option 'dimen' specifies the arity of the data in the set
#
-model.A = Set(dimen=3)
+model.A = pyo.Set(dimen=3)
#
####
#### Set Methods
@@ -121,7 +121,7 @@ def f(model, value):
len(model.A)
len(model.A[i])
#
-# data() - returns the underlying set object used by Set()
+# data() - returns the underlying set object used by pyo.Set()
#
instance.A.data()
instance.A[i].data()
@@ -216,17 +216,17 @@ def f(model, value):
#
# Scalar parameter
#
-model.Z = Param()
+model.Z = pyo.Param()
#
# Array of parameters
#
-model.Z = Param(model.A, model.B)
+model.Z = pyo.Param(model.A, model.B)
#
# Option 'initialize' specifies values used to construct the parameter
#
-model.Z = Param(initialize=9)
-model.Z = Param(model.A, initialize={1: 1, 2: 4, 3: 9})
-model.Z = Param(model.A, initialize=2)
+model.Z = pyo.Param(initialize=9)
+model.Z = pyo.Param(model.A, initialize={1: 1, 2: 4, 3: 9})
+model.Z = pyo.Param(model.A, initialize=2)
#
@@ -237,19 +237,19 @@ def f(model, i):
return 3 * i
-model.Z = Param(model.A, initialize=f)
+model.Z = pyo.Param(model.A, initialize=f)
#
# Option 'default' specifies values used for a parameter if no value
# has been set. Note that for scalar parameters this has the same
# role as the 'initialize' option. For parameter arrays this
# 'fills in' parameter values that have not been initialized.
#
-model.Z = Param(default=9.0)
-model.Z = Param(model.A, default=9.0)
+model.Z = pyo.Param(default=9.0)
+model.Z = pyo.Param(model.A, default=9.0)
#
# Option 'within' specifies a set that is used to validate parameters
#
-model.Z = Param(within=model.A)
+model.Z = pyo.Param(within=model.A)
#
@@ -259,7 +259,7 @@ def f(model, value):
return value in model.A
-model.Z = Param(validate=f)
+model.Z = pyo.Param(validate=f)
#
####
#### Param Methods
@@ -284,8 +284,8 @@ def f(model, value):
#
# Getting parameter values (which may be integer or floats)
#
-tmp = value(instance.Z)
-tmp = value(instance.Z[i])
+tmp = pyo.value(instance.Z)
+tmp = pyo.value(instance.Z[i])
tmp = instance.Z.value
tmp = instance.Z[i].value
#
@@ -318,17 +318,17 @@ def f(model, value):
#
# Scalar variable
#
-model.x = Var()
+model.x = pyo.Var()
#
# Array of variables
#
-model.x = Var(model.A, model.B)
+model.x = pyo.Var(model.A, model.B)
#
# Option 'initialize' specifies the initial values of variables
#
-model.x = Var(initialize=9)
-model.x = Var(model.A, initialize={1: 1, 2: 4, 3: 9})
-model.x = Var(model.A, initialize=2)
+model.x = pyo.Var(initialize=9)
+model.x = pyo.Var(model.A, initialize={1: 1, 2: 4, 3: 9})
+model.x = pyo.Var(model.A, initialize=2)
#
@@ -339,24 +339,24 @@ def f(model, i):
return 3 * i
-model.x = Var(model.A, initialize=f)
+model.x = pyo.Var(model.A, initialize=f)
#
# Option 'within' specifies a set that is used to constrain variables
#
-model.x = Var(within=model.A)
+model.x = pyo.Var(within=model.A)
#
# Option 'bounds' specifies upper and lower bounds for variables.
# Simple bounds can be specified, or a function that defines bounds for
# different variables.
#
-model.x = Var(bounds=(0.0, 1.0))
+model.x = pyo.Var(bounds=(0.0, 1.0))
def f(model, i):
return (model.x_low[i], model._x_high[i])
-model.x = Var(bounds=f)
+model.x = pyo.Var(bounds=f)
#
####
#### Var Methods
@@ -381,8 +381,8 @@ def f(model, i):
#
# Getting variable values (which may be integer or floats)
#
-tmp = value(instance.x)
-tmp = value(instance.x[i])
+tmp = pyo.value(instance.x)
+tmp = pyo.value(instance.x[i])
tmp = instance.x.value
tmp = instance.x[i].value
#
@@ -402,7 +402,7 @@ def f(model, i):
####
#
# Value - the value of a variable
-# Note: value(x) == x.value
+# Note: pyo.value(x) == x.value
#
instance.x.value = 1.0
tmp = instance.x.value
@@ -435,29 +435,29 @@ def f(model, i):
#
# Scalar objective
#
-model.obj = Objective()
+model.obj = pyo.Objective()
#
# Array of objectives
#
-model.obj = Objective(model.A, model.B)
+model.obj = pyo.Objective(model.A, model.B)
#
# Option 'rule' can specify a function used to construct the objective
# expression
#
-model.Z = Param(model.A)
-model.x = Var(model.A)
+model.Z = pyo.Param(model.A)
+model.x = pyo.Var(model.A)
def f(model, i):
return model.Z[i] * model.A[i]
-model.obj = Objective(model.A, rule=f)
+model.obj = pyo.Objective(model.A, rule=f)
#
# Option 'sense' specifies whether the objective is maximized or minimized
# Note: this option applies to all objectives in an array objective
#
-model.obj = Objective(sense=maximize)
+model.obj = pyo.Objective(sense=pyo.maximize)
#
####
#### Objective Methods
@@ -481,13 +481,13 @@ def f(model, i):
#
# sense - the optimization sense
#
-instance.x.sense = maximize
+instance.x.sense = pyo.maximize
#
# value - returns the value of the objective
# NOTE: this attribute cannot be set
#
tmp = instance.obj.value
-tmp = value(instance.obj)
+tmp = pyo.value(instance.obj)
#
# NOTE: if the objective is an array, then this returns a dictionary of
# objective values, indexed by the array indices. Thus, the following
@@ -495,7 +495,7 @@ def f(model, i):
# for index '2'
#
tmp = instance.obj.value[2]
-tmp = value(instance.obj)[2]
+tmp = pyo.value(instance.obj)[2]
## -------------------------------------------------------------------------
@@ -514,17 +514,17 @@ def f(model, i):
#
# Scalar constraint
#
-model.con = Constraint()
+model.con = pyo.Constraint()
#
# Array of constraint
#
-model.con = Constraint(model.A, model.B)
+model.con = pyo.Constraint(model.A, model.B)
#
# Option 'rule' can specify a function used to construct the constraint
# expression
#
-model.Z = Param(model.A)
-model.x = Var(model.A)
+model.Z = pyo.Param(model.A)
+model.x = pyo.Var(model.A)
def f(model, i):
@@ -532,7 +532,7 @@ def f(model, i):
return (0, expr, 1)
-model.con = Constraint(model.A, rule=f)
+model.con = pyo.Constraint(model.A, rule=f)
#
@@ -577,12 +577,12 @@ def f(model, i):
#
def f1(model, i):
if i % 2 == 0:
- return Constraint.Skip
+ return pyo.Constraint.Skip
expr = model.Z[i] * model.A[i]
return (0, expr, 1)
-model.con1 = Constraint(model.A, rule=f1)
+model.con1 = pyo.Constraint(model.A, rule=f1)
def f2(model):
@@ -594,7 +594,7 @@ def f2(model):
return res
-model.con2 = Constraint(model.A, rule=f2)
+model.con2 = pyo.Constraint(model.A, rule=f2)
####
#### Constraint Methods
@@ -620,7 +620,7 @@ def f2(model):
# NOTE: this attribute cannot be set
#
tmp = instance.con.value
-tmp = value(instance.con)
+tmp = pyo.value(instance.con)
#
# NOTE: if the constraint is an array, then this returns a dictionary of
# constraint values, indexed by the array indices. Thus, the following
@@ -628,4 +628,4 @@ def f2(model):
# for index '2'
#
tmp = instance.con.value[2]
-tmp = value(instance.con)[2]
+tmp = pyo.value(instance.con)[2]
diff --git a/examples/pyomo/draft/bpack.py b/examples/pyomo/draft/bpack.py
index 7b076f7737b..f16697ba22c 100644
--- a/examples/pyomo/draft/bpack.py
+++ b/examples/pyomo/draft/bpack.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,21 +10,21 @@
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
#
# Parameter N
#
-model.N = Param(within=Integers)
+model.N = pyo.Param(within=pyo.Integers)
#
# Set I
#
-model.I = RangeSet(1, model.N)
+model.I = pyo.RangeSet(1, model.N)
#
# Variable b
#
-model.b = Var(model.I, domain=Boolean)
+model.b = pyo.Var(model.I, domain=pyo.Boolean)
#
@@ -38,8 +38,8 @@ def costrule(model):
return ans
-# model.zot = Objective(rule=costrule)
-model.zot = Objective(rule=costrule, sense=maximize)
+# model.zot = pyo.Objective(rule=costrule)
+model.zot = pyo.Objective(rule=costrule, sense=pyo.maximize)
#
@@ -59,19 +59,19 @@ def w_ind_rule(model):
return ans
-model.w_ind = Set(initialize=w_ind_rule, dimen=2)
+model.w_ind = pyo.Set(initialize=w_ind_rule, dimen=2)
#
# Parameter w
#
-model.w = Param(model.w_ind)
+model.w = pyo.Param(model.w_ind)
#
# Set rhs_ind
#
-model.rhs_ind = RangeSet(1, model.N - 9)
+model.rhs_ind = pyo.RangeSet(1, model.N - 9)
#
# Parameter rhs
#
-model.rhs = Param(model.rhs_ind)
+model.rhs = pyo.Param(model.rhs_ind)
#
@@ -88,4 +88,4 @@ def bletch_rule(model, i):
return ans
-model.bletch = Constraint(model.rhs_ind, rule=bletch_rule)
+model.bletch = pyo.Constraint(model.rhs_ind, rule=bletch_rule)
diff --git a/examples/pyomo/draft/diet2.py b/examples/pyomo/draft/diet2.py
index d23fa3cf5db..9c318438a51 100644
--- a/examples/pyomo/draft/diet2.py
+++ b/examples/pyomo/draft/diet2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -15,28 +15,28 @@
#
# Imports
#
-from pyomo.core import *
+import pyomo.environ as pyo
#
# Setup
#
-model = AbstractModel()
-model.NUTR = Set()
-model.FOOD = Set()
+model = pyo.AbstractModel()
+model.NUTR = pyo.Set()
+model.FOOD = pyo.Set()
-model.cost = Param(model.FOOD, within=NonNegativeReals)
+model.cost = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
-model.f_min = Param(model.FOOD, within=NonNegativeReals)
+model.f_min = pyo.Param(model.FOOD, within=pyo.NonNegativeReals)
def f_max_valid(model, value, j):
return model.f_max[j] > model.f_min[j]
-model.f_max = Param(model.FOOD, validate=f_max_valid)
+model.f_max = pyo.Param(model.FOOD, validate=f_max_valid)
-model.n_min = Param(model.NUTR, within=NonNegativeReals)
+model.n_min = pyo.Param(model.NUTR, within=pyo.NonNegativeReals)
def paramn_max(model, i):
@@ -44,18 +44,18 @@ def paramn_max(model, i):
return model.n_max[i]
-model.n_max = Param(model.NUTR, initialize=paramn_max)
+model.n_max = pyo.Param(model.NUTR, initialize=paramn_max)
# ***********************************
-model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
+model.amt = pyo.Param(model.NUTR, model.FOOD, within=pyo.NonNegativeReals)
def Buy_bounds(model, i):
return (model.f_min[i], model.f_max[i])
-model.Buy = Var(model.FOOD, bounds=Buy_bounds)
+model.Buy = pyo.Var(model.FOOD, bounds=Buy_bounds)
def Objective_rule(model):
@@ -67,7 +67,7 @@ def Objective_rule(model):
return ans
-model.totalcost = Objective(rule=Objective_rule)
+model.totalcost = pyo.Objective(rule=Objective_rule)
def Diet_rule(model, i):
@@ -81,4 +81,4 @@ def Diet_rule(model, i):
return expr
-model.Diet = Constraint(model.NUTR, rule=Diet_rule)
+model.Diet = pyo.Constraint(model.NUTR, rule=Diet_rule)
diff --git a/examples/pyomo/draft/morphEpanet3.mod b/examples/pyomo/draft/morphEpanet3.mod
index a1a8dc79dee..2899d868dcf 100644
--- a/examples/pyomo/draft/morphEpanet3.mod
+++ b/examples/pyomo/draft/morphEpanet3.mod
@@ -25,7 +25,7 @@ set ID;
param pipe := 1;
param pump := 2;
param valve := 3;
-param typ {ID};
+param type {ID};
param source {ID};
param sink {ID};
param demand {V};
@@ -436,19 +436,19 @@ let DA := setof {(id,i,j,l,d,f,h) in Pipes} (id,i,j)
let ID := setof {(id,i,j) in DA} id;
for {(idd,i,j,l,d,f,h) in Pipes} {
- let typ[idd] := pipe;
+ let type[idd] := pipe;
let source[idd] := i;
let sink[idd] := j;
}
for {(id,i,j,d,f,h) in Valves} {
- let typ[id] := valve;
+ let type[id] := valve;
let source[id] := i;
let sink[id] := j;
}
for {(id,i,j,f,h) in Pumps} {
- let typ[id] := pump;
+ let type[id] := pump;
let source[id] := i;
let sink[id] := j;
}
diff --git a/examples/pyomo/p-median/decorated_pmedian.py b/examples/pyomo/p-median/decorated_pmedian.py
index c66971945f3..f66a1463745 100644
--- a/examples/pyomo/p-median/decorated_pmedian.py
+++ b/examples/pyomo/p-median/decorated_pmedian.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,30 +9,30 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.environ import *
+import pyomo.environ as pyo
import random
random.seed(1000)
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.N = Param(within=PositiveIntegers)
-model.P = Param(within=RangeSet(1, model.N))
-model.M = Param(within=PositiveIntegers)
+model.N = pyo.Param(within=pyo.PositiveIntegers)
+model.P = pyo.Param(within=pyo.RangeSet(1, model.N))
+model.M = pyo.Param(within=pyo.PositiveIntegers)
-model.Locations = RangeSet(1, model.N)
-model.Customers = RangeSet(1, model.M)
+model.Locations = pyo.RangeSet(1, model.N)
+model.Customers = pyo.RangeSet(1, model.M)
-model.d = Param(
+model.d = pyo.Param(
model.Locations,
model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
- within=Reals,
+ within=pyo.Reals,
)
-model.x = Var(model.Locations, model.Customers, bounds=(0.0, 1.0))
-model.y = Var(model.Locations, within=Binary)
+model.x = pyo.Var(model.Locations, model.Customers, bounds=(0.0, 1.0))
+model.y = pyo.Var(model.Locations, within=pyo.Binary)
@model.Objective()
diff --git a/examples/pyomo/p-median/pmedian.py b/examples/pyomo/p-median/pmedian.py
index 865aa7cb61f..86143d1c3fa 100644
--- a/examples/pyomo/p-median/pmedian.py
+++ b/examples/pyomo/p-median/pmedian.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,7 @@
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
def pyomo_create_model(options=None, model_options=None):
@@ -18,28 +18,28 @@ def pyomo_create_model(options=None, model_options=None):
random.seed(1000)
- model = AbstractModel()
+ model = pyo.AbstractModel()
- model.N = Param(within=PositiveIntegers)
+ model.N = pyo.Param(within=pyo.PositiveIntegers)
- model.Locations = RangeSet(1, model.N)
+ model.Locations = pyo.RangeSet(1, model.N)
- model.P = Param(within=RangeSet(1, model.N))
+ model.P = pyo.Param(within=pyo.RangeSet(1, model.N))
- model.M = Param(within=PositiveIntegers)
+ model.M = pyo.Param(within=pyo.PositiveIntegers)
- model.Customers = RangeSet(1, model.M)
+ model.Customers = pyo.RangeSet(1, model.M)
- model.d = Param(
+ model.d = pyo.Param(
model.Locations,
model.Customers,
initialize=lambda n, m, model: random.uniform(1.0, 2.0),
- within=Reals,
+ within=pyo.Reals,
)
- model.x = Var(model.Locations, model.Customers, bounds=(0.0, 1.0))
+ model.x = pyo.Var(model.Locations, model.Customers, bounds=(0.0, 1.0))
- model.y = Var(model.Locations, within=Binary)
+ model.y = pyo.Var(model.Locations, within=pyo.Binary)
def rule(model):
return sum(
@@ -48,21 +48,21 @@ def rule(model):
for m in model.Customers
)
- model.obj = Objective(rule=rule)
+ model.obj = pyo.Objective(rule=rule)
def rule(model, m):
return (sum(model.x[n, m] for n in model.Locations), 1.0)
- model.single_x = Constraint(model.Customers, rule=rule)
+ model.single_x = pyo.Constraint(model.Customers, rule=rule)
def rule(model, n, m):
return (None, model.x[n, m] - model.y[n], 0.0)
- model.bound_y = Constraint(model.Locations, model.Customers, rule=rule)
+ model.bound_y = pyo.Constraint(model.Locations, model.Customers, rule=rule)
def rule(model):
return (sum(model.y[n] for n in model.Locations) - model.P, 0.0)
- model.num_facilities = Constraint(rule=rule)
+ model.num_facilities = pyo.Constraint(rule=rule)
return model
diff --git a/examples/pyomo/p-median/solver1.py b/examples/pyomo/p-median/solver1.py
index 2652ab13943..7d63400aded 100644
--- a/examples/pyomo/p-median/solver1.py
+++ b/examples/pyomo/p-median/solver1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,12 +10,13 @@
# ___________________________________________________________________________
# Imports from Pyomo
-from pyomo.core import *
-from pyomo.common.plugin_base import *
-from pyomo.opt import *
+import copy
+import pyomo.environ as pyo
+from pyomo.common.plugin_base import alias, implements
+from pyomo.opt import SolverStatus, SolutionStatus, ProblemSense
-@plugin_factory(SolverFactory)
+@plugin_factory(pyo.SolverFactory)
class MySolver(object):
alias('greedy')
@@ -27,9 +28,9 @@ class MySolver(object):
def solve(self, instance, **kwds):
print("Starting greedy heuristic")
val, instance = self._greedy(instance)
- n = value(instance.N)
+ n = pyo.value(instance.N)
# Setup results
- results = SolverResults()
+ results = pyo.SolverResults()
results.problem.name = instance.name
results.problem.sense = ProblemSense.minimize
results.problem.num_constraints = 1
@@ -39,31 +40,31 @@ def solve(self, instance, **kwds):
soln = results.solution.add()
soln.value = val
soln.status = SolutionStatus.feasible
- for j in sequence(n):
+ for j in pyo.sequence(n):
if instance.y[j].value is 1:
soln.variable[instance.y[j].name] = {"Value": 1, "Id": j}
return results
# Perform a greedy search
def _greedy(self, instance):
- p = value(instance.P)
- n = value(instance.N)
- m = value(instance.M)
+ p = pyo.value(instance.P)
+ n = pyo.value(instance.N)
+ m = pyo.value(instance.M)
fixed = set()
# Initialize
- for j in sequence(n):
+ for j in pyo.sequence(n):
instance.y[j].value = 0
# Greedily fix the next best facility
- for i in sequence(p):
+ for i in pyo.sequence(p):
best = None
ndx = j
- for j in sequence(n):
+ for j in pyo.sequence(n):
if j in fixed:
continue
instance.y[j].value = 1
# Compute value
val = 0.0
- for kk in sequence(m):
+ for kk in pyo.sequence(m):
tmp = copy.copy(fixed)
tmp.add(j)
tbest = None
diff --git a/examples/pyomo/p-median/solver2.py b/examples/pyomo/p-median/solver2.py
index 50ec5388811..f8355d34b23 100644
--- a/examples/pyomo/p-median/solver2.py
+++ b/examples/pyomo/p-median/solver2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,9 +10,9 @@
# ___________________________________________________________________________
# Imports from Pyomo
-from pyomo.core import *
-from pyomo.common.plugin_base import *
-from pyomo.opt import *
+import pyomo.environ as pyo
+from pyomo.common.plugin_base import alias, implements
+from pyomo.opt import SolverStatus, SolutionStatus, ProblemSense
import random
import copy
@@ -29,9 +29,9 @@ class MySolver(object):
def solve(self, instance, **kwds):
print("Starting random heuristic")
val, sol = self._random(instance)
- n = value(instance.N)
+ n = pyo.value(instance.N)
# Setup results
- results = SolverResults()
+ results = pyo.SolverResults()
results.problem.name = instance.name
results.problem.sense = ProblemSense.minimize
results.problem.num_constraints = 1
@@ -41,7 +41,7 @@ def solve(self, instance, **kwds):
soln = results.solution.add()
soln.value = val
soln.status = SolutionStatus.feasible
- for j in sequence(n):
+ for j in pyo.sequence(n):
soln.variable[instance.y[j].name] = {"Value": sol[j - 1], "Id": j}
# Return results
return results
@@ -58,11 +58,11 @@ def _random(self, instance):
random.shuffle(sol)
# Compute value
val = 0.0
- for j in sequence(instance.M.value):
+ for j in pyo.sequence(instance.M.value):
val += min(
[
instance.d[i, j].value
- for i in sequence(instance.N.value)
+ for i in pyo.sequence(instance.N.value)
if sol[i - 1] == 1
]
)
diff --git a/examples/pyomo/piecewise/convex.py b/examples/pyomo/piecewise/convex.py
index fb8095f80e3..f9136bf12e8 100644
--- a/examples/pyomo/piecewise/convex.py
+++ b/examples/pyomo/piecewise/convex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -17,7 +17,7 @@
# \ X , 1 <= X <= 5
#
-from pyomo.core import *
+import pyomo.environ as pyo
# Define the function
@@ -27,14 +27,14 @@ def f(model, x):
return abs(x - 1) + 1.0
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.X = Var(bounds=(-5, 5))
-model.Z = Var()
+model.X = pyo.Var(bounds=(-5, 5))
+model.Z = pyo.Var()
# See documentation on Piecewise component by typing
# help(Piecewise) in a python terminal after importing pyomo.core
-model.con = Piecewise(
+model.con = pyo.Piecewise(
model.Z,
model.X, # range and domain variables
pw_pts=[-5, 1, 5],
@@ -48,4 +48,4 @@ def f(model, x):
# when a lower bounding convex function is supplied. Adding 'force_pw=True'
# to the Piecewise argument list will cause the original piecewise constraints
# to be used even when simplifications can be applied.
-model.obj = Objective(expr=model.Z, sense=minimize)
+model.obj = pyo.Objective(expr=model.Z, sense=pyo.minimize)
diff --git a/examples/pyomo/piecewise/indexed.py b/examples/pyomo/piecewise/indexed.py
index cde21ec847e..2aa47e5745c 100644
--- a/examples/pyomo/piecewise/indexed.py
+++ b/examples/pyomo/piecewise/indexed.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,24 +11,24 @@
# A piewise approximiation of a nonconvex objective function.
-from pyomo.core import *
+import pyomo.environ as pyo
# Define the function
# Just like in Pyomo constraint rules, a Pyomo model object
# must be the first argument for the function rule
def f(model, t1, t2, x):
- return 0.1 * x - cos(5.0 * x)
+ return 0.1 * x - pyo.cos(5.0 * x)
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# Note we can use an arbitrary number of index sets of
# arbitrary dimension as the first arguments to the
# Piecewise component.
-model.INDEX1 = Set(dimen=2, initialize=[(0, 1), (8, 3)])
-model.X = Var(model.INDEX1, bounds=(-2, 2))
-model.Z = Var(model.INDEX1)
+model.INDEX1 = pyo.Set(dimen=2, initialize=[(0, 1), (8, 3)])
+model.X = pyo.Var(model.INDEX1, bounds=(-2, 2))
+model.Z = pyo.Var(model.INDEX1)
# For indexed variables, pw_pts must be a
# python dictionary with keys the same as the variable index
@@ -45,7 +45,7 @@ def f(model, t1, t2, x):
for idx in model.X.index_set():
PW_PTS[idx] = [-2.0 + i * step for i in range(num_points)] # [-2.0, ..., 2.0]
-model.linearized_constraint = Piecewise(
+model.linearized_constraint = pyo.Piecewise(
model.INDEX1, # indexing sets
model.Z,
model.X, # range and domain variables
@@ -59,4 +59,4 @@ def f(model, t1, t2, x):
# maximize the sum of Z over its index
# This is just a simple example of how to implement indexed variables. All indices
# of Z will have the same solution.
-model.obj = Objective(expr=sum_product(model.Z), sense=maximize)
+model.obj = pyo.Objective(expr=pyo.sum_product(model.Z), sense=pyo.maximize)
diff --git a/examples/pyomo/piecewise/indexed_nonlinear.py b/examples/pyomo/piecewise/indexed_nonlinear.py
index d72fbc8a899..d3e66e5c52c 100644
--- a/examples/pyomo/piecewise/indexed_nonlinear.py
+++ b/examples/pyomo/piecewise/indexed_nonlinear.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
# Nonlinear version of example4.
# Must have a nonlinear solver
# to run this example.
-from pyomo.core import *
+import pyomo.environ as pyo
from indexed import model, f
@@ -22,7 +22,7 @@ def nonlinear_con_rule(model, i, j):
return model.Z[i, j] == f(model, i, j, model.X[i, j])
-model.nonlinear_constraint = Constraint(model.INDEX1, rule=nonlinear_con_rule)
+model.nonlinear_constraint = pyo.Constraint(model.INDEX1, rule=nonlinear_con_rule)
# deactivate all constraints on the Piecewise component
model.linearized_constraint.deactivate()
diff --git a/examples/pyomo/piecewise/indexed_points.py b/examples/pyomo/piecewise/indexed_points.py
index 66110bea342..06b178af341 100644
--- a/examples/pyomo/piecewise/indexed_points.py
+++ b/examples/pyomo/piecewise/indexed_points.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,25 +13,25 @@
# index set when starting from a discrete set of (x,y)
# points.
-from pyomo.core import *
+import pyomo.environ as pyo
# Note: One or both of these can also be a dictionary of
# lists with keys matching the index set
x = [0.0, 1.5, 3.0, 5.0]
y = [1.1, -1.1, 2.0, 1.1]
-model = ConcreteModel()
-model.index = Set(initialize=[1, 2, 3])
-model.x = Var(model.index, bounds=(min(x), max(x)))
-model.y = Var(model.index)
+model = pyo.ConcreteModel()
+model.index = pyo.Set(initialize=[1, 2, 3])
+model.x = pyo.Var(model.index, bounds=(min(x), max(x)))
+model.y = pyo.Var(model.index)
-model.fx = Piecewise(
+model.fx = pyo.Piecewise(
model.index, model.y, model.x, pw_pts=x, pw_constr_type='EQ', f_rule=y
)
-model.c = ConstraintList()
+model.c = pyo.ConstraintList()
model.c.add(model.x[1] >= 1.0)
model.c.add(model.x[2] >= 2.0)
model.c.add(model.x[3] >= 3.1)
-model.o = Objective(expr=sum_product(model.y))
+model.o = pyo.Objective(expr=pyo.sum_product(model.y))
diff --git a/examples/pyomo/piecewise/nonconvex.py b/examples/pyomo/piecewise/nonconvex.py
index 5300278d5b9..8164fc8cbe8 100644
--- a/examples/pyomo/piecewise/nonconvex.py
+++ b/examples/pyomo/piecewise/nonconvex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -15,7 +15,7 @@
# Z(X) = | -2X + 4 , 2 <= X <= 6
# \ 5X - 38 , 6 <= X <= 10
-from pyomo.core import *
+import pyomo.environ as pyo
# Define the function
# Just like in Pyomo constraint rules, a Pyomo model object
@@ -27,17 +27,17 @@ def f(model, x):
return RANGE_POINTS[x]
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.X = Var(bounds=(-1.0, 10.0))
-model.Z = Var()
-model.p = Var(within=NonNegativeReals)
-model.n = Var(within=NonNegativeReals)
+model.X = pyo.Var(bounds=(-1.0, 10.0))
+model.Z = pyo.Var()
+model.p = pyo.Var(within=pyo.NonNegativeReals)
+model.n = pyo.Var(within=pyo.NonNegativeReals)
# See documentation on Piecewise component by typing
# help(Piecewise) in a python terminal after importing pyomo.core
# Using BigM constraints with binary variables to represent the piecewise constraints
-model.con = Piecewise(
+model.con = pyo.Piecewise(
model.Z,
model.X, # range and domain variables
pw_pts=[-1.0, 2.0, 6.0, 10.0],
@@ -47,5 +47,5 @@ def f(model, x):
)
# minimize the 1-norm distance of Z to 7.0, i.e., |Z-7|
-model.pn_con = Constraint(expr=model.Z - 7.0 == model.p - model.n)
-model.obj = Objective(rule=lambda model: model.p + model.n, sense=minimize)
+model.pn_con = pyo.Constraint(expr=model.Z - 7.0 == model.p - model.n)
+model.obj = pyo.Objective(rule=lambda model: model.p + model.n, sense=pyo.minimize)
diff --git a/examples/pyomo/piecewise/points.py b/examples/pyomo/piecewise/points.py
index 91d45684c4f..6d4980e5949 100644
--- a/examples/pyomo/piecewise/points.py
+++ b/examples/pyomo/piecewise/points.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,15 +12,15 @@
# An example of how to use the Piecewise component when
# starting from a discrete set of (x,y) points.
-from pyomo.core import *
+import pyomo.environ as pyo
x = [0.0, 1.5, 3.0, 5.0]
y = [1.1, -1.1, 2.0, 1.1]
-model = ConcreteModel()
-model.x = Var(bounds=(min(x), max(x)))
-model.y = Var()
+model = pyo.ConcreteModel()
+model.x = pyo.Var(bounds=(min(x), max(x)))
+model.y = pyo.Var()
-model.fx = Piecewise(model.y, model.x, pw_pts=x, pw_constr_type='EQ', f_rule=y)
+model.fx = pyo.Piecewise(model.y, model.x, pw_pts=x, pw_constr_type='EQ', f_rule=y)
-model.o = Objective(expr=model.y)
+model.o = pyo.Objective(expr=model.y)
diff --git a/examples/pyomo/piecewise/step.py b/examples/pyomo/piecewise/step.py
index 95aac74d7f7..f6e58ae562a 100644
--- a/examples/pyomo/piecewise/step.py
+++ b/examples/pyomo/piecewise/step.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -24,16 +24,16 @@
DOMAIN_PTS = [0.0, 1.0, 1.0, 2.0, 2.0, 3.0]
RANGE_PTS = [0.0, 0.0, 2.0, 2.0, 0.5, 0.5]
-from pyomo.core import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.X = Var(bounds=(0, 3))
-model.Z = Var()
+model.X = pyo.Var(bounds=(0, 3))
+model.Z = pyo.Var()
# See documentation on Piecewise component by typing
# help(Piecewise) in a python terminal after importing pyomo.core
-model.con = Piecewise(
+model.con = pyo.Piecewise(
model.Z,
model.X, # range and domain variables
pw_pts=DOMAIN_PTS,
@@ -45,4 +45,4 @@
# not work with step functions are:
# BIGM_SOS1, BIGM_BIN, and MC
-model.obj = Objective(expr=model.Z + model.X, sense=maximize)
+model.obj = pyo.Objective(expr=model.Z + model.X, sense=pyo.maximize)
diff --git a/examples/pyomo/quadratic/example1.py b/examples/pyomo/quadratic/example1.py
index ab77c5a1733..3b2fce05820 100644
--- a/examples/pyomo/quadratic/example1.py
+++ b/examples/pyomo/quadratic/example1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -14,15 +14,15 @@
# constraints could (but shouldn't in a perfect world) cause issues for
# certain solvers.
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.x = Var(bounds=(-10, 10), within=Reals)
+model.x = pyo.Var(bounds=(-10, 10), within=pyo.Reals)
def objective_rule(model):
return model.x * model.x
-model.objective = Objective(rule=objective_rule, sense=minimize)
+model.objective = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
diff --git a/examples/pyomo/quadratic/example2.py b/examples/pyomo/quadratic/example2.py
index ce02c6f70c8..8978f47cde9 100644
--- a/examples/pyomo/quadratic/example2.py
+++ b/examples/pyomo/quadratic/example2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,29 +12,29 @@
# a slightly less brain-dead separable parabolic function of three variables, whose
# minimum is obviously at x[1]=x[2]=x[3]=0.
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
def indices_rule(model):
return range(1, 4)
-model.indices = Set(initialize=indices_rule, within=PositiveIntegers)
+model.indices = pyo.Set(initialize=indices_rule, within=pyo.PositiveIntegers)
-model.x = Var(model.indices, within=Reals)
+model.x = pyo.Var(model.indices, within=pyo.Reals)
def bound_x_rule(model, i):
return (-10, model.x[i], 10)
-model.bound_x = Constraint(model.indices, rule=bound_x_rule)
+model.bound_x = pyo.Constraint(model.indices, rule=bound_x_rule)
def objective_rule(model):
return sum([model.x[i] * model.x[i] for i in model.indices])
-model.objective = Objective(rule=objective_rule, sense=minimize)
+model.objective = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
diff --git a/examples/pyomo/quadratic/example3.py b/examples/pyomo/quadratic/example3.py
index bdba936f694..5a000dc633b 100644
--- a/examples/pyomo/quadratic/example3.py
+++ b/examples/pyomo/quadratic/example3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,29 +13,29 @@
# optimal objective function value is obviously 5, with the optimal solution
# being x[1]=x[2]=x[3]=3.
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
def indices_rule(model):
- return xrange(1, 4)
+ return range(1, 4)
-model.indices = Set(initialize=indices_rule, within=PositiveIntegers)
+model.indices = pyo.Set(initialize=indices_rule, within=pyo.PositiveIntegers)
-model.x = Var(model.indices, within=Reals)
+model.x = pyo.Var(model.indices, within=pyo.Reals)
def bound_x_rule(model, i):
return (-10, model.x[i], 10)
-model.bound_x = Constraint(model.indices, rule=bound_x_rule)
+model.bound_x = pyo.Constraint(model.indices, rule=bound_x_rule)
def objective_rule(model):
return 5 + sum([(model.x[i] - 3) * (model.x[i] - 3) for i in model.indices])
-model.objective = Objective(rule=objective_rule, sense=minimize)
+model.objective = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
diff --git a/examples/pyomo/quadratic/example4.py b/examples/pyomo/quadratic/example4.py
index ecfc9981162..f39e1941f93 100644
--- a/examples/pyomo/quadratic/example4.py
+++ b/examples/pyomo/quadratic/example4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,19 +12,19 @@
# a simple quadratic function of two variables - taken from the CPLEX file format reference manual.
# optimal objective function value is 60. solution is x=10, y=0.
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
-model.x = Var(within=NonNegativeReals)
-model.y = Var(within=NonNegativeReals)
+model.x = pyo.Var(within=pyo.NonNegativeReals)
+model.y = pyo.Var(within=pyo.NonNegativeReals)
def constraint_rule(model):
return model.x + model.y >= 10
-model.constraint = Constraint(rule=constraint_rule)
+model.constraint = pyo.Constraint(rule=constraint_rule)
def objective_rule(model):
@@ -35,4 +35,4 @@ def objective_rule(model):
)
-model.objective = Objective(rule=objective_rule, sense=minimize)
+model.objective = pyo.Objective(rule=objective_rule, sense=pyo.minimize)
diff --git a/examples/pyomo/radertext/Ex2_1.py b/examples/pyomo/radertext/Ex2_1.py
index 981388d4c72..22f4efc8c8d 100644
--- a/examples/pyomo/radertext/Ex2_1.py
+++ b/examples/pyomo/radertext/Ex2_1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,26 +13,26 @@
# Example 2.1 - Allen Holder
#
-from pyomo.core import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Sets
-model.DoorType = Set()
-model.MachineType = Set()
-model.MarketDoorType1 = Set(within=model.DoorType)
-model.MarketDoorType2 = Set(within=model.DoorType)
+model.DoorType = pyo.Set()
+model.MachineType = pyo.Set()
+model.MarketDoorType1 = pyo.Set(within=model.DoorType)
+model.MarketDoorType2 = pyo.Set(within=model.DoorType)
# Parameters
-model.Hours = Param(model.DoorType, model.MachineType, within=NonNegativeReals)
-model.Labor = Param(model.DoorType, model.MachineType, within=NonNegativeReals)
-model.Profit = Param(model.DoorType, within=NonNegativeReals)
-model.MachineLimit = Param(model.MachineType, within=NonNegativeReals)
-model.LaborLimit = Param(within=NonNegativeReals)
+model.Hours = pyo.Param(model.DoorType, model.MachineType, within=pyo.NonNegativeReals)
+model.Labor = pyo.Param(model.DoorType, model.MachineType, within=pyo.NonNegativeReals)
+model.Profit = pyo.Param(model.DoorType, within=pyo.NonNegativeReals)
+model.MachineLimit = pyo.Param(model.MachineType, within=pyo.NonNegativeReals)
+model.LaborLimit = pyo.Param(within=pyo.NonNegativeReals)
# Variables
-model.NumDoors = Var(model.DoorType, within=NonNegativeIntegers)
+model.NumDoors = pyo.Var(model.DoorType, within=pyo.NonNegativeIntegers)
# Objective
@@ -40,7 +40,7 @@ def CalcProfit(M):
return sum(M.NumDoors[d] * M.Profit[d] for d in M.DoorType)
-model.TotProf = Objective(rule=CalcProfit, sense=maximize)
+model.TotProf = pyo.Objective(rule=CalcProfit, sense=pyo.maximize)
# Constraints
@@ -48,7 +48,7 @@ def EnsureMachineLimit(M, m):
return sum(M.NumDoors[d] * M.Labor[d, m] for d in M.DoorType) <= M.MachineLimit[m]
-model.MachineUpBound = Constraint(model.MachineType, rule=EnsureMachineLimit)
+model.MachineUpBound = pyo.Constraint(model.MachineType, rule=EnsureMachineLimit)
def EnsureLaborLimit(M):
@@ -58,7 +58,7 @@ def EnsureLaborLimit(M):
)
-model.MachineUpBound = Constraint(rule=EnsureLaborLimit)
+model.MachineUpBound = pyo.Constraint(rule=EnsureLaborLimit)
def EnsureMarketRatio(M):
@@ -67,4 +67,4 @@ def EnsureMarketRatio(M):
)
-model.MarketRatio = Constraint(rule=EnsureMarketRatio)
+model.MarketRatio = pyo.Constraint(rule=EnsureMarketRatio)
diff --git a/examples/pyomo/radertext/Ex2_2.py b/examples/pyomo/radertext/Ex2_2.py
index 41b56e52669..d610c178c19 100644
--- a/examples/pyomo/radertext/Ex2_2.py
+++ b/examples/pyomo/radertext/Ex2_2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,22 +13,22 @@
# Example 2.2 - Allen Holder
#
-from pyomo.core import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Parameters for Set Definitions
-model.NumTimePeriods = Param(within=NonNegativeIntegers)
+model.NumTimePeriods = pyo.Param(within=pyo.NonNegativeIntegers)
# Sets
-model.StartTime = RangeSet(1, model.NumTimePeriods)
+model.StartTime = pyo.RangeSet(1, model.NumTimePeriods)
# Parameters
-model.RequiredWorkers = Param(model.StartTime, within=NonNegativeIntegers)
+model.RequiredWorkers = pyo.Param(model.StartTime, within=pyo.NonNegativeIntegers)
# Variables
-model.NumWorkers = Var(model.StartTime, within=NonNegativeIntegers)
+model.NumWorkers = pyo.Var(model.StartTime, within=pyo.NonNegativeIntegers)
# Objective
@@ -36,7 +36,7 @@ def CalcTotalWorkers(M):
return sum(M.NumWorkers[i] for i in M.StartTime)
-model.TotalWorkers = Objective(rule=CalcTotalWorkers, sense=minimize)
+model.TotalWorkers = pyo.Objective(rule=CalcTotalWorkers, sense=pyo.minimize)
# Constraints
@@ -50,4 +50,4 @@ def EnsureWorkforce(M, i):
)
-model.WorkforceDemand = Constraint(model.StartTime, rule=EnsureWorkforce)
+model.WorkforceDemand = pyo.Constraint(model.StartTime, rule=EnsureWorkforce)
diff --git a/examples/pyomo/radertext/Ex2_3.py b/examples/pyomo/radertext/Ex2_3.py
index 7dc39afa773..534524053c2 100644
--- a/examples/pyomo/radertext/Ex2_3.py
+++ b/examples/pyomo/radertext/Ex2_3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,38 +13,37 @@
# Problem 2.17 - courtesy Allen Holder
#
-from pyomo.core import *
-from pyomo.opt import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Parameters for Set Definitions
-model.NumCrudeTypes = Param(within=PositiveIntegers)
-model.NumGasTypes = Param(within=PositiveIntegers)
+model.NumCrudeTypes = pyo.Param(within=pyo.PositiveIntegers)
+model.NumGasTypes = pyo.Param(within=pyo.PositiveIntegers)
# Sets
-model.CrudeType = RangeSet(1, model.NumCrudeTypes)
-model.GasType = RangeSet(1, model.NumGasTypes)
+model.CrudeType = pyo.RangeSet(1, model.NumCrudeTypes)
+model.GasType = pyo.RangeSet(1, model.NumGasTypes)
# Parameters
-model.Cost = Param(model.CrudeType, within=NonNegativeReals)
-model.CrudeOctane = Param(model.CrudeType, within=NonNegativeReals)
-model.CrudeMax = Param(model.CrudeType, within=NonNegativeReals)
-model.MinGasOctane = Param(model.GasType, within=NonNegativeReals)
-model.GasPrice = Param(model.GasType, within=NonNegativeReals)
-model.GasDemand = Param(model.GasType, within=NonNegativeReals)
-model.MixtureUpBounds = Param(
- model.CrudeType, model.GasType, within=NonNegativeReals, default=10**8
+model.Cost = pyo.Param(model.CrudeType, within=pyo.NonNegativeReals)
+model.CrudeOctane = pyo.Param(model.CrudeType, within=pyo.NonNegativeReals)
+model.CrudeMax = pyo.Param(model.CrudeType, within=pyo.NonNegativeReals)
+model.MinGasOctane = pyo.Param(model.GasType, within=pyo.NonNegativeReals)
+model.GasPrice = pyo.Param(model.GasType, within=pyo.NonNegativeReals)
+model.GasDemand = pyo.Param(model.GasType, within=pyo.NonNegativeReals)
+model.MixtureUpBounds = pyo.Param(
+ model.CrudeType, model.GasType, within=pyo.NonNegativeReals, default=10**8
)
-model.MixtureLowBounds = Param(
- model.CrudeType, model.GasType, within=NonNegativeReals, default=0
+model.MixtureLowBounds = pyo.Param(
+ model.CrudeType, model.GasType, within=pyo.NonNegativeReals, default=0
)
# Variabls
-model.x = Var(model.CrudeType, model.GasType, within=NonNegativeReals)
-model.q = Var(model.CrudeType, within=NonNegativeReals)
-model.z = Var(model.GasType, within=NonNegativeReals)
+model.x = pyo.Var(model.CrudeType, model.GasType, within=pyo.NonNegativeReals)
+model.q = pyo.Var(model.CrudeType, within=pyo.NonNegativeReals)
+model.z = pyo.Var(model.GasType, within=pyo.NonNegativeReals)
# Objective
@@ -54,7 +53,7 @@ def CalcProfit(M):
)
-model.Profit = Objective(rule=CalcProfit, sense=maximize)
+model.Profit = pyo.Objective(rule=CalcProfit, sense=pyo.maximize)
# Constraints
@@ -63,28 +62,28 @@ def BalanceCrude(M, i):
return sum(M.x[i, j] for j in M.GasType) == M.q[i]
-model.BalanceCrudeProduction = Constraint(model.CrudeType, rule=BalanceCrude)
+model.BalanceCrudeProduction = pyo.Constraint(model.CrudeType, rule=BalanceCrude)
def BalanceGas(M, j):
return sum(M.x[i, j] for i in M.CrudeType) == M.z[j]
-model.BalanceGasProduction = Constraint(model.GasType, rule=BalanceGas)
+model.BalanceGasProduction = pyo.Constraint(model.GasType, rule=BalanceGas)
def EnsureCrudeLimit(M, i):
return M.q[i] <= M.CrudeMax[i]
-model.LimitCrude = Constraint(model.CrudeType, rule=EnsureCrudeLimit)
+model.LimitCrude = pyo.Constraint(model.CrudeType, rule=EnsureCrudeLimit)
def EnsureGasDemand(M, j):
return M.z[j] >= M.GasDemand[j]
-model.DemandGas = Constraint(model.GasType, rule=EnsureGasDemand)
+model.DemandGas = pyo.Constraint(model.GasType, rule=EnsureGasDemand)
def EnsureOctane(M, j):
@@ -94,18 +93,22 @@ def EnsureOctane(M, j):
)
-model.OctaneLimit = Constraint(model.GasType, rule=EnsureOctane)
+model.OctaneLimit = pyo.Constraint(model.GasType, rule=EnsureOctane)
def EnsureLowMixture(M, i, j):
return sum(M.x[k, j] for k in M.CrudeType) * M.MixtureLowBounds[i, j] <= M.x[i, j]
-model.LowCrudeBound = Constraint(model.CrudeType, model.GasType, rule=EnsureLowMixture)
+model.LowCrudeBound = pyo.Constraint(
+ model.CrudeType, model.GasType, rule=EnsureLowMixture
+)
def EnsureUpMixture(M, i, j):
return sum(M.x[k, j] for k in M.CrudeType) * M.MixtureUpBounds[i, j] >= M.x[i, j]
-model.UpCrudeBound = Constraint(model.CrudeType, model.GasType, rule=EnsureUpMixture)
+model.UpCrudeBound = pyo.Constraint(
+ model.CrudeType, model.GasType, rule=EnsureUpMixture
+)
diff --git a/examples/pyomo/radertext/Ex2_5.py b/examples/pyomo/radertext/Ex2_5.py
index fee49b46cb0..10ab0bd5da1 100644
--- a/examples/pyomo/radertext/Ex2_5.py
+++ b/examples/pyomo/radertext/Ex2_5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,30 +13,29 @@
# Example 2.5 - Allen Holder
#
-from pyomo.core import *
-from pyomo.opt import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Sets
-model.NumMonths = Param(within=NonNegativeIntegers)
-model.EngineType = Set()
-model.Month = RangeSet(1, model.NumMonths)
+model.NumMonths = pyo.Param(within=pyo.NonNegativeIntegers)
+model.EngineType = pyo.Set()
+model.Month = pyo.RangeSet(1, model.NumMonths)
# Parameters
-model.Demand = Param(model.EngineType, model.Month, within=NonNegativeIntegers)
-model.InvCost = Param(within=NonNegativeReals)
-model.InitInv = Param(model.EngineType, within=NonNegativeIntegers)
-model.FinInv = Param(model.EngineType, within=NonNegativeIntegers)
-model.Labor = Param(model.EngineType, within=NonNegativeReals)
-model.LaborBound = Param(within=NonNegativeReals)
-model.ProdCost = Param(model.EngineType, within=NonNegativeReals)
-model.ProdBound = Param(within=NonNegativeIntegers)
+model.Demand = pyo.Param(model.EngineType, model.Month, within=pyo.NonNegativeIntegers)
+model.InvCost = pyo.Param(within=pyo.NonNegativeReals)
+model.InitInv = pyo.Param(model.EngineType, within=pyo.NonNegativeIntegers)
+model.FinInv = pyo.Param(model.EngineType, within=pyo.NonNegativeIntegers)
+model.Labor = pyo.Param(model.EngineType, within=pyo.NonNegativeReals)
+model.LaborBound = pyo.Param(within=pyo.NonNegativeReals)
+model.ProdCost = pyo.Param(model.EngineType, within=pyo.NonNegativeReals)
+model.ProdBound = pyo.Param(within=pyo.NonNegativeIntegers)
# Variables
-model.Produce = Var(model.EngineType, model.Month, within=NonNegativeIntegers)
-model.Inventory = Var(model.EngineType, model.Month, within=NonNegativeIntegers)
+model.Produce = pyo.Var(model.EngineType, model.Month, within=pyo.NonNegativeIntegers)
+model.Inventory = pyo.Var(model.EngineType, model.Month, within=pyo.NonNegativeIntegers)
# Objective
@@ -46,7 +45,7 @@ def CalcCost(M):
) + sum(M.Inventory[e, t] * M.InvCost for e in M.EngineType for t in M.Month)
-model.TotalCost = Objective(rule=CalcCost, sense=minimize)
+model.TotalCost = pyo.Objective(rule=CalcCost, sense=pyo.minimize)
# Constraints
@@ -60,21 +59,23 @@ def EnsureBalance(M, e, t):
return M.Inventory[e, t] == M.InitInv[e] + M.Produce[e, t] - M.Demand[e, t]
-model.InventoryBalance = Constraint(model.EngineType, model.Month, rule=EnsureBalance)
+model.InventoryBalance = pyo.Constraint(
+ model.EngineType, model.Month, rule=EnsureBalance
+)
def EnsureLaborLimit(M, t):
return sum(M.Produce[e, t] * M.Labor[e] for e in M.EngineType) <= M.LaborBound
-model.LimitLabor = Constraint(model.Month, rule=EnsureLaborLimit)
+model.LimitLabor = pyo.Constraint(model.Month, rule=EnsureLaborLimit)
def EnsureProdLimit(M, t):
return sum(M.Produce[e, t] for e in M.EngineType) <= M.ProdBound
-model.ProdLimit = Constraint(model.Month, rule=EnsureProdLimit)
+model.ProdLimit = pyo.Constraint(model.Month, rule=EnsureProdLimit)
def LeaveEnough(M, e, t):
@@ -82,4 +83,4 @@ def LeaveEnough(M, e, t):
return M.Inventory[e, t] >= M.FinInv[e]
-model.FinalInventory = Constraint(model.EngineType, model.Month, rule=LeaveEnough)
+model.FinalInventory = pyo.Constraint(model.EngineType, model.Month, rule=LeaveEnough)
diff --git a/examples/pyomo/radertext/Ex2_6a.py b/examples/pyomo/radertext/Ex2_6a.py
index 24bb866ec51..92c59d37968 100644
--- a/examples/pyomo/radertext/Ex2_6a.py
+++ b/examples/pyomo/radertext/Ex2_6a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,25 +13,24 @@
# Example 2.6a - Allen Holder
#
-from pyomo.core import *
-from pyomo.opt import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Sets and Set Parameters
-model.NumSensors = Param(within=NonNegativeIntegers)
-model.Sensor = RangeSet(1, model.NumSensors)
+model.NumSensors = pyo.Param(within=pyo.NonNegativeIntegers)
+model.Sensor = pyo.RangeSet(1, model.NumSensors)
# Parameters
-model.xPos = Param(model.Sensor, within=NonNegativeIntegers)
-model.yPos = Param(model.Sensor, within=NonNegativeIntegers)
+model.xPos = pyo.Param(model.Sensor, within=pyo.NonNegativeIntegers)
+model.yPos = pyo.Param(model.Sensor, within=pyo.NonNegativeIntegers)
# Variables
-model.xCentralSensor = Var(within=NonNegativeIntegers)
-model.yCentralSensor = Var(within=NonNegativeIntegers)
-model.xMax = Var(model.Sensor, within=NonNegativeReals)
-model.yMax = Var(model.Sensor, within=NonNegativeReals)
+model.xCentralSensor = pyo.Var(within=pyo.NonNegativeIntegers)
+model.yCentralSensor = pyo.Var(within=pyo.NonNegativeIntegers)
+model.xMax = pyo.Var(model.Sensor, within=pyo.NonNegativeReals)
+model.yMax = pyo.Var(model.Sensor, within=pyo.NonNegativeReals)
# Objective
@@ -39,7 +38,7 @@ def CalcDist(M):
return sum(M.xMax[s] + M.yMax[s] for s in M.Sensor)
-model.Dist = Objective(rule=CalcDist, sense=minimize)
+model.Dist = pyo.Objective(rule=CalcDist, sense=pyo.minimize)
# Constraints
@@ -48,25 +47,25 @@ def xEnsureUp(s, M):
return M.xCentralSensor - M.xPos[s] <= M.xMax[s]
-model.xUpBound = Constraint(model.Sensor, rule=xEnsureUp)
+model.xUpBound = pyo.Constraint(model.Sensor, rule=xEnsureUp)
def xEnsureLow(s, M):
return M.xCentralSensor - M.xPos[s] >= -M.xMax[s]
-model.xLowBound = Constraint(model.Sensor, rule=xEnsureLow)
+model.xLowBound = pyo.Constraint(model.Sensor, rule=xEnsureLow)
def yEnsureUp(s, M):
return M.yCentralSensor - M.yPos[s] <= M.yMax[s]
-model.yUpBound = Constraint(model.Sensor, rule=yEnsureUp)
+model.yUpBound = pyo.Constraint(model.Sensor, rule=yEnsureUp)
def yEnsureLow(s, M):
return M.yCentralSensor - M.yPos[s] >= -M.yMax[s]
-model.yLowBound = Constraint(model.Sensor, rule=yEnsureLow)
+model.yLowBound = pyo.Constraint(model.Sensor, rule=yEnsureLow)
diff --git a/examples/pyomo/radertext/Ex2_6b.py b/examples/pyomo/radertext/Ex2_6b.py
index 1be55461b9e..5e7a046c887 100644
--- a/examples/pyomo/radertext/Ex2_6b.py
+++ b/examples/pyomo/radertext/Ex2_6b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,26 +13,25 @@
# Example 2.6b - Allen Holder
#
-from pyomo.core import *
-from pyomo.opt import *
+import pyomo.environ as pyo
# Instantiate the model
-model = AbstractModel()
+model = pyo.AbstractModel()
# Sets and Set Parameters
-model.NumSensors = Param(within=NonNegativeIntegers)
-model.Sensor = RangeSet(1, model.NumSensors)
+model.NumSensors = pyo.Param(within=pyo.NonNegativeIntegers)
+model.Sensor = pyo.RangeSet(1, model.NumSensors)
# Parameters
-model.xPos = Param(model.Sensor, within=NonNegativeIntegers)
-model.yPos = Param(model.Sensor, within=NonNegativeIntegers)
+model.xPos = pyo.Param(model.Sensor, within=pyo.NonNegativeIntegers)
+model.yPos = pyo.Param(model.Sensor, within=pyo.NonNegativeIntegers)
# Variables
-model.xCentralSensor = Var(within=NonNegativeIntegers)
-model.yCentralSensor = Var(within=NonNegativeIntegers)
-model.xMax = Var(model.Sensor, within=NonNegativeReals)
-model.yMax = Var(model.Sensor, within=NonNegativeReals)
-model.Max = Var(within=NonNegativeReals)
+model.xCentralSensor = pyo.Var(within=pyo.NonNegativeIntegers)
+model.yCentralSensor = pyo.Var(within=pyo.NonNegativeIntegers)
+model.xMax = pyo.Var(model.Sensor, within=pyo.NonNegativeReals)
+model.yMax = pyo.Var(model.Sensor, within=pyo.NonNegativeReals)
+model.Max = pyo.Var(within=pyo.NonNegativeReals)
# Objective
@@ -40,7 +39,7 @@ def CalcDist(M):
return M.Max
-model.Dist = Objective(rule=CalcDist, sense=minimize)
+model.Dist = pyo.Objective(rule=CalcDist, sense=pyo.minimize)
# Constraints
@@ -49,32 +48,32 @@ def xEnsureUp(M, s):
return M.xCentralSensor - M.xPos[s] <= M.xMax[s]
-model.xUpBound = Constraint(model.Sensor, rule=xEnsureUp)
+model.xUpBound = pyo.Constraint(model.Sensor, rule=xEnsureUp)
def xEnsureLow(M, s):
return M.xCentralSensor - M.xPos[s] >= -M.xMax[s]
-model.xLowBound = Constraint(model.Sensor, rule=xEnsureLow)
+model.xLowBound = pyo.Constraint(model.Sensor, rule=xEnsureLow)
def yEnsureUp(M, s):
return M.yCentralSensor - M.yPos[s] <= M.yMax[s]
-model.yUpBound = Constraint(model.Sensor, rule=yEnsureUp)
+model.yUpBound = pyo.Constraint(model.Sensor, rule=yEnsureUp)
def yEnsureLow(M, s):
return M.yCentralSensor - M.yPos[s] >= -M.yMax[s]
-model.yLowBound = Constraint(model.Sensor, rule=yEnsureLow)
+model.yLowBound = pyo.Constraint(model.Sensor, rule=yEnsureLow)
def EnsureSensorBound(M, s):
return M.xMax[s] + M.yMax[s] <= M.Max
-model.MaxDist = Constraint(model.Sensor, rule=EnsureSensorBound)
+model.MaxDist = pyo.Constraint(model.Sensor, rule=EnsureSensorBound)
diff --git a/examples/pyomo/sos/DepotSiting.py b/examples/pyomo/sos/DepotSiting.py
index 40826e989b7..6c3eed91d86 100644
--- a/examples/pyomo/sos/DepotSiting.py
+++ b/examples/pyomo/sos/DepotSiting.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,33 +11,35 @@
# a simple SOS example from "Modeling Building in Mathematical Programming", H. Paul Williams, 4th Edition, p. 166.
-from pyomo.core import *
+import pyomo.environ as pyo
-model = AbstractModel()
+model = pyo.AbstractModel()
# the set of customers.
-model.Customers = Set()
+model.Customers = pyo.Set()
# the possible locations of the facility that you're trying to place.
-model.Sites = Set()
+model.Sites = pyo.Set()
# the cost of satisfying customer demand from each of the potential sites.
-model.SatisfactionCost = Param(model.Customers, model.Sites, within=NonNegativeReals)
+model.SatisfactionCost = pyo.Param(
+ model.Customers, model.Sites, within=pyo.NonNegativeReals
+)
# indicators of which sites are selected. constraints ensure only one site is selected,
# and allow the binary integrality to be implicit.
-model.SiteSelected = Var(model.Sites, bounds=(0, 1))
+model.SiteSelected = pyo.Var(model.Sites, bounds=(0, 1))
# ensure that only one of the site selected variables is non-zero.
-model.SiteSelectedSOS = SOSConstraint(var=model.SiteSelected, sos=1)
+model.SiteSelectedSOS = pyo.SOSConstraint(var=model.SiteSelected, sos=1)
# ensure that one of the sites is selected (enforce binary).
def enforce_site_selected_binary_rule(model):
- return sum_product(model.SiteSelected) == 1
+ return pyo.sum_product(model.SiteSelected) == 1
-model.EnforceSiteSelectedBinary = Constraint(rule=enforce_site_selected_binary_rule)
+model.EnforceSiteSelectedBinary = pyo.Constraint(rule=enforce_site_selected_binary_rule)
# the objective is to minimize the cost to satisfy all customers.
@@ -51,4 +53,4 @@ def minimize_cost_rule(model):
)
-model.MinimizeCost = Objective(rule=minimize_cost_rule, sense=minimize)
+model.MinimizeCost = pyo.Objective(rule=minimize_cost_rule, sense=pyo.minimize)
diff --git a/examples/pyomo/sos/basic_sos2_example.py b/examples/pyomo/sos/basic_sos2_example.py
index 3aa0887356c..0620dfd7416 100644
--- a/examples/pyomo/sos/basic_sos2_example.py
+++ b/examples/pyomo/sos/basic_sos2_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,7 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.core import *
+import pyomo.environ as pyo
# Problem borrowed from the lpsolve project documentation
# http://lpsolve.sourceforge.net/5.0/SOS.htm
@@ -60,28 +60,28 @@ def constraint_rule(model, c):
###############################################################################
# Cruft above complete, now we actually create and tie the model together
-model = AbstractModel()
+model = pyo.AbstractModel()
M = model
-M.variable_set = RangeSet(1, 5)
-M.constraint_set = RangeSet(1, 2)
+M.variable_set = pyo.RangeSet(1, 5)
+M.constraint_set = pyo.RangeSet(1, 2)
-M.c = Param(M.variable_set, initialize=c_param_init)
+M.c = pyo.Param(M.variable_set, initialize=c_param_init)
-M.A = Param(M.constraint_set, M.variable_set, initialize=A_param_init)
-M.b = Param(M.constraint_set, initialize=b_param_init)
+M.A = pyo.Param(M.constraint_set, M.variable_set, initialize=A_param_init)
+M.b = pyo.Param(M.constraint_set, initialize=b_param_init)
-M.x = Var(M.variable_set, within=PositiveReals)
+M.x = pyo.Var(M.variable_set, within=pyo.PositiveReals)
-M.obj = Objective(rule=obj_rule, sense=minimize) # min "c transpose" X
+M.obj = pyo.Objective(rule=obj_rule, sense=pyo.minimize) # min "c transpose" X
# At first, this is little more than a standard form Ax=b ...
-M.constraints = Constraint(M.constraint_set, rule=constraint_rule)
+M.constraints = pyo.Constraint(M.constraint_set, rule=constraint_rule)
# ... with a couple of extra constraints ...
-M.x1_constraint = Constraint(rule=x1_constraint_rule)
-M.x2_constraint = Constraint(rule=x2_constraint_rule)
-M.x5_constraint = Constraint(rule=x5_constraint_rule)
+M.x1_constraint = pyo.Constraint(rule=x1_constraint_rule)
+M.x2_constraint = pyo.Constraint(rule=x2_constraint_rule)
+M.x5_constraint = pyo.Constraint(rule=x5_constraint_rule)
# ... and finally, add the constraint for which this example was created
-M.x_sos_vars = SOSConstraint(var=M.x, sos=2)
+M.x_sos_vars = pyo.SOSConstraint(var=M.x, sos=2)
diff --git a/examples/pyomo/sos/sos2_piecewise.py b/examples/pyomo/sos/sos2_piecewise.py
index 79195761f3d..bbcaccab6eb 100644
--- a/examples/pyomo/sos/sos2_piecewise.py
+++ b/examples/pyomo/sos/sos2_piecewise.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,19 +10,19 @@
# ___________________________________________________________________________
"""
-This example shows how to represent a piecewise function using
+This example shows how to represent a piecewise function using
Pyomo's built SOSConstraint component. The function is defined as:
/ 3x-2 , 1 <= x <= 2
-f(x) = |
+f(x) = |
\ 5x-6 , 2 <= x <= 3
"""
-from pyomo.core import *
+import pyomo.environ as pyo
-model = ConcreteModel()
+model = pyo.ConcreteModel()
-model.index_set = Set(initialize=[1, 2])
+model.index_set = pyo.Set(initialize=[1, 2])
DOMAIN_PTS = {1: [1, 2, 3], 2: [1, 2, 3]}
F = {1: [1, 4, 9], 2: [1, 4, 9]}
# Note we can also implement this like below
@@ -36,7 +36,7 @@ def SOS_indices_init(model, t):
return [(t, i) for i in range(len(DOMAIN_PTS[t]))]
-model.SOS_indices = Set(
+model.SOS_indices = pyo.Set(
model.index_set, dimen=2, ordered=True, initialize=SOS_indices_init
)
@@ -45,13 +45,13 @@ def sos_var_indices_init(model):
return [(t, i) for t in model.index_set for i in range(len(DOMAIN_PTS[t]))]
-model.sos_var_indices = Set(ordered=True, dimen=2, initialize=sos_var_indices_init)
+model.sos_var_indices = pyo.Set(ordered=True, dimen=2, initialize=sos_var_indices_init)
-model.x = Var(model.index_set) # domain variable
-model.Fx = Var(model.index_set) # range variable
-model.y = Var(model.sos_var_indices, within=NonNegativeReals) # SOS2 variable
+model.x = pyo.Var(model.index_set) # domain variable
+model.Fx = pyo.Var(model.index_set) # range variable
+model.y = pyo.Var(model.sos_var_indices, within=pyo.NonNegativeReals) # SOS2 variable
-model.obj = Objective(expr=sum_product(model.Fx), sense=maximize)
+model.obj = pyo.Objective(expr=pyo.sum_product(model.Fx), sense=pyo.maximize)
def constraint1_rule(model, t):
@@ -73,13 +73,13 @@ def constraint3_rule(model, t):
return sum(model.y[t, j] for j in range(len(DOMAIN_PTS[t]))) == 1
-model.constraint1 = Constraint(model.index_set, rule=constraint1_rule)
-model.constraint2 = Constraint(model.index_set, rule=constraint2_rule)
-model.constraint3 = Constraint(model.index_set, rule=constraint3_rule)
-model.SOS_set_constraint = SOSConstraint(
+model.constraint1 = pyo.Constraint(model.index_set, rule=constraint1_rule)
+model.constraint2 = pyo.Constraint(model.index_set, rule=constraint2_rule)
+model.constraint3 = pyo.Constraint(model.index_set, rule=constraint3_rule)
+model.SOS_set_constraint = pyo.SOSConstraint(
model.index_set, var=model.y, index=model.SOS_indices, sos=2
)
# Fix the answer for testing purposes
-model.set_answer_constraint1 = Constraint(expr=model.x[1] == 2.5)
-model.set_answer_constraint2 = Constraint(expr=model.x[2] == 2.0)
+model.set_answer_constraint1 = pyo.Constraint(expr=model.x[1] == 2.5)
+model.set_answer_constraint2 = pyo.Constraint(expr=model.x[2] == 2.0)
diff --git a/examples/pyomo/suffixes/duals_pyomo.py b/examples/pyomo/suffixes/duals_pyomo.py
index 6ce88fde429..41ec6e78ea0 100644
--- a/examples/pyomo/suffixes/duals_pyomo.py
+++ b/examples/pyomo/suffixes/duals_pyomo.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,17 +11,17 @@
# A Suffix example for the collection of duals.
-from pyomo.core import *
+import pyomo.environ as pyo
### Create a trivial and infeasible example model
-model = ConcreteModel()
-model.x = Var(within=NonNegativeReals)
-model.obj = Objective(expr=model.x)
-model.con = Constraint(expr=model.x >= 1)
+model = pyo.ConcreteModel()
+model.x = pyo.Var(within=pyo.NonNegativeReals)
+model.obj = pyo.Objective(expr=model.x)
+model.con = pyo.Constraint(expr=model.x >= 1)
###
# Declare an IMPORT Suffix to store the dual information that will
-# be returned by the solver. When Suffix components are declared
+# be returned by the solver. When pyo.Suffix components are declared
# with an IMPORT direction, Pyomo solver interfaces will attempt to collect
# this named information from a solver solution.
-model.dual = Suffix(direction=Suffix.IMPORT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
diff --git a/examples/pyomo/suffixes/duals_script.py b/examples/pyomo/suffixes/duals_script.py
index e8ef9aef1bc..754eb85ba4e 100644
--- a/examples/pyomo/suffixes/duals_script.py
+++ b/examples/pyomo/suffixes/duals_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -22,16 +22,14 @@
# on this system. This example was tested using Gurobi
# Solver 5.1.0
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the a solver plugin
solver = 'gurobi'
solver_io = 'lp' # Uses the LP file interface
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
diff --git a/examples/pyomo/suffixes/gurobi_ampl_basis.py b/examples/pyomo/suffixes/gurobi_ampl_basis.py
index eab86f8aa47..d323f49c448 100644
--- a/examples/pyomo/suffixes/gurobi_ampl_basis.py
+++ b/examples/pyomo/suffixes/gurobi_ampl_basis.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -22,7 +22,7 @@
# solver is in the current search path for executables
# on this system. This example was tested using
# gurobi_ampl version 6.5.0.
-from pyomo.environ import *
+import pyomo.environ as pyo
#
@@ -32,7 +32,7 @@
solver_io = 'nl'
stream_solver = True # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
print(
@@ -61,11 +61,11 @@
#
# Create a trivial example model
#
-model = ConcreteModel()
-model.s = Set(initialize=[1, 2, 3])
-model.x = Var(model.s, within=NonNegativeReals)
-model.obj = Objective(expr=sum_product(model.x))
-model.con = Constraint(model.s, rule=lambda model, i: model.x[i] >= i - 1)
+model = pyo.ConcreteModel()
+model.s = pyo.Set(initialize=[1, 2, 3])
+model.x = pyo.Var(model.s, within=pyo.NonNegativeReals)
+model.obj = pyo.Objective(expr=pyo.sum_product(model.x))
+model.con = pyo.Constraint(model.s, rule=lambda model, i: model.x[i] >= i - 1)
###
#
@@ -81,8 +81,8 @@
# - 5: nonbasic at equal lower and upper bounds
# - 6: nonbasic between bounds
-model.sstatus = Suffix(direction=Suffix.IMPORT_EXPORT, datatype=Suffix.INT)
-model.dual = Suffix(direction=Suffix.IMPORT_EXPORT)
+model.sstatus = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT, datatype=pyo.Suffix.INT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)
#
diff --git a/examples/pyomo/suffixes/gurobi_ampl_example.py b/examples/pyomo/suffixes/gurobi_ampl_example.py
index 4f3364c09dc..5c1e9748cc6 100644
--- a/examples/pyomo/suffixes/gurobi_ampl_example.py
+++ b/examples/pyomo/suffixes/gurobi_ampl_example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -21,16 +21,14 @@
# on this system. This example was tested using Gurobi
# Solver 5.0.0
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the gurobi_ampl solver plugin using the ASL interface
solver = 'gurobi_ampl'
solver_io = 'nl'
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
@@ -45,11 +43,11 @@
###
### Create a trivial example model
-model = ConcreteModel()
-model.s = Set(initialize=[1, 2, 3])
-model.x = Var(model.s, within=NonNegativeReals)
-model.obj = Objective(expr=sum_product(model.x))
-model.con = Constraint(model.s, rule=lambda model, i: model.x[i] >= i - 1)
+model = pyo.ConcreteModel()
+model.s = pyo.Set(initialize=[1, 2, 3])
+model.x = pyo.Var(model.s, within=pyo.NonNegativeReals)
+model.obj = pyo.Objective(expr=pyo.sum_product(model.x))
+model.con = pyo.Constraint(model.s, rule=lambda model, i: model.x[i] >= i - 1)
###
### Declare all suffixes
@@ -63,20 +61,30 @@
'equ': 5, # nonbasic at equal lower and upper bounds
'btw': 6,
} # nonbasic between bounds
-model.sstatus = Suffix(direction=Suffix.IMPORT_EXPORT, datatype=Suffix.INT)
-model.dual = Suffix(direction=Suffix.IMPORT_EXPORT)
+model.sstatus = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT, datatype=pyo.Suffix.INT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)
# Report the best known bound on the objective function
-model.bestbound = Suffix(direction=Suffix.IMPORT)
+model.bestbound = pyo.Suffix(direction=pyo.Suffix.IMPORT)
# A few Gurobi variable solution sensitivity suffixes
-model.senslblo = Suffix(direction=Suffix.IMPORT) # smallest variable lower bound
-model.senslbhi = Suffix(direction=Suffix.IMPORT) # greatest variable lower bound
-model.sensublo = Suffix(direction=Suffix.IMPORT) # smallest variable upper bound
-model.sensubhi = Suffix(direction=Suffix.IMPORT) # greatest variable upper bound
+model.senslblo = pyo.Suffix(
+ direction=pyo.Suffix.IMPORT
+) # smallest variable lower bound
+model.senslbhi = pyo.Suffix(
+ direction=pyo.Suffix.IMPORT
+) # greatest variable lower bound
+model.sensublo = pyo.Suffix(
+ direction=pyo.Suffix.IMPORT
+) # smallest variable upper bound
+model.sensubhi = pyo.Suffix(
+ direction=pyo.Suffix.IMPORT
+) # greatest variable upper bound
# A Gurobi constraint solution sensitivity suffix
-model.sensrhshi = Suffix(direction=Suffix.IMPORT) # greatest right-hand side value
+model.sensrhshi = pyo.Suffix(
+ direction=pyo.Suffix.IMPORT
+) # greatest right-hand side value
###
# Tell gurobi_ampl to report solution sensitivities
@@ -91,21 +99,21 @@
def print_model_suffixes(model):
# print all suffix values for all model components in a nice table
print("\t", end='')
- for name, suffix in active_import_suffix_generator(model):
+ for name, suffix in pyo.active_import_suffix_generator(model):
print("%10s" % (name), end='')
print("")
for i in model.s:
print(model.x[i].name + "\t", end='')
- for name, suffix in active_import_suffix_generator(model):
+ for name, suffix in pyo.active_import_suffix_generator(model):
print("%10s" % (suffix.get(model.x[i])), end='')
print("")
for i in model.s:
print(model.con[i].name + "\t", end='')
- for name, suffix in active_import_suffix_generator(model):
+ for name, suffix in pyo.active_import_suffix_generator(model):
print("%10s" % (suffix.get(model.con[i])), end='')
print("")
print(model.obj.name + "\t", end='')
- for name, suffix in active_import_suffix_generator(model):
+ for name, suffix in pyo.active_import_suffix_generator(model):
print("%10s" % (suffix.get(model.obj)), end='')
print("")
print("")
diff --git a/examples/pyomo/suffixes/gurobi_ampl_iis.py b/examples/pyomo/suffixes/gurobi_ampl_iis.py
index da5bad073e7..46d6e8304aa 100644
--- a/examples/pyomo/suffixes/gurobi_ampl_iis.py
+++ b/examples/pyomo/suffixes/gurobi_ampl_iis.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -21,16 +21,14 @@
# on this system. This example was tested using Gurobi
# Solver 5.0.0
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the gurobi_ampl solver plugin using the ASL interface
solver = 'gurobi_ampl'
solver_io = 'nl'
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
@@ -48,15 +46,15 @@
opt.options['iisfind'] = 1 # tell gurobi to be verbose with output
### Create a trivial and infeasible example model
-model = ConcreteModel()
-model.x = Var(within=NonNegativeReals)
-model.obj = Objective(expr=model.x)
-model.con = Constraint(expr=model.x <= -1)
+model = pyo.ConcreteModel()
+model.x = pyo.Var(within=pyo.NonNegativeReals)
+model.obj = pyo.Objective(expr=model.x)
+model.con = pyo.Constraint(expr=model.x <= -1)
###
# Create an IMPORT Suffix to store the iis information that will
# be returned by gurobi_ampl
-model.iis = Suffix(direction=Suffix.IMPORT)
+model.iis = pyo.Suffix(direction=pyo.Suffix.IMPORT)
### Send the model to gurobi_ampl and collect the solution
# The solver plugin will scan the model for all active suffixes
diff --git a/examples/pyomo/suffixes/ipopt_scaling.py b/examples/pyomo/suffixes/ipopt_scaling.py
index 7113128c21d..7685c287ad4 100644
--- a/examples/pyomo/suffixes/ipopt_scaling.py
+++ b/examples/pyomo/suffixes/ipopt_scaling.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -19,16 +19,14 @@
# on this system. This example was tested using Ipopt
# version 3.10.2
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the ipopt solver plugin using the ASL interface
solver = 'ipopt'
solver_io = 'nl'
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
@@ -45,23 +43,23 @@
###
### Create the example model
-model = ConcreteModel()
-model.s = Set(initialize=[1, 2, 3])
-model.y = Var(bounds=(1, 5), initialize=1.0)
-model.x = Var(model.s, bounds=(1, 5), initialize=5.0)
-model.obj = Objective(
+model = pyo.ConcreteModel()
+model.s = pyo.Set(initialize=[1, 2, 3])
+model.y = pyo.Var(bounds=(1, 5), initialize=1.0)
+model.x = pyo.Var(model.s, bounds=(1, 5), initialize=5.0)
+model.obj = pyo.Objective(
expr=model.y * model.x[3] * (model.y + model.x[1] + model.x[2]) + model.x[2]
)
-model.inequality = Constraint(
+model.inequality = pyo.Constraint(
expr=model.y * model.x[1] * model.x[2] * model.x[3] >= 25.0
)
-model.equality = Constraint(
+model.equality = pyo.Constraint(
expr=model.y**2 + model.x[1] ** 2 + model.x[2] ** 2 + model.x[3] ** 2 == 40.0
)
###
### Declare the scaling_factor suffix
-model.scaling_factor = Suffix(direction=Suffix.EXPORT)
+model.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)
# set objective scaling factor
model.scaling_factor[model.obj] = 4.23
# set variable scaling factor
diff --git a/examples/pyomo/suffixes/ipopt_warmstart.py b/examples/pyomo/suffixes/ipopt_warmstart.py
index 4882c48c8c8..a8ade973004 100644
--- a/examples/pyomo/suffixes/ipopt_warmstart.py
+++ b/examples/pyomo/suffixes/ipopt_warmstart.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -23,16 +23,14 @@
# on this system. This example was tested using Ipopt
# version 3.10.2
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the ipopt solver plugin using the ASL interface
solver = 'ipopt'
solver_io = 'nl'
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
if opt is None:
print("")
@@ -45,29 +43,31 @@
###
### Create the example model
-model = ConcreteModel()
-model.x1 = Var(bounds=(1, 5), initialize=1.0)
-model.x2 = Var(bounds=(1, 5), initialize=5.0)
-model.x3 = Var(bounds=(1, 5), initialize=5.0)
-model.x4 = Var(bounds=(1, 5), initialize=1.0)
-model.obj = Objective(
+model = pyo.ConcreteModel()
+model.x1 = pyo.Var(bounds=(1, 5), initialize=1.0)
+model.x2 = pyo.Var(bounds=(1, 5), initialize=5.0)
+model.x3 = pyo.Var(bounds=(1, 5), initialize=5.0)
+model.x4 = pyo.Var(bounds=(1, 5), initialize=1.0)
+model.obj = pyo.Objective(
expr=model.x1 * model.x4 * (model.x1 + model.x2 + model.x3) + model.x3
)
-model.inequality = Constraint(expr=model.x1 * model.x2 * model.x3 * model.x4 >= 25.0)
-model.equality = Constraint(
+model.inequality = pyo.Constraint(
+ expr=model.x1 * model.x2 * model.x3 * model.x4 >= 25.0
+)
+model.equality = pyo.Constraint(
expr=model.x1**2 + model.x2**2 + model.x3**2 + model.x4**2 == 40.0
)
###
### Declare all suffixes
# Ipopt bound multipliers (obtained from solution)
-model.ipopt_zL_out = Suffix(direction=Suffix.IMPORT)
-model.ipopt_zU_out = Suffix(direction=Suffix.IMPORT)
+model.ipopt_zL_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.ipopt_zU_out = pyo.Suffix(direction=pyo.Suffix.IMPORT)
# Ipopt bound multipliers (sent to solver)
-model.ipopt_zL_in = Suffix(direction=Suffix.EXPORT)
-model.ipopt_zU_in = Suffix(direction=Suffix.EXPORT)
+model.ipopt_zL_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.ipopt_zU_in = pyo.Suffix(direction=pyo.Suffix.EXPORT)
# Obtain dual solutions from first solve and send to warm start
-model.dual = Suffix(direction=Suffix.IMPORT_EXPORT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)
###
### Send the model to ipopt and collect the solution
@@ -80,7 +80,8 @@
print(" %7s %12s %12s" % ("Value", "ipopt_zL_out", "ipopt_zU_out"))
for v in [model.x1, model.x2, model.x3, model.x4]:
print(
- "%s %7g %12g %12g" % (v, value(v), model.ipopt_zL_out[v], model.ipopt_zU_out[v])
+ "%s %7g %12g %12g"
+ % (v, pyo.value(v), model.ipopt_zL_out[v], model.ipopt_zU_out[v])
)
print("inequality.dual = " + str(model.dual[model.inequality]))
print("equality.dual = " + str(model.dual[model.equality]))
@@ -112,7 +113,8 @@
print(" %7s %12s %12s" % ("Value", "ipopt_zL_out", "ipopt_zU_out"))
for v in [model.x1, model.x2, model.x3, model.x4]:
print(
- "%s %7g %12g %12g" % (v, value(v), model.ipopt_zL_out[v], model.ipopt_zU_out[v])
+ "%s %7g %12g %12g"
+ % (v, pyo.value(v), model.ipopt_zL_out[v], model.ipopt_zU_out[v])
)
print("inequality.dual = " + str(model.dual[model.inequality]))
print("equality.dual = " + str(model.dual[model.equality]))
diff --git a/examples/pyomo/suffixes/sipopt_hicks.py b/examples/pyomo/suffixes/sipopt_hicks.py
index c7e058d5907..bb543bbf2ca 100644
--- a/examples/pyomo/suffixes/sipopt_hicks.py
+++ b/examples/pyomo/suffixes/sipopt_hicks.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -23,16 +23,14 @@
# are the numpy and matplotlib python modules (needed for
# viewing results).
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the ipopt_sens solver plugin using the ASL interface
solver = 'ipopt_sens'
solver_io = 'nl'
stream_solver = False # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
###
if opt is None:
@@ -69,26 +67,26 @@
yc = tc / (jj * cf)
yf = tf / (jj * cf)
-model = ConcreteModel()
-model.c_init_var = Var()
-model.t_init_var = Var()
-model.cdot = Var(FE, CP)
-model.tdot = Var(FE, CP)
+model = pyo.ConcreteModel()
+model.c_init_var = pyo.Var()
+model.t_init_var = pyo.Var()
+model.cdot = pyo.Var(FE, CP)
+model.tdot = pyo.Var(FE, CP)
def c_init_rule(m, i, j):
return float(i) / nfe * (c_des - c_init) + c_init
-model.c = Var(FE, CP, within=NonNegativeReals, initialize=c_init_rule)
+model.c = pyo.Var(FE, CP, within=pyo.NonNegativeReals, initialize=c_init_rule)
def t_init_rule(m, i, j):
return float(i) / nfe * (t_des - t_init) + t_init
-model.t = Var(FE, CP, within=NonNegativeReals, initialize=t_init_rule)
-model.u = Var(FE, within=NonNegativeReals, initialize=1.0)
+model.t = pyo.Var(FE, CP, within=pyo.NonNegativeReals, initialize=t_init_rule)
+model.u = pyo.Var(FE, within=pyo.NonNegativeReals, initialize=1.0)
a_init = {}
a_init[0, 0] = 0.19681547722366
@@ -101,7 +99,7 @@ def t_init_rule(m, i, j):
a_init[2, 1] = -0.04154875212600
a_init[2, 2] = 0.11111111111111
-model.a = Param(FE, CP, initialize=a_init)
+model.a = pyo.Param(FE, CP, initialize=a_init)
h = [1.0 / nfe] * nfe
@@ -109,20 +107,20 @@ def t_init_rule(m, i, j):
def cdot_ode_rule(m, i, j):
return (
m.cdot[i, j]
- == (1.0 - m.c[i, j]) / theta - k10 * exp(-n / m.t[i, j]) * m.c[i, j]
+ == (1.0 - m.c[i, j]) / theta - k10 * pyo.exp(-n / m.t[i, j]) * m.c[i, j]
)
-model.cdot_ode = Constraint(FE, CP, rule=cdot_ode_rule)
+model.cdot_ode = pyo.Constraint(FE, CP, rule=cdot_ode_rule)
def tdot_ode_rule(m, i, j):
- return m.tdot[i, j] == (yf - m.t[i, j]) / theta + k10 * exp(-n / m.t[i, j]) * m.c[
- i, j
- ] - alpha * m.u[i] * (m.t[i, j] - yc)
+ return m.tdot[i, j] == (yf - m.t[i, j]) / theta + k10 * pyo.exp(
+ -n / m.t[i, j]
+ ) * m.c[i, j] - alpha * m.u[i] * (m.t[i, j] - yc)
-model.tdot_ode = Constraint(FE, CP, rule=tdot_ode_rule)
+model.tdot_ode = pyo.Constraint(FE, CP, rule=tdot_ode_rule)
def fecolc_rule(m, i, j):
@@ -136,9 +134,9 @@ def fecolc_rule(m, i, j):
)
-model.fecolc = Constraint(FE, CP, rule=fecolc_rule)
-model.c_init_def = Constraint(expr=model.c_init_var == c_init)
-model.t_init_def = Constraint(expr=model.t_init_var == t_init)
+model.fecolc = pyo.Constraint(FE, CP, rule=fecolc_rule)
+model.c_init_def = pyo.Constraint(expr=model.c_init_var == c_init)
+model.t_init_def = pyo.Constraint(expr=model.t_init_var == t_init)
def fecolt_rule(m, i, j):
@@ -152,7 +150,7 @@ def fecolt_rule(m, i, j):
)
-model.fecolt = Constraint(FE, CP, rule=fecolt_rule)
+model.fecolt = pyo.Constraint(FE, CP, rule=fecolt_rule)
def obj_rule(m):
@@ -189,15 +187,15 @@ def obj_rule(m):
)
-model.cost = Objective(rule=obj_rule)
+model.cost = pyo.Objective(rule=obj_rule)
###
### declare suffixes
-model.sens_state_0 = Suffix(direction=Suffix.EXPORT)
-model.sens_state_1 = Suffix(direction=Suffix.EXPORT)
-model.sens_state_value_1 = Suffix(direction=Suffix.EXPORT)
-model.sens_sol_state_1 = Suffix(direction=Suffix.IMPORT)
-model.sens_init_constr = Suffix(direction=Suffix.EXPORT)
+model.sens_state_0 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_state_1 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_state_value_1 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_sol_state_1 = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.sens_init_constr = pyo.Suffix(direction=pyo.Suffix.EXPORT)
###
### set sIPOPT data
@@ -252,10 +250,10 @@ def collocation_idx(n_fe, n_cp):
tnominal = np.zeros((nfe * ncp, 1))
tperturbed = np.zeros((nfe * ncp, 1))
for k, (i, j) in enumerate(collocation_idx(nfe, ncp)):
- cnominal[k] = value(model.c[i, j])
- tnominal[k] = value(model.t[i, j])
- cperturbed[k] = value(model.sens_sol_state_1[model.c[i, j]])
- tperturbed[k] = value(model.sens_sol_state_1[model.t[i, j]])
+ cnominal[k] = pyo.value(model.c[i, j])
+ tnominal[k] = pyo.value(model.t[i, j])
+ cperturbed[k] = pyo.value(model.sens_sol_state_1[model.c[i, j]])
+ tperturbed[k] = pyo.value(model.sens_sol_state_1[model.t[i, j]])
plt.subplot(2, 1, 1)
plt.plot(times, cnominal, label='c_nominal')
diff --git a/examples/pyomo/suffixes/sipopt_parametric.py b/examples/pyomo/suffixes/sipopt_parametric.py
index 0cb1c35f441..c51486011ba 100644
--- a/examples/pyomo/suffixes/sipopt_parametric.py
+++ b/examples/pyomo/suffixes/sipopt_parametric.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -21,16 +21,14 @@
# solver (distributed with Ipopt) is in the current search
# path for executables on this system.
-import pyomo.environ
-from pyomo.core import *
-from pyomo.opt import SolverFactory
+import pyomo.environ as pyo
### Create the ipopt_sens solver plugin using the ASL interface
solver = 'ipopt_sens'
solver_io = 'nl'
stream_solver = True # True prints solver output to screen
keepfiles = False # True prints intermediate file names (.nl,.sol,...)
-opt = SolverFactory(solver, solver_io=solver_io)
+opt = pyo.SolverFactory(solver, solver_io=solver_io)
###
if opt is None:
@@ -46,30 +44,30 @@
perturbed_eta2 = 1.0
### Create the model
-model = ConcreteModel()
+model = pyo.ConcreteModel()
# variables
-model.x1 = Var(initialize=0.15, within=NonNegativeReals)
-model.x2 = Var(initialize=0.15, within=NonNegativeReals)
-model.x3 = Var(initialize=0.0, within=NonNegativeReals)
+model.x1 = pyo.Var(initialize=0.15, within=pyo.NonNegativeReals)
+model.x2 = pyo.Var(initialize=0.15, within=pyo.NonNegativeReals)
+model.x3 = pyo.Var(initialize=0.0, within=pyo.NonNegativeReals)
# parameters
-model.eta1 = Var()
-model.eta2 = Var()
+model.eta1 = pyo.Var()
+model.eta2 = pyo.Var()
# constraints + objective
-model.const1 = Constraint(
+model.const1 = pyo.Constraint(
expr=6 * model.x1 + 3 * model.x2 + 2 * model.x3 - model.eta1 == 0
)
-model.const2 = Constraint(expr=model.eta2 * model.x1 + model.x2 - model.x3 - 1 == 0)
-model.cost = Objective(expr=model.x1**2 + model.x2**2 + model.x3**2)
-model.consteta1 = Constraint(expr=model.eta1 == nominal_eta1)
-model.consteta2 = Constraint(expr=model.eta2 == nominal_eta2)
+model.const2 = pyo.Constraint(expr=model.eta2 * model.x1 + model.x2 - model.x3 - 1 == 0)
+model.cost = pyo.Objective(expr=model.x1**2 + model.x2**2 + model.x3**2)
+model.consteta1 = pyo.Constraint(expr=model.eta1 == nominal_eta1)
+model.consteta2 = pyo.Constraint(expr=model.eta2 == nominal_eta2)
###
### declare suffixes
-model.sens_state_0 = Suffix(direction=Suffix.EXPORT)
-model.sens_state_1 = Suffix(direction=Suffix.EXPORT)
-model.sens_state_value_1 = Suffix(direction=Suffix.EXPORT)
-model.sens_sol_state_1 = Suffix(direction=Suffix.IMPORT)
-model.sens_init_constr = Suffix(direction=Suffix.EXPORT)
+model.sens_state_0 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_state_1 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_state_value_1 = pyo.Suffix(direction=pyo.Suffix.EXPORT)
+model.sens_sol_state_1 = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.sens_init_constr = pyo.Suffix(direction=pyo.Suffix.EXPORT)
###
### set sIPOPT data
@@ -91,5 +89,5 @@
### Print Solution
print("Nominal and perturbed solution:")
for v in [model.x1, model.x2, model.x3, model.eta1, model.eta2]:
- print("%5s %14g %14g" % (v, value(v), model.sens_sol_state_1[v]))
+ print("%5s %14g %14g" % (v, pyo.value(v), model.sens_sol_state_1[v]))
###
diff --git a/examples/pyomo/transform/scaling_ex.py b/examples/pyomo/transform/scaling_ex.py
index 34f937cbb45..8ef768de988 100644
--- a/examples/pyomo/transform/scaling_ex.py
+++ b/examples/pyomo/transform/scaling_ex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,19 +9,19 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-import pyomo.environ as pe
+import pyomo.environ as pyo
###
# create the original unscaled model
###
-model = pe.ConcreteModel()
-model.x = pe.Var([1, 2, 3], bounds=(-10, 10), initialize=5.0)
-model.z = pe.Var(bounds=(10, 20))
-model.obj = pe.Objective(expr=model.z + model.x[1])
+model = pyo.ConcreteModel()
+model.x = pyo.Var([1, 2, 3], bounds=(-10, 10), initialize=5.0)
+model.z = pyo.Var(bounds=(10, 20))
+model.obj = pyo.Objective(expr=model.z + model.x[1])
# demonstrate scaling of duals as well
-model.dual = pe.Suffix(direction=pe.Suffix.IMPORT)
-model.rc = pe.Suffix(direction=pe.Suffix.IMPORT)
+model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
+model.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
def con_rule(m, i):
@@ -33,13 +33,13 @@ def con_rule(m, i):
return m.x[1] + 3.0 * m.x[2] + 1 * m.x[3] == 5.0
-model.con = pe.Constraint([1, 2, 3], rule=con_rule)
-model.zcon = pe.Constraint(expr=model.z >= model.x[2])
+model.con = pyo.Constraint([1, 2, 3], rule=con_rule)
+model.zcon = pyo.Constraint(expr=model.z >= model.x[2])
###
# set the scaling parameters
###
-model.scaling_factor = pe.Suffix(direction=pe.Suffix.EXPORT)
+model.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT)
model.scaling_factor[model.obj] = 2.0
model.scaling_factor[model.x] = 0.5
model.scaling_factor[model.z] = -10.0
@@ -51,14 +51,14 @@ def con_rule(m, i):
###
# build and solve the scaled model
###
-scaled_model = pe.TransformationFactory('core.scale_model').create_using(model)
-pe.SolverFactory('glpk').solve(scaled_model)
+scaled_model = pyo.TransformationFactory('core.scale_model').create_using(model)
+pyo.SolverFactory('glpk').solve(scaled_model)
###
# propagate the solution back to the original model
###
-pe.TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)
+pyo.TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)
# print the scaled model
scaled_model.pprint()
@@ -73,12 +73,12 @@ def con_rule(m, i):
# solve the original (unscaled) model
original_model = model.clone()
- pe.SolverFactory('glpk').solve(original_model)
+ pyo.SolverFactory('glpk').solve(original_model)
# create and solve the scaled model
- scaling_tx = pe.TransformationFactory('core.scale_model')
+ scaling_tx = pyo.TransformationFactory('core.scale_model')
scaled_model = scaling_tx.create_using(model)
- pe.SolverFactory('glpk').solve(scaled_model)
+ pyo.SolverFactory('glpk').solve(scaled_model)
# propagate the solution from the scaled model back to a clone of the original model
backmapped_unscaled_model = model.clone()
@@ -88,8 +88,8 @@ def con_rule(m, i):
print('\n\n')
print('%s\t%12s %18s' % ('Var', 'Orig.', 'Scaled -> Backmapped'))
print('=====================================================')
- for v in original_model.component_data_objects(ctype=pe.Var, descend_into=True):
- cuid = pe.ComponentUID(v)
+ for v in original_model.component_data_objects(ctype=pyo.Var, descend_into=True):
+ cuid = pyo.ComponentUID(v)
bv = cuid.find_component_on(backmapped_unscaled_model)
- print('%s\t%.16f\t%.16f' % (v.local_name, pe.value(v), pe.value(bv)))
+ print('%s\t%.16f\t%.16f' % (v.local_name, pyo.value(v), pyo.value(bv)))
print('=====================================================')
diff --git a/examples/pyomo/tutorials/data.py b/examples/pyomo/tutorials/data.py
index ea2569af934..7db01fa9f19 100644
--- a/examples/pyomo/tutorials/data.py
+++ b/examples/pyomo/tutorials/data.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
##
## Using a Model
@@ -23,7 +23,7 @@
# declaration of model components (e.g. sets and variables), and to
# generate a problem instance.
#
-model = AbstractModel()
+model = pyo.AbstractModel()
##
## Declaring Sets
@@ -31,11 +31,11 @@
#
# An unordered set of arbitrary objects
#
-model.A = Set()
+model.A = pyo.Set()
#
# An unordered set of numeric values
#
-model.B = Set()
+model.B = pyo.Set()
#
# A simple cross-product
#
@@ -43,36 +43,36 @@
#
# A simple cross-product loaded with a tabular data format
#
-model.D = Set(within=model.A * model.B)
+model.D = pyo.Set(within=model.A * model.B)
#
# A multiple cross-product
#
-model.E = Set(within=model.A * model.B * model.A)
+model.E = pyo.Set(within=model.A * model.B * model.A)
#
# An indexed set
#
-model.F = Set(model.A)
+model.F = pyo.Set(model.A)
#
# An indexed set
#
-model.G = Set(model.A, model.B)
+model.G = pyo.Set(model.A, model.B)
#
# A simple set
#
-model.H = Set()
+model.H = pyo.Set()
#
# A simple set
#
-model.I = Set()
+model.I = pyo.Set()
#
# A two-dimensional set
#
-model.J = Set(dimen=2)
+model.J = pyo.Set(dimen=2)
#
# A two-dimensional set
#
-model.K = Set(dimen=2)
+model.K = pyo.Set(dimen=2)
##
## Declaring Params
@@ -81,49 +81,49 @@
#
# A simple parameter
#
-model.Z = Param()
-model.ZZ = Param()
+model.Z = pyo.Param()
+model.ZZ = pyo.Param()
#
# A single-dimension parameter
#
-model.Y = Param(model.A)
+model.Y = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together
#
-model.X = Param(model.A)
-model.W = Param(model.A)
+model.X = pyo.Param(model.A)
+model.W = pyo.Param(model.A)
#
# Initializing a parameter with two indices
#
-model.U = Param(model.I, model.A)
-model.T = Param(model.A, model.I)
+model.U = pyo.Param(model.I, model.A)
+model.T = pyo.Param(model.A, model.I)
#
# Initializing a parameter with missing data
#
-model.S = Param(model.A)
+model.S = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together with
# an index set
#
-model.R = Param(model.H, within=Reals)
-model.Q = Param(model.H, within=Reals)
+model.R = pyo.Param(model.H, within=pyo.Reals)
+model.Q = pyo.Param(model.H, within=pyo.Reals)
#
# An example of initializing parameters with a two-dimensional index set
#
-model.P = Param(model.J, within=Reals)
-model.PP = Param(model.J, within=Reals)
-model.O = Param(model.J, within=Reals)
+model.P = pyo.Param(model.J, within=pyo.Reals)
+model.PP = pyo.Param(model.J, within=pyo.Reals)
+model.O = pyo.Param(model.J, within=pyo.Reals)
-model.z = Set(dimen=2)
-model.y = Set()
-model.x = Set()
+model.z = pyo.Set(dimen=2)
+model.y = pyo.Set()
+model.x = pyo.Set()
-model.M = Param(model.K, within=Reals)
-model.N = Param(model.y, within=Reals)
+model.M = pyo.Param(model.K, within=pyo.Reals)
+model.N = pyo.Param(model.y, within=pyo.Reals)
-model.MM = Param(model.z)
-model.MMM = Param(model.z)
-model.NNN = Param(model.x)
+model.MM = pyo.Param(model.z)
+model.MMM = pyo.Param(model.z)
+model.NNN = pyo.Param(model.x)
##
## Process an input file and confirm that we get appropriate
diff --git a/examples/pyomo/tutorials/excel.py b/examples/pyomo/tutorials/excel.py
index f9a5f66826b..22b9a5360ee 100644
--- a/examples/pyomo/tutorials/excel.py
+++ b/examples/pyomo/tutorials/excel.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
##
## Using a Model
@@ -23,7 +23,7 @@
# declaration of model components (e.g. sets and variables), and to
# generate a problem instance.
#
-model = AbstractModel()
+model = pyo.AbstractModel()
##
## Declaring Sets
@@ -31,11 +31,11 @@
#
# An unordered set of arbitrary objects
#
-model.A = Set()
+model.A = pyo.Set()
#
# An unordered set of numeric values
#
-model.B = Set()
+model.B = pyo.Set()
#
# A simple cross-product
#
@@ -43,32 +43,32 @@
#
# A simple cross-product loaded with a tabular data format
#
-model.D = Set(within=model.A * model.B)
+model.D = pyo.Set(within=model.A * model.B)
#
# A multiple cross-product
#
-model.E = Set(within=model.A * model.B * model.A)
+model.E = pyo.Set(within=model.A * model.B * model.A)
#
# An indexed set
#
-model.F = Set(model.A)
+model.F = pyo.Set(model.A)
#
# An indexed set
#
-model.G = Set(model.A, model.B)
+model.G = pyo.Set(model.A, model.B)
#
# A simple set
#
-model.H = Set()
+model.H = pyo.Set()
#
# A simple set
#
-model.I = Set()
+model.I = pyo.Set()
#
# A two-dimensional set
#
-model.J = Set(dimen=2)
+model.J = pyo.Set(dimen=2)
##
## Declaring Params
@@ -77,37 +77,37 @@
#
# A simple parameter
#
-model.Z = Param()
+model.Z = pyo.Param()
#
# A single-dimension parameter
#
-model.Y = Param(model.A)
+model.Y = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together
#
-model.X = Param(model.A)
-model.W = Param(model.A)
+model.X = pyo.Param(model.A)
+model.W = pyo.Param(model.A)
#
# Initializing a parameter with two indices
#
-model.U = Param(model.I, model.A)
-model.T = Param(model.A, model.I)
+model.U = pyo.Param(model.I, model.A)
+model.T = pyo.Param(model.A, model.I)
#
# Initializing a parameter with missing data
#
-model.S = Param(model.A)
+model.S = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together with
# an index set
#
-model.R = Param(model.H, within=Reals)
-model.Q = Param(model.H, within=Reals)
+model.R = pyo.Param(model.H, within=pyo.Reals)
+model.Q = pyo.Param(model.H, within=pyo.Reals)
#
# An example of initializing parameters with a two-dimensional index set
#
-model.P = Param(model.J, within=Reals)
-model.PP = Param(model.J, within=Reals)
-model.O = Param(model.J, within=Reals)
+model.P = pyo.Param(model.J, within=pyo.Reals)
+model.PP = pyo.Param(model.J, within=pyo.Reals)
+model.O = pyo.Param(model.J, within=pyo.Reals)
##
## Process an input file and confirm that we get appropriate
@@ -115,7 +115,7 @@
##
# model.pprint()
-data = DataPortal(model=model)
+data = pyo.DataPortal(model=model)
data.load(filename="excel.xls", range="Atable", format='set', set='A')
data.load(filename="excel.xls", range="Btable", format='set', set='B')
data.load(filename="excel.xls", range="Ctable", format='set', set='C')
diff --git a/examples/pyomo/tutorials/param.py b/examples/pyomo/tutorials/param.py
index 5a94bafaa5e..375943d25c3 100644
--- a/examples/pyomo/tutorials/param.py
+++ b/examples/pyomo/tutorials/param.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
##
## Setting up a Model
@@ -20,12 +20,12 @@
#
# Create the model
#
-model = AbstractModel()
+model = pyo.AbstractModel()
#
# Create sets used to define parameters
#
-model.A = Set()
-model.B = Set()
+model.A = pyo.Set()
+model.B = pyo.Set()
##
## Declaring Params
@@ -34,15 +34,15 @@
#
# A simple parameter
#
-model.Z = Param()
+model.Z = pyo.Param()
#
# A single-dimension parameter
#
-model.Y = Param(model.A)
+model.Y = pyo.Param(model.A)
#
# Initializing a parameter with two indices
#
-model.X = Param(model.A, model.B)
+model.X = pyo.Param(model.A, model.B)
##
@@ -60,7 +60,7 @@ def W_init(model, i, j):
return i * j
-model.W = Param(model.A, model.B, initialize=W_init)
+model.W = pyo.Param(model.A, model.B, initialize=W_init)
#
# Note that the parameter model.W is not created when this object is
# constructed. Instead, W_init() is called during the construction of a
@@ -74,19 +74,19 @@ def W_init(model, i, j):
V_init[1] = 1
V_init[2] = 2
V_init[3] = 9
-model.V = Param(model.B, initialize=V_init)
+model.V = pyo.Param(model.B, initialize=V_init)
#
# Note that parameter V is initialized with a dictionary, which maps
# tuples from parameter indices to parameter values. Simple, unindexed
# parameters can be initialized with a scalar value.
#
-model.U = Param(initialize=9.9)
+model.U = pyo.Param(initialize=9.9)
#
# Validation of parameter data is supported in two different ways. First,
# the domain of feasible parameter values can be specified with the _within_
# option:
#
-model.T = Param(within=model.B)
+model.T = pyo.Param(within=model.B)
#
@@ -100,7 +100,7 @@ def S_validate(model, value):
return value in model.A
-model.S = Param(validate=S_validate)
+model.S = pyo.Param(validate=S_validate)
##
## Default Values
@@ -120,7 +120,7 @@ def S_validate(model, value):
R_init[2, 1] = 1
R_init[2, 2] = 1
R_init[2, 3] = 1
-model.R = Param(model.A, model.B, default=99.0, initialize=R_init)
+model.R = pyo.Param(model.A, model.B, default=99.0, initialize=R_init)
#
# Note that the parameter default value can also be specified in an input
# file. See data.dat for an example.
@@ -128,8 +128,8 @@ def S_validate(model, value):
# Note that the explicit specification of a zero default changes Pyomo
# behavior. For example, consider:
#
-# model.a = Param(model.A, default=0.0)
-# model.b = Param(model.A)
+# model.a = pyo.Param(model.A, default=0.0)
+# model.b = pyo.Param(model.A)
#
# When model.a[x] is accessed and the index has not been explicitly initialized,
# the value zero is returned. This is true whether or not the parameter has
diff --git a/examples/pyomo/tutorials/set.dat b/examples/pyomo/tutorials/set.dat
index ab0d00b43cc..16ad7ff9698 100644
--- a/examples/pyomo/tutorials/set.dat
+++ b/examples/pyomo/tutorials/set.dat
@@ -16,3 +16,10 @@ set S[5] := 2 3;
set T[2] := 1 3;
set T[5] := 2 3;
+
+set T_indexed_validate[2] := 1;
+set T_indexed_validate[3] := 1 2;
+set T_indexed_validate[4] := 1 2 3;
+
+set X[2] := 1;
+set X[5] := 2 3;
diff --git a/examples/pyomo/tutorials/set.out b/examples/pyomo/tutorials/set.out
index 818977f6155..3f278a2f9b2 100644
--- a/examples/pyomo/tutorials/set.out
+++ b/examples/pyomo/tutorials/set.out
@@ -1,4 +1,4 @@
-23 Set Declarations
+25 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
@@ -80,6 +80,11 @@
Key : Dimen : Domain : Size : Members
2 : 1 : Any : 2 : {1, 3}
5 : 1 : Any : 2 : {2, 3}
+ T_indexed_validate : Size=3, Index=B, Ordered=Insertion
+ Key : Dimen : Domain : Size : Members
+ 2 : 1 : Any : 1 : {1,}
+ 3 : 1 : Any : 2 : {1, 2}
+ 4 : 1 : Any : 3 : {1, 2, 3}
U : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 5 : {1, 2, 6, 24, 120}
@@ -89,5 +94,9 @@
2 : 1 : Any : 5 : {1, 3, 5, 7, 9}
3 : 1 : Any : 5 : {1, 4, 7, 10, 13}
4 : 1 : Any : 5 : {1, 5, 9, 13, 17}
+ X : Size=2, Index=B, Ordered=Insertion
+ Key : Dimen : Domain : Size : Members
+ 2 : 1 : S[2] : 1 : {1,}
+ 5 : 1 : S[5] : 2 : {2, 3}
-23 Declarations: A B C D E F G H Hsub I J K K_2 L M N O P R S T U V
+25 Declarations: A B C D E F G H Hsub I J K K_2 L M N O P R S X T T_indexed_validate U V
diff --git a/examples/pyomo/tutorials/set.py b/examples/pyomo/tutorials/set.py
index a14301484c9..e6d380cc23d 100644
--- a/examples/pyomo/tutorials/set.py
+++ b/examples/pyomo/tutorials/set.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,12 +12,12 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
##
## Creating a model
##
-model = AbstractModel()
+model = pyo.AbstractModel()
##
## Declaring Sets
@@ -26,13 +26,13 @@
# An unordered set of arbitrary objects can be defined by creating a Set()
# object:
#
-model.A = Set()
+model.A = pyo.Set()
#
# An index set of sets can also be specified by providing sets as options
-# to the Set() object:
+# to the pyo.Set() object:
#
-model.B = Set()
-model.C = Set(model.A, model.B)
+model.B = pyo.Set()
+model.C = pyo.Set(model.A, model.B)
#
# Set declarations can also use standard set operations to declare
# a set in a constructive fashion:
@@ -49,7 +49,7 @@
# Note that this is different from the following, which specifies that Hsub
# is a subset of this cross-product.
#
-model.Hsub = Set(within=model.A * model.B)
+model.Hsub = pyo.Set(within=model.A * model.B)
##
@@ -68,7 +68,7 @@ def I_init(model):
return ans
-model.I = Set(within=model.A * model.B, initialize=I_init)
+model.I = pyo.Set(within=model.A * model.B, initialize=I_init)
#
# Note that the set model.I is not created when this set object is
# constructed. Instead, I_init() is called during the construction of a
@@ -76,7 +76,7 @@ def I_init(model):
#
# A set can also be explicitly constructed by adding set elements:
#
-model.J = Set()
+model.J = pyo.Set()
model.J.construct()
model.J.add(1, 4, 9)
#
@@ -84,13 +84,13 @@ def I_init(model):
# a set. These default values may be overridden by later construction
# steps, or by data in an input file:
#
-model.K = Set(initialize=[1, 4, 9])
-model.K_2 = Set(initialize=[(1, 4), (9, 16)], dimen=2)
+model.K = pyo.Set(initialize=[1, 4, 9])
+model.K_2 = pyo.Set(initialize=[(1, 4), (9, 16)], dimen=2)
#
# Validation of set data is supported in two different ways. First, a
# superset can be specified with the _within_ option:
#
-model.L = Set(within=model.A)
+model.L = pyo.Set(within=model.A)
#
@@ -101,12 +101,12 @@ def M_validate(model, value):
return value in model.A
-model.M = Set(validate=M_validate)
+model.M = pyo.Set(validate=M_validate)
#
# Although the _within_ option is convenient, it can force the creation of
# a temporary set. For example, consider the declaration
#
-model.N = Set(within=model.A * model.B)
+model.N = pyo.Set(within=model.A * model.B)
#
@@ -119,7 +119,7 @@ def O_validate(model, value):
return value[0] in model.A and value[1] in model.B
-model.O = Set(validate=O_validate)
+model.O = pyo.Set(validate=O_validate)
##
@@ -134,18 +134,18 @@ def P_init(model, i, j):
return range(0, i * j)
-model.P = Set(model.B, model.B, initialize=P_init)
+model.P = pyo.Set(model.B, model.B, initialize=P_init)
#
# A set array CANNOT be explicitly constructed by adding set elements
# to individual arrays. For example, the following is invalid:
#
-# model.Q = Set(model.B)
+# model.Q = pyo.Set(model.B)
# model.Q[2].add(4)
# model.Q[4].add(16)
#
# The reason is that the line
#
-# model.Q = Set(model.B)
+# model.Q = pyo.Set(model.B)
#
# declares set Q with an abstract index set B. However, B is not initialized
# until the 'model.create_instance()' call is executed at the end of this file. We
@@ -164,12 +164,19 @@ def P_init(model, i, j):
R_init[2] = [1, 3, 5]
R_init[3] = [2, 4, 6]
R_init[4] = [3, 5, 7]
-model.R = Set(model.B, initialize=R_init)
+model.R = pyo.Set(model.B, initialize=R_init)
#
# Validation of a set array is supported with the _within_ option. The
# elements of all sets in the array must be in this set:
#
-model.S = Set(model.B, within=model.A)
+model.S = pyo.Set(model.B, within=model.A)
+
+#
+# Validation of a set array can also be linked to another set array. If so, the
+# elements under each index must also be found under the corresponding index in
+# the validation set array:
+#
+model.X = pyo.Set(model.B, within=model.S)
#
@@ -180,7 +187,17 @@ def T_validate(model, value):
return value in model.A
-model.T = Set(model.B, validate=M_validate)
+model.T = pyo.Set(model.B, validate=T_validate)
+
+
+#
+# Validation also provides the index within the IndexedSet being validated:
+#
+def T_indexed_validate(model, value, i):
+ return value in model.A and value < i
+
+
+model.T_indexed_validate = pyo.Set(model.B, validate=T_indexed_validate)
##
@@ -198,14 +215,14 @@ def T_validate(model, value):
#
def U_init(model, z):
if z == 6:
- return Set.End
+ return pyo.Set.End
if z == 1:
return 1
else:
return model.U[z - 1] * z
-model.U = Set(ordered=True, initialize=U_init)
+model.U = pyo.Set(ordered=True, initialize=U_init)
#
@@ -217,13 +234,13 @@ def U_init(model, z):
#
def V_init(model, z, i):
if z == 6:
- return Set.End
+ return pyo.Set.End
if i == 1:
return z
return model.V[i - 1][z] + z - 1
-model.V = Set(RangeSet(1, 4), initialize=V_init, ordered=True)
+model.V = pyo.Set(pyo.RangeSet(1, 4), initialize=V_init, ordered=True)
##
## Process an input file and confirm that we get appropriate
diff --git a/examples/pyomo/tutorials/table.py b/examples/pyomo/tutorials/table.py
index 7d9fceda14a..75802fa98f5 100644
--- a/examples/pyomo/tutorials/table.py
+++ b/examples/pyomo/tutorials/table.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,7 @@
#
# Imports
#
-from pyomo.environ import *
+import pyomo.environ as pyo
##
## Using a Model
@@ -23,7 +23,7 @@
# declaration of model components (e.g. sets and variables), and to
# generate a problem instance.
#
-model = AbstractModel()
+model = pyo.AbstractModel()
##
## Declaring Sets
@@ -31,11 +31,11 @@
#
# An unordered set of arbitrary objects
#
-model.A = Set()
+model.A = pyo.Set()
#
# An unordered set of numeric values
#
-model.B = Set()
+model.B = pyo.Set()
#
# A simple cross-product
#
@@ -43,32 +43,32 @@
#
# A simple cross-product loaded with a tabular data format
#
-model.D = Set(within=model.A * model.B)
+model.D = pyo.Set(within=model.A * model.B)
#
# A multiple cross-product
#
-model.E = Set(within=model.A * model.B * model.A)
+model.E = pyo.Set(within=model.A * model.B * model.A)
#
# An indexed set
#
-model.F = Set(model.A)
+model.F = pyo.Set(model.A)
#
# An indexed set
#
-model.G = Set(model.A, model.B)
+model.G = pyo.Set(model.A, model.B)
#
# A simple set
#
-model.H = Set()
+model.H = pyo.Set()
#
# A simple set
#
-model.I = Set()
+model.I = pyo.Set()
#
# A two-dimensional set
#
-model.J = Set(dimen=2)
+model.J = pyo.Set(dimen=2)
##
## Declaring Params
@@ -77,43 +77,43 @@
#
# A simple parameter
#
-model.Z = Param()
+model.Z = pyo.Param()
#
# A single-dimension parameter
#
-model.Y = Param(model.A)
+model.Y = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together
#
-model.X = Param(model.A)
-model.W = Param(model.A)
+model.X = pyo.Param(model.A)
+model.W = pyo.Param(model.A)
#
# Initializing a parameter with two indices
#
-model.U = Param(model.I, model.A)
-model.T = Param(model.A, model.I)
+model.U = pyo.Param(model.I, model.A)
+model.T = pyo.Param(model.A, model.I)
#
# Initializing a parameter with missing data
#
-model.S = Param(model.A)
+model.S = pyo.Param(model.A)
#
# An example of initializing two single-dimension parameters together with
# an index set
#
-model.R = Param(model.H, within=Reals)
-model.Q = Param(model.H, within=Reals)
+model.R = pyo.Param(model.H, within=pyo.Reals)
+model.Q = pyo.Param(model.H, within=pyo.Reals)
#
# An example of initializing parameters with a two-dimensional index set
#
-model.P = Param(model.J, within=Reals)
-model.PP = Param(model.J, within=Reals)
-model.O = Param(model.J, within=Reals)
+model.P = pyo.Param(model.J, within=pyo.Reals)
+model.PP = pyo.Param(model.J, within=pyo.Reals)
+model.O = pyo.Param(model.J, within=pyo.Reals)
##
## Process an input file and confirm that we get appropriate
## set instances.
##
-data = DataPortal()
+data = pyo.DataPortal()
data.load(filename="tab/A.tab", format='set', set='A')
data.load(filename="tab/B.tab", format='set', set='B')
data.load(filename="tab/C.tab", format='set', set="C")
diff --git a/examples/pyomobook/__init__.py b/examples/pyomobook/__init__.py
index a4a626013c4..6eb9ea8b81d 100644
--- a/examples/pyomobook/__init__.py
+++ b/examples/pyomobook/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/AbstHLinScript.py b/examples/pyomobook/abstract-ch/AbstHLinScript.py
index 687d3fc4e6b..118f77e811c 100644
--- a/examples/pyomobook/abstract-ch/AbstHLinScript.py
+++ b/examples/pyomobook/abstract-ch/AbstHLinScript.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/AbstractH.py b/examples/pyomobook/abstract-ch/AbstractH.py
index 7595cbc4933..69f308fecfd 100644
--- a/examples/pyomobook/abstract-ch/AbstractH.py
+++ b/examples/pyomobook/abstract-ch/AbstractH.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/AbstractHLinear.py b/examples/pyomobook/abstract-ch/AbstractHLinear.py
index f312020a9d5..67eecb24b7a 100644
--- a/examples/pyomobook/abstract-ch/AbstractHLinear.py
+++ b/examples/pyomobook/abstract-ch/AbstractHLinear.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/abstract5.py b/examples/pyomobook/abstract-ch/abstract5.py
index 8849d2dfe7f..6f558dabf00 100644
--- a/examples/pyomobook/abstract-ch/abstract5.py
+++ b/examples/pyomobook/abstract-ch/abstract5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/abstract6.py b/examples/pyomobook/abstract-ch/abstract6.py
index 121b12a51fa..9c8d401049c 100644
--- a/examples/pyomobook/abstract-ch/abstract6.py
+++ b/examples/pyomobook/abstract-ch/abstract6.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/abstract7.py b/examples/pyomobook/abstract-ch/abstract7.py
index 3e8131bf42b..fabf13b56ec 100644
--- a/examples/pyomobook/abstract-ch/abstract7.py
+++ b/examples/pyomobook/abstract-ch/abstract7.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/buildactions.py b/examples/pyomobook/abstract-ch/buildactions.py
index 6963f285c4c..54b3db441e9 100644
--- a/examples/pyomobook/abstract-ch/buildactions.py
+++ b/examples/pyomobook/abstract-ch/buildactions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/concrete1.py b/examples/pyomobook/abstract-ch/concrete1.py
index 2c89fbafaad..91a2a2ac52f 100644
--- a/examples/pyomobook/abstract-ch/concrete1.py
+++ b/examples/pyomobook/abstract-ch/concrete1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/concrete2.py b/examples/pyomobook/abstract-ch/concrete2.py
index f68c4d6e242..ff001e165a7 100644
--- a/examples/pyomobook/abstract-ch/concrete2.py
+++ b/examples/pyomobook/abstract-ch/concrete2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/diet1.py b/examples/pyomobook/abstract-ch/diet1.py
index fa8bf5f549f..84545133bca 100644
--- a/examples/pyomobook/abstract-ch/diet1.py
+++ b/examples/pyomobook/abstract-ch/diet1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/ex.py b/examples/pyomobook/abstract-ch/ex.py
index 83cfd445e01..852596e87c6 100644
--- a/examples/pyomobook/abstract-ch/ex.py
+++ b/examples/pyomobook/abstract-ch/ex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param1.py b/examples/pyomobook/abstract-ch/param1.py
index 3ff8b648661..4d3db689466 100644
--- a/examples/pyomobook/abstract-ch/param1.py
+++ b/examples/pyomobook/abstract-ch/param1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param2.py b/examples/pyomobook/abstract-ch/param2.py
index aca8fac0baf..ec1b9e32429 100644
--- a/examples/pyomobook/abstract-ch/param2.py
+++ b/examples/pyomobook/abstract-ch/param2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param2a.py b/examples/pyomobook/abstract-ch/param2a.py
index 6b6f77f2a8f..38bdd712ae1 100644
--- a/examples/pyomobook/abstract-ch/param2a.py
+++ b/examples/pyomobook/abstract-ch/param2a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param3.py b/examples/pyomobook/abstract-ch/param3.py
index 7545b47dadc..0ea722b2e0c 100644
--- a/examples/pyomobook/abstract-ch/param3.py
+++ b/examples/pyomobook/abstract-ch/param3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param3a.py b/examples/pyomobook/abstract-ch/param3a.py
index 4c52b6432fb..4025d33db9a 100644
--- a/examples/pyomobook/abstract-ch/param3a.py
+++ b/examples/pyomobook/abstract-ch/param3a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param3b.py b/examples/pyomobook/abstract-ch/param3b.py
index 786d6b58a16..cd51507b1d8 100644
--- a/examples/pyomobook/abstract-ch/param3b.py
+++ b/examples/pyomobook/abstract-ch/param3b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param3c.py b/examples/pyomobook/abstract-ch/param3c.py
index 3f5da5f837e..862bb1e7a60 100644
--- a/examples/pyomobook/abstract-ch/param3c.py
+++ b/examples/pyomobook/abstract-ch/param3c.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param4.py b/examples/pyomobook/abstract-ch/param4.py
index c1926ddea74..6e94fbd96ee 100644
--- a/examples/pyomobook/abstract-ch/param4.py
+++ b/examples/pyomobook/abstract-ch/param4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param5.py b/examples/pyomobook/abstract-ch/param5.py
index 7e0020f70b7..f68c8c70fc7 100644
--- a/examples/pyomobook/abstract-ch/param5.py
+++ b/examples/pyomobook/abstract-ch/param5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param5a.py b/examples/pyomobook/abstract-ch/param5a.py
index efdd1855f3f..9de1c963747 100644
--- a/examples/pyomobook/abstract-ch/param5a.py
+++ b/examples/pyomobook/abstract-ch/param5a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param6.py b/examples/pyomobook/abstract-ch/param6.py
index f6d60f11e4b..dc882ca8ee9 100644
--- a/examples/pyomobook/abstract-ch/param6.py
+++ b/examples/pyomobook/abstract-ch/param6.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param6a.py b/examples/pyomobook/abstract-ch/param6a.py
index 280e942d01d..f5d7c6fae65 100644
--- a/examples/pyomobook/abstract-ch/param6a.py
+++ b/examples/pyomobook/abstract-ch/param6a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param7a.py b/examples/pyomobook/abstract-ch/param7a.py
index 21839bf3b64..68d01a4343d 100644
--- a/examples/pyomobook/abstract-ch/param7a.py
+++ b/examples/pyomobook/abstract-ch/param7a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param7b.py b/examples/pyomobook/abstract-ch/param7b.py
index a4d79b6dee9..ad7c27d5bdc 100644
--- a/examples/pyomobook/abstract-ch/param7b.py
+++ b/examples/pyomobook/abstract-ch/param7b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/param8a.py b/examples/pyomobook/abstract-ch/param8a.py
index f00ed649c30..7df9a9960a7 100644
--- a/examples/pyomobook/abstract-ch/param8a.py
+++ b/examples/pyomobook/abstract-ch/param8a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/postprocess_fn.py b/examples/pyomobook/abstract-ch/postprocess_fn.py
index 2f2d114c216..ab7c99264ac 100644
--- a/examples/pyomobook/abstract-ch/postprocess_fn.py
+++ b/examples/pyomobook/abstract-ch/postprocess_fn.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set1.py b/examples/pyomobook/abstract-ch/set1.py
index 5a23fe683e0..c76a29eb9cb 100644
--- a/examples/pyomobook/abstract-ch/set1.py
+++ b/examples/pyomobook/abstract-ch/set1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set2.py b/examples/pyomobook/abstract-ch/set2.py
index 5ecc0914bee..a8b3fc316ce 100644
--- a/examples/pyomobook/abstract-ch/set2.py
+++ b/examples/pyomobook/abstract-ch/set2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set2a.py b/examples/pyomobook/abstract-ch/set2a.py
index 7252ec0ad69..082fda43758 100644
--- a/examples/pyomobook/abstract-ch/set2a.py
+++ b/examples/pyomobook/abstract-ch/set2a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set3.py b/examples/pyomobook/abstract-ch/set3.py
index f3e3efc33c7..fa8ca7cd363 100644
--- a/examples/pyomobook/abstract-ch/set3.py
+++ b/examples/pyomobook/abstract-ch/set3.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set4.py b/examples/pyomobook/abstract-ch/set4.py
index 0c29798b816..cc71b5b616a 100644
--- a/examples/pyomobook/abstract-ch/set4.py
+++ b/examples/pyomobook/abstract-ch/set4.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/set5.py b/examples/pyomobook/abstract-ch/set5.py
index 781b956404e..6d6a6ed74e3 100644
--- a/examples/pyomobook/abstract-ch/set5.py
+++ b/examples/pyomobook/abstract-ch/set5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/wl_abstract.py b/examples/pyomobook/abstract-ch/wl_abstract.py
index 61eeed6b506..6b81070a239 100644
--- a/examples/pyomobook/abstract-ch/wl_abstract.py
+++ b/examples/pyomobook/abstract-ch/wl_abstract.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/abstract-ch/wl_abstract_script.py b/examples/pyomobook/abstract-ch/wl_abstract_script.py
index 7f0871350fc..f8aa546d2e8 100644
--- a/examples/pyomobook/abstract-ch/wl_abstract_script.py
+++ b/examples/pyomobook/abstract-ch/wl_abstract_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/blocks_gen.py b/examples/pyomobook/blocks-ch/blocks_gen.py
index 31a4462f7d6..11c3cbce547 100644
--- a/examples/pyomobook/blocks-ch/blocks_gen.py
+++ b/examples/pyomobook/blocks-ch/blocks_gen.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/blocks_intro.py b/examples/pyomobook/blocks-ch/blocks_intro.py
index ba2bd9d3a97..6f19a7eaa8c 100644
--- a/examples/pyomobook/blocks-ch/blocks_intro.py
+++ b/examples/pyomobook/blocks-ch/blocks_intro.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/blocks_lotsizing.py b/examples/pyomobook/blocks-ch/blocks_lotsizing.py
index 758ad964dc5..4e5791c4617 100644
--- a/examples/pyomobook/blocks-ch/blocks_lotsizing.py
+++ b/examples/pyomobook/blocks-ch/blocks_lotsizing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/lotsizing.py b/examples/pyomobook/blocks-ch/lotsizing.py
index ece4d6b541c..f4c355654d1 100644
--- a/examples/pyomobook/blocks-ch/lotsizing.py
+++ b/examples/pyomobook/blocks-ch/lotsizing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/lotsizing_no_time.py b/examples/pyomobook/blocks-ch/lotsizing_no_time.py
index 60e8ba44424..2c61aefb02b 100644
--- a/examples/pyomobook/blocks-ch/lotsizing_no_time.py
+++ b/examples/pyomobook/blocks-ch/lotsizing_no_time.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/blocks-ch/lotsizing_uncertain.py b/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
index f72161db5c6..7bbfd1b24ac 100644
--- a/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
+++ b/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/dae-ch/dae_tester_model.py b/examples/pyomobook/dae-ch/dae_tester_model.py
index 396b8a53db1..2a47a2f7a55 100644
--- a/examples/pyomobook/dae-ch/dae_tester_model.py
+++ b/examples/pyomobook/dae-ch/dae_tester_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/dae-ch/path_constraint.py b/examples/pyomobook/dae-ch/path_constraint.py
index 5e252d1b99f..3e8ccfdf952 100644
--- a/examples/pyomobook/dae-ch/path_constraint.py
+++ b/examples/pyomobook/dae-ch/path_constraint.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/dae-ch/plot_path_constraint.py b/examples/pyomobook/dae-ch/plot_path_constraint.py
index be86f13cbc0..23b80ca9be2 100644
--- a/examples/pyomobook/dae-ch/plot_path_constraint.py
+++ b/examples/pyomobook/dae-ch/plot_path_constraint.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/dae-ch/run_path_constraint.py b/examples/pyomobook/dae-ch/run_path_constraint.py
index fc115f5649c..c8db1bb7bd6 100644
--- a/examples/pyomobook/dae-ch/run_path_constraint.py
+++ b/examples/pyomobook/dae-ch/run_path_constraint.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,7 +10,6 @@
# ___________________________________________________________________________
import pyomo.environ as pyo
-from pyomo.dae import *
from path_constraint import m
# Discretize model using Orthogonal Collocation
diff --git a/examples/pyomobook/dae-ch/run_path_constraint_tester.py b/examples/pyomobook/dae-ch/run_path_constraint_tester.py
index 22d887e9b11..86a5bd08b74 100644
--- a/examples/pyomobook/dae-ch/run_path_constraint_tester.py
+++ b/examples/pyomobook/dae-ch/run_path_constraint_tester.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/gdp-ch/gdp_uc.py b/examples/pyomobook/gdp-ch/gdp_uc.py
index 6268bcce068..ed27802bf5b 100644
--- a/examples/pyomobook/gdp-ch/gdp_uc.py
+++ b/examples/pyomobook/gdp-ch/gdp_uc.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,7 +11,7 @@
# gdp_uc.py
import pyomo.environ as pyo
-from pyomo.gdp import *
+from pyomo.gdp import Disjunct, Disjunction
model = pyo.AbstractModel()
@@ -116,3 +116,9 @@ def obj(m):
@model.Constraint(model.GENERATORS)
def nontrivial(m, g):
return sum(m.Power[g, t] for t in m.TIME) >= len(m.TIME) / 2 * m.MinPower[g]
+
+
+@model.ConstraintList()
+def nondegenerate(m):
+ for i, g in enumerate(m.GENERATORS):
+ yield m.Power[g, i + 1] == 0
diff --git a/examples/pyomobook/gdp-ch/pyomo.gdp_uc.txt b/examples/pyomobook/gdp-ch/pyomo.gdp_uc.txt
index 477336d48ba..f0b5a5c4795 100644
--- a/examples/pyomobook/gdp-ch/pyomo.gdp_uc.txt
+++ b/examples/pyomobook/gdp-ch/pyomo.gdp_uc.txt
@@ -22,9 +22,9 @@ Problem:
Lower bound: 45.0
Upper bound: 45.0
Number of objectives: 1
- Number of constraints: 58
+ Number of constraints: 60
Number of variables: 24
- Number of nonzeros: 124
+ Number of nonzeros: 126
Sense: minimize
# ----------------------------------------------------------
# Solver Information
@@ -34,8 +34,8 @@ Solver:
Termination condition: optimal
Statistics:
Branch and bound:
- Number of bounded subproblems: 15
- Number of created subproblems: 15
+ Number of bounded subproblems: 9
+ Number of created subproblems: 9
Error rc: 0
Time: 0.007754325866699219
# ----------------------------------------------------------
@@ -51,24 +51,24 @@ Solution:
obj:
Value: 45
Variable:
- GenOff[g1,2].binary_indicator_var:
+ GenOff[g1,1].binary_indicator_var:
Value: 1
- GenOff[g2,1].binary_indicator_var:
+ GenOff[g2,2].binary_indicator_var:
Value: 1
- GenOn[g1,1].binary_indicator_var:
+ GenOn[g1,3].binary_indicator_var:
Value: 1
- GenOn[g2,3].binary_indicator_var:
+ GenOn[g2,1].binary_indicator_var:
Value: 1
- GenStartup[g1,3].binary_indicator_var:
+ GenStartup[g1,2].binary_indicator_var:
Value: 1
- GenStartup[g2,2].binary_indicator_var:
+ GenStartup[g2,3].binary_indicator_var:
Value: 1
- Power[g1,1]:
- Value: 10
- Power[g1,3]:
+ Power[g1,2]:
Value: 5
- Power[g2,2]:
+ Power[g1,3]:
Value: 10
- Power[g2,3]:
+ Power[g2,1]:
Value: 20
+ Power[g2,3]:
+ Value: 10
Constraint: No values
diff --git a/examples/pyomobook/gdp-ch/scont.py b/examples/pyomobook/gdp-ch/scont.py
index d1cf4b172bd..3c275a13158 100644
--- a/examples/pyomobook/gdp-ch/scont.py
+++ b/examples/pyomobook/gdp-ch/scont.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/gdp-ch/scont2.py b/examples/pyomobook/gdp-ch/scont2.py
index 2c77fe670d5..fbfd1540b57 100644
--- a/examples/pyomobook/gdp-ch/scont2.py
+++ b/examples/pyomobook/gdp-ch/scont2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/gdp-ch/scont_script.py b/examples/pyomobook/gdp-ch/scont_script.py
index fe0702dc262..a9285ac0aa4 100644
--- a/examples/pyomobook/gdp-ch/scont_script.py
+++ b/examples/pyomobook/gdp-ch/scont_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/gdp-ch/verify_scont.py b/examples/pyomobook/gdp-ch/verify_scont.py
index 222453560b6..4d73ce520eb 100644
--- a/examples/pyomobook/gdp-ch/verify_scont.py
+++ b/examples/pyomobook/gdp-ch/verify_scont.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/intro-ch/abstract5.py b/examples/pyomobook/intro-ch/abstract5.py
index 2caad5f9351..f42918af027 100644
--- a/examples/pyomobook/intro-ch/abstract5.py
+++ b/examples/pyomobook/intro-ch/abstract5.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/intro-ch/coloring_concrete.py b/examples/pyomobook/intro-ch/coloring_concrete.py
index 9931b5d80de..2a5c25ea611 100644
--- a/examples/pyomobook/intro-ch/coloring_concrete.py
+++ b/examples/pyomobook/intro-ch/coloring_concrete.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/intro-ch/concrete1.py b/examples/pyomobook/intro-ch/concrete1.py
index 169fbeb281c..2f379d9dcb0 100644
--- a/examples/pyomobook/intro-ch/concrete1.py
+++ b/examples/pyomobook/intro-ch/concrete1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/intro-ch/concrete1_generic.py b/examples/pyomobook/intro-ch/concrete1_generic.py
index 9a2d26bded8..a271269a611 100644
--- a/examples/pyomobook/intro-ch/concrete1_generic.py
+++ b/examples/pyomobook/intro-ch/concrete1_generic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/intro-ch/mydata.py b/examples/pyomobook/intro-ch/mydata.py
index 209546ebeaf..9e9ad32c18f 100644
--- a/examples/pyomobook/intro-ch/mydata.py
+++ b/examples/pyomobook/intro-ch/mydata.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex1a.py b/examples/pyomobook/mpec-ch/ex1a.py
index e6f1c33fbbc..c24695af1a6 100644
--- a/examples/pyomobook/mpec-ch/ex1a.py
+++ b/examples/pyomobook/mpec-ch/ex1a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex1b.py b/examples/pyomobook/mpec-ch/ex1b.py
index 2b0ac2ce1b7..1ee594c2019 100644
--- a/examples/pyomobook/mpec-ch/ex1b.py
+++ b/examples/pyomobook/mpec-ch/ex1b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex1c.py b/examples/pyomobook/mpec-ch/ex1c.py
index eaf0292b50d..98aa89e0c82 100644
--- a/examples/pyomobook/mpec-ch/ex1c.py
+++ b/examples/pyomobook/mpec-ch/ex1c.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex1d.py b/examples/pyomobook/mpec-ch/ex1d.py
index 4c0e0d9fd0f..2b8e55845ac 100644
--- a/examples/pyomobook/mpec-ch/ex1d.py
+++ b/examples/pyomobook/mpec-ch/ex1d.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex1e.py b/examples/pyomobook/mpec-ch/ex1e.py
index c552847fcfb..bb47e12a5b0 100644
--- a/examples/pyomobook/mpec-ch/ex1e.py
+++ b/examples/pyomobook/mpec-ch/ex1e.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ex2.py b/examples/pyomobook/mpec-ch/ex2.py
index 6981af33376..4743e2144f8 100644
--- a/examples/pyomobook/mpec-ch/ex2.py
+++ b/examples/pyomobook/mpec-ch/ex2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,7 +11,7 @@
# ex2.py
import pyomo.environ as pyo
-from pyomo.mpec import *
+from pyomo.mpec import Complementarity, complements
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/mpec-ch/munson1.py b/examples/pyomobook/mpec-ch/munson1.py
index e85d9359768..61ce93cc058 100644
--- a/examples/pyomobook/mpec-ch/munson1.py
+++ b/examples/pyomobook/mpec-ch/munson1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/mpec-ch/ralph1.py b/examples/pyomobook/mpec-ch/ralph1.py
index b6a8b45e8df..c56bb94ae4f 100644
--- a/examples/pyomobook/mpec-ch/ralph1.py
+++ b/examples/pyomobook/mpec-ch/ralph1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py b/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
index dc3ca179a58..794f2f5b900 100644
--- a/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
+++ b/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py b/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
index 5675d7a715b..c090bca0c9f 100644
--- a/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
+++ b/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
index a50bf3321d6..1439744799b 100644
--- a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
+++ b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
index 6a209334521..46d7c7e77ec 100644
--- a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
+++ b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
index 1cfe3b7193f..b8b6d02dcc1 100644
--- a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
+++ b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
index 2bd9574b427..8d6f23d1bab 100644
--- a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
+++ b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py b/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
index bec1d04c12c..274f2649474 100644
--- a/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
+++ b/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/optimization-ch/ConcHLinScript.py b/examples/pyomobook/optimization-ch/ConcHLinScript.py
index b94903585dc..b4ae096e041 100644
--- a/examples/pyomobook/optimization-ch/ConcHLinScript.py
+++ b/examples/pyomobook/optimization-ch/ConcHLinScript.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/optimization-ch/ConcreteH.py b/examples/pyomobook/optimization-ch/ConcreteH.py
index d7474291d0d..25b0322fa76 100644
--- a/examples/pyomobook/optimization-ch/ConcreteH.py
+++ b/examples/pyomobook/optimization-ch/ConcreteH.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/optimization-ch/ConcreteHLinear.py b/examples/pyomobook/optimization-ch/ConcreteHLinear.py
index 772c18cb6d5..daffdd1fc4e 100644
--- a/examples/pyomobook/optimization-ch/ConcreteHLinear.py
+++ b/examples/pyomobook/optimization-ch/ConcreteHLinear.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/optimization-ch/IC_model_dict.py b/examples/pyomobook/optimization-ch/IC_model_dict.py
index b7e359777c7..4ccde353fea 100644
--- a/examples/pyomobook/optimization-ch/IC_model_dict.py
+++ b/examples/pyomobook/optimization-ch/IC_model_dict.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/var_obj_con_snippet.py b/examples/pyomobook/overview-ch/var_obj_con_snippet.py
index 22524b5815a..3e026ecb352 100644
--- a/examples/pyomobook/overview-ch/var_obj_con_snippet.py
+++ b/examples/pyomobook/overview-ch/var_obj_con_snippet.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_abstract.py b/examples/pyomobook/overview-ch/wl_abstract.py
index 61eeed6b506..6b81070a239 100644
--- a/examples/pyomobook/overview-ch/wl_abstract.py
+++ b/examples/pyomobook/overview-ch/wl_abstract.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_abstract_script.py b/examples/pyomobook/overview-ch/wl_abstract_script.py
index 7f0871350fc..f8aa546d2e8 100644
--- a/examples/pyomobook/overview-ch/wl_abstract_script.py
+++ b/examples/pyomobook/overview-ch/wl_abstract_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_concrete.py b/examples/pyomobook/overview-ch/wl_concrete.py
index c1bf70b07f1..5f599836b3d 100644
--- a/examples/pyomobook/overview-ch/wl_concrete.py
+++ b/examples/pyomobook/overview-ch/wl_concrete.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_concrete_script.py b/examples/pyomobook/overview-ch/wl_concrete_script.py
index b369521994c..6b593fca774 100644
--- a/examples/pyomobook/overview-ch/wl_concrete_script.py
+++ b/examples/pyomobook/overview-ch/wl_concrete_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_excel.py b/examples/pyomobook/overview-ch/wl_excel.py
index 180e36422fe..354d90ecc15 100644
--- a/examples/pyomobook/overview-ch/wl_excel.py
+++ b/examples/pyomobook/overview-ch/wl_excel.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_list.py b/examples/pyomobook/overview-ch/wl_list.py
index 37cba5a9595..9ec943f838b 100644
--- a/examples/pyomobook/overview-ch/wl_list.py
+++ b/examples/pyomobook/overview-ch/wl_list.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_mutable.py b/examples/pyomobook/overview-ch/wl_mutable.py
index 8e129dd3c49..631d60f227a 100644
--- a/examples/pyomobook/overview-ch/wl_mutable.py
+++ b/examples/pyomobook/overview-ch/wl_mutable.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_mutable_excel.py b/examples/pyomobook/overview-ch/wl_mutable_excel.py
index 935fa4963e5..e139c58e7f1 100644
--- a/examples/pyomobook/overview-ch/wl_mutable_excel.py
+++ b/examples/pyomobook/overview-ch/wl_mutable_excel.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/overview-ch/wl_scalar.py b/examples/pyomobook/overview-ch/wl_scalar.py
index 6f538baedb8..c559813235b 100644
--- a/examples/pyomobook/overview-ch/wl_scalar.py
+++ b/examples/pyomobook/overview-ch/wl_scalar.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/performance-ch/SparseSets.py b/examples/pyomobook/performance-ch/SparseSets.py
index 519808306de..5109070b33f 100644
--- a/examples/pyomobook/performance-ch/SparseSets.py
+++ b/examples/pyomobook/performance-ch/SparseSets.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/performance-ch/lin_expr.py b/examples/pyomobook/performance-ch/lin_expr.py
index af50ddd6228..2611122e8ba 100644
--- a/examples/pyomobook/performance-ch/lin_expr.py
+++ b/examples/pyomobook/performance-ch/lin_expr.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/performance-ch/persistent.py b/examples/pyomobook/performance-ch/persistent.py
index 67f8c656cfe..5574fec1c6b 100644
--- a/examples/pyomobook/performance-ch/persistent.py
+++ b/examples/pyomobook/performance-ch/persistent.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/performance-ch/wl.py b/examples/pyomobook/performance-ch/wl.py
index 000f81272a1..fc5764ede44 100644
--- a/examples/pyomobook/performance-ch/wl.py
+++ b/examples/pyomobook/performance-ch/wl.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/con_declaration.py b/examples/pyomobook/pyomo-components-ch/con_declaration.py
index 0890ba4771b..8bec3dee42a 100644
--- a/examples/pyomobook/pyomo-components-ch/con_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/con_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/examples.py b/examples/pyomobook/pyomo-components-ch/examples.py
index 1a59e9e308e..1799ca74f1d 100644
--- a/examples/pyomobook/pyomo-components-ch/examples.py
+++ b/examples/pyomobook/pyomo-components-ch/examples.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/expr_declaration.py b/examples/pyomobook/pyomo-components-ch/expr_declaration.py
index da0d854e513..303bbf332b2 100644
--- a/examples/pyomobook/pyomo-components-ch/expr_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/expr_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/obj_declaration.py b/examples/pyomobook/pyomo-components-ch/obj_declaration.py
index a63fc441206..69dd718c4ec 100644
--- a/examples/pyomobook/pyomo-components-ch/obj_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/obj_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/obj_declaration.txt b/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
index 607586a1fb3..e4d4b02a252 100644
--- a/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
@@ -55,7 +55,7 @@ Model unknown
None
value
x[Q] + 2*x[R]
-1
+minimize
6.5
Model unknown
diff --git a/examples/pyomobook/pyomo-components-ch/param_declaration.py b/examples/pyomobook/pyomo-components-ch/param_declaration.py
index 98b16548c28..a2409b543a9 100644
--- a/examples/pyomobook/pyomo-components-ch/param_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/param_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/param_initialization.py b/examples/pyomobook/pyomo-components-ch/param_initialization.py
index 88da8a68354..d98c23a174a 100644
--- a/examples/pyomobook/pyomo-components-ch/param_initialization.py
+++ b/examples/pyomobook/pyomo-components-ch/param_initialization.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/param_misc.py b/examples/pyomobook/pyomo-components-ch/param_misc.py
index 72fca60f787..7e045da8fe9 100644
--- a/examples/pyomobook/pyomo-components-ch/param_misc.py
+++ b/examples/pyomobook/pyomo-components-ch/param_misc.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/param_validation.py b/examples/pyomobook/pyomo-components-ch/param_validation.py
index baf5f0ac1e2..96efa16ad68 100644
--- a/examples/pyomobook/pyomo-components-ch/param_validation.py
+++ b/examples/pyomobook/pyomo-components-ch/param_validation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/rangeset.py b/examples/pyomobook/pyomo-components-ch/rangeset.py
index 169060e9ab2..b617be600e3 100644
--- a/examples/pyomobook/pyomo-components-ch/rangeset.py
+++ b/examples/pyomobook/pyomo-components-ch/rangeset.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/set_declaration.py b/examples/pyomobook/pyomo-components-ch/set_declaration.py
index bf3cfa1be15..9d183e13027 100644
--- a/examples/pyomobook/pyomo-components-ch/set_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/set_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/set_initialization.py b/examples/pyomobook/pyomo-components-ch/set_initialization.py
index bdfd662c985..0390d0b9a3c 100644
--- a/examples/pyomobook/pyomo-components-ch/set_initialization.py
+++ b/examples/pyomobook/pyomo-components-ch/set_initialization.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/set_misc.py b/examples/pyomobook/pyomo-components-ch/set_misc.py
index 20ed9518f52..eef741f2ac9 100644
--- a/examples/pyomobook/pyomo-components-ch/set_misc.py
+++ b/examples/pyomobook/pyomo-components-ch/set_misc.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/set_options.py b/examples/pyomobook/pyomo-components-ch/set_options.py
index 30c0b49706d..289a6b1479d 100644
--- a/examples/pyomobook/pyomo-components-ch/set_options.py
+++ b/examples/pyomobook/pyomo-components-ch/set_options.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/set_validation.py b/examples/pyomobook/pyomo-components-ch/set_validation.py
index 2300c0be693..6a9cbe60a89 100644
--- a/examples/pyomobook/pyomo-components-ch/set_validation.py
+++ b/examples/pyomobook/pyomo-components-ch/set_validation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/suffix_declaration.py b/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
index 619093712f1..ae1e72ec168 100644
--- a/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/pyomo-components-ch/var_declaration.py b/examples/pyomobook/pyomo-components-ch/var_declaration.py
index 2ee5d7fb749..d22e64e5c73 100644
--- a/examples/pyomobook/pyomo-components-ch/var_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/var_declaration.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/BadIndent.py b/examples/pyomobook/python-ch/BadIndent.py
index 4a00cae12ef..27eb99b6fa6 100644
--- a/examples/pyomobook/python-ch/BadIndent.py
+++ b/examples/pyomobook/python-ch/BadIndent.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/LineExample.py b/examples/pyomobook/python-ch/LineExample.py
index 31cface5760..21ba8889bb9 100644
--- a/examples/pyomobook/python-ch/LineExample.py
+++ b/examples/pyomobook/python-ch/LineExample.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/class.py b/examples/pyomobook/python-ch/class.py
index a09f991d37b..0cd3fdd5b54 100644
--- a/examples/pyomobook/python-ch/class.py
+++ b/examples/pyomobook/python-ch/class.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/ctob.py b/examples/pyomobook/python-ch/ctob.py
index 8945e4863de..d9161480121 100644
--- a/examples/pyomobook/python-ch/ctob.py
+++ b/examples/pyomobook/python-ch/ctob.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/example.py b/examples/pyomobook/python-ch/example.py
index 184153545a3..e95b8da371a 100644
--- a/examples/pyomobook/python-ch/example.py
+++ b/examples/pyomobook/python-ch/example.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/example2.py b/examples/pyomobook/python-ch/example2.py
index 9a6a28bedbd..7f049444783 100644
--- a/examples/pyomobook/python-ch/example2.py
+++ b/examples/pyomobook/python-ch/example2.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/functions.py b/examples/pyomobook/python-ch/functions.py
index 97fb77edbe4..66e64027a1b 100644
--- a/examples/pyomobook/python-ch/functions.py
+++ b/examples/pyomobook/python-ch/functions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/iterate.py b/examples/pyomobook/python-ch/iterate.py
index 50d74f93da7..e25ec1fd412 100644
--- a/examples/pyomobook/python-ch/iterate.py
+++ b/examples/pyomobook/python-ch/iterate.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/python-ch/pythonconditional.py b/examples/pyomobook/python-ch/pythonconditional.py
index a39e148622b..480d12221b0 100644
--- a/examples/pyomobook/python-ch/pythonconditional.py
+++ b/examples/pyomobook/python-ch/pythonconditional.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/attributes.py b/examples/pyomobook/scripts-ch/attributes.py
index c406bbf3e1c..33125a28e13 100644
--- a/examples/pyomobook/scripts-ch/attributes.py
+++ b/examples/pyomobook/scripts-ch/attributes.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/prob_mod_ex.py b/examples/pyomobook/scripts-ch/prob_mod_ex.py
index dceafe9d4f0..310d6eaa861 100644
--- a/examples/pyomobook/scripts-ch/prob_mod_ex.py
+++ b/examples/pyomobook/scripts-ch/prob_mod_ex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/sudoku/sudoku.py b/examples/pyomobook/scripts-ch/sudoku/sudoku.py
index 8aa39f91203..e274616ec53 100644
--- a/examples/pyomobook/scripts-ch/sudoku/sudoku.py
+++ b/examples/pyomobook/scripts-ch/sudoku/sudoku.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py b/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
index b3f861f86b5..c770db4b9e8 100644
--- a/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
+++ b/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/value_expression.py b/examples/pyomobook/scripts-ch/value_expression.py
index 00c79fec501..ccb850654ed 100644
--- a/examples/pyomobook/scripts-ch/value_expression.py
+++ b/examples/pyomobook/scripts-ch/value_expression.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_cuts.py b/examples/pyomobook/scripts-ch/warehouse_cuts.py
index 345dc5540cb..771887037a1 100644
--- a/examples/pyomobook/scripts-ch/warehouse_cuts.py
+++ b/examples/pyomobook/scripts-ch/warehouse_cuts.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_load_solutions.py b/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
index d38412f84df..d7ba0f7416e 100644
--- a/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
+++ b/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_model.py b/examples/pyomobook/scripts-ch/warehouse_model.py
index 149eb212759..02b67c5db3c 100644
--- a/examples/pyomobook/scripts-ch/warehouse_model.py
+++ b/examples/pyomobook/scripts-ch/warehouse_model.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_print.py b/examples/pyomobook/scripts-ch/warehouse_print.py
index 8c862506bf0..96947165aec 100644
--- a/examples/pyomobook/scripts-ch/warehouse_print.py
+++ b/examples/pyomobook/scripts-ch/warehouse_print.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_script.py b/examples/pyomobook/scripts-ch/warehouse_script.py
index 617b8036abf..508a54e301b 100644
--- a/examples/pyomobook/scripts-ch/warehouse_script.py
+++ b/examples/pyomobook/scripts-ch/warehouse_script.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_solver_options.py b/examples/pyomobook/scripts-ch/warehouse_solver_options.py
index 4e79e158d50..106e3cb9c07 100644
--- a/examples/pyomobook/scripts-ch/warehouse_solver_options.py
+++ b/examples/pyomobook/scripts-ch/warehouse_solver_options.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/strip_examples.py b/examples/pyomobook/strip_examples.py
index 84017299fb6..6128162eda3 100644
--- a/examples/pyomobook/strip_examples.py
+++ b/examples/pyomobook/strip_examples.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/examples/pyomobook/test_book_examples.py b/examples/pyomobook/test_book_examples.py
index 192330dc1bf..d3fa418950e 100644
--- a/examples/pyomobook/test_book_examples.py
+++ b/examples/pyomobook/test_book_examples.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/__init__.py b/pyomo/__init__.py
index 14cc42b626e..bce2e9f0ba3 100644
--- a/pyomo/__init__.py
+++ b/pyomo/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,3 +11,22 @@
from . import common
from .version import __version__
+
+
+#
+# declare deprecation paths for removed modules
+#
+from pyomo.common.deprecation import moved_module
+
+moved_module(
+ 'pyomo.pysp',
+ 'pysp',
+ version='6.0',
+ msg="PySP has been removed from the pyomo.pysp namespace. "
+ "Beginning in Pyomo 6.0, PySP is distributed as a separate "
+ "package. Please see https://github.com/Pyomo/pysp for "
+ "information on downloading and installing PySP",
+)
+# (*silently*) redirect 'pyomo.__future__' to 'pyomo.future'
+moved_module('pyomo.__future__', 'pyomo.future', msg=None)
+del moved_module
diff --git a/pyomo/_archive/__init__.py b/pyomo/_archive/__init__.py
new file mode 100644
index 00000000000..af86df84849
--- /dev/null
+++ b/pyomo/_archive/__init__.py
@@ -0,0 +1,18 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+__doc__ = """This package contains archived modules that are no longer part of the
+official Pyomo API.
+
+These modules are still importable through their old names via
+:func:`pyomo.common.moved_module()`
+
+"""
diff --git a/pyomo/contrib/parmest/ipopt_solver_wrapper.py b/pyomo/_archive/chull.py
similarity index 75%
rename from pyomo/contrib/parmest/ipopt_solver_wrapper.py
rename to pyomo/_archive/chull.py
index 75c470a4b81..547b75df26e 100644
--- a/pyomo/contrib/parmest/ipopt_solver_wrapper.py
+++ b/pyomo/_archive/chull.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,6 +9,6 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.common.deprecation import relocated_module
+"This is the deprecated pyomo.gdp.plugins.chull module"
-relocated_module('pyomo.contrib.parmest.utils.ipopt_solver_wrapper', version='6.4.2')
+from pyomo.gdp.plugins.hull import _Deprecated_Name_Hull as ConvexHull_Transformation
diff --git a/pyomo/common/plugin.py b/pyomo/_archive/component_map.py
similarity index 78%
rename from pyomo/common/plugin.py
rename to pyomo/_archive/component_map.py
index ac88388ebc0..df510cac9e6 100644
--- a/pyomo/common/plugin.py
+++ b/pyomo/_archive/component_map.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,6 +9,6 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.common.deprecation import relocated_module
+"This is the deprecated pyomo.core.kernel.component_map module"
-relocated_module('pyomo.common.plugin_base', version='6.5.0')
+from pyomo.common.collections import ComponentMap
diff --git a/pyomo/repn/tests/ampl/nl_diff.py b/pyomo/_archive/component_set.py
similarity index 76%
rename from pyomo/repn/tests/ampl/nl_diff.py
rename to pyomo/_archive/component_set.py
index 9fe352ee503..319b12e092f 100644
--- a/pyomo/repn/tests/ampl/nl_diff.py
+++ b/pyomo/_archive/component_set.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,6 +9,6 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.common.deprecation import relocated_module
+"This is the deprecated pyomo.core.kernel.component_set module"
-relocated_module('pyomo.repn.tests.nl_diff', version='6.6.0', remove_in='6.6.1')
+from pyomo.common.collections import ComponentSet
diff --git a/pyomo/core/expr/current.py b/pyomo/_archive/current.py
similarity index 94%
rename from pyomo/core/expr/current.py
rename to pyomo/_archive/current.py
index 1209dac0310..a839dbe5633 100644
--- a/pyomo/core/expr/current.py
+++ b/pyomo/_archive/current.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,17 +9,11 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
+"This is the deprecated pyomo.core.expr.current module"
+
import enum
import math
-from pyomo.common.deprecation import deprecation_warning
-
-deprecation_warning(
- "pyomo.core.expr.current is deprecated. "
- "Please import expression symbols from pyomo.core.expr",
- version='6.6.2',
-)
-
#
# Common intrinsic functions
#
diff --git a/pyomo/core/base/plugin.py b/pyomo/_archive/plugin.py
similarity index 76%
rename from pyomo/core/base/plugin.py
rename to pyomo/_archive/plugin.py
index 062e9f9fb85..11e1aa54e34 100644
--- a/pyomo/core/base/plugin.py
+++ b/pyomo/_archive/plugin.py
@@ -1,25 +1,15 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________
-import inspect
-from pyomo.common.deprecation import deprecation_warning
-deprecation_warning(
- "The pyomo.core.base.plugin module is deprecated. "
- "See pyomo.core.base.transformation for Transformation and "
- "TransformationFactory, pyomo.core.base.component for "
- "ModelComponentFactory and pyomo.scripting.interface for "
- "IPyomoScript* interfaces.",
- version='6.0',
- calling_frame=inspect.currentframe().f_back,
-)
+"This is the deprecated pyomo.core.base.plugin module"
from pyomo.core.base.component import ModelComponentFactory
from pyomo.core.base.transformation import (
diff --git a/pyomo/common/getGSL.py b/pyomo/_archive/rangeset.py
similarity index 79%
rename from pyomo/common/getGSL.py
rename to pyomo/_archive/rangeset.py
index 66b75b45665..bf6b56809f5 100644
--- a/pyomo/common/getGSL.py
+++ b/pyomo/_archive/rangeset.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,6 +9,6 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.common.deprecation import relocated_module
+"This is the deprecated pyomo.core.base.rangeset module"
-relocated_module('pyomo.common.gsl', version='6.5.0')
+from pyomo.core.base.set import RangeSet
diff --git a/pyomo/core/kernel/register_numpy_types.py b/pyomo/_archive/register_numpy_types.py
similarity index 82%
rename from pyomo/core/kernel/register_numpy_types.py
rename to pyomo/_archive/register_numpy_types.py
index 86877be2230..3b48e0c1c6e 100644
--- a/pyomo/core/kernel/register_numpy_types.py
+++ b/pyomo/_archive/register_numpy_types.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,13 +9,7 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from pyomo.common.deprecation import deprecation_warning
-
-deprecation_warning(
- "pyomo.core.kernel.register_numpy_types is deprecated. NumPy type "
- "registration is handled automatically by pyomo.common.dependencies.numpy",
- version='6.1',
-)
+"This is the deprecated pyomo.core.kernel.register_numpy_types module"
from pyomo.common.numeric_types import (
RegisterNumericType,
@@ -45,10 +39,12 @@
# Historically, the lists included several numpy aliases
numpy_int_names.extend(('int_', 'intc', 'intp'))
numpy_int.extend((numpy.int_, numpy.intc, numpy.intp))
- numpy_float_names.append('float_')
- numpy_float.append(numpy.float_)
- numpy_complex_names.append('complex_')
- numpy_complex.append(numpy.complex_)
+ if hasattr(numpy, 'float_'):
+ numpy_float_names.append('float_')
+ numpy_float.append(numpy.float_)
+ if hasattr(numpy, 'complex_'):
+ numpy_complex_names.append('complex_')
+ numpy_complex.append(numpy.complex_)
# Re-build the old numpy_* lists
for t in native_boolean_types:
diff --git a/pyomo/_archive/sets.py b/pyomo/_archive/sets.py
new file mode 100644
index 00000000000..4aa29d9870a
--- /dev/null
+++ b/pyomo/_archive/sets.py
@@ -0,0 +1,23 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+"This is the deprecated pyomo.core.base.sets module"
+
+from pyomo.core.base.set import (
+ process_setarg,
+ set_options,
+ simple_set_rule,
+ _SetDataBase,
+ SetData,
+ Set,
+ SetOf,
+ IndexedSet,
+)
diff --git a/pyomo/_archive/template_expr.py b/pyomo/_archive/template_expr.py
new file mode 100644
index 00000000000..42a5547d143
--- /dev/null
+++ b/pyomo/_archive/template_expr.py
@@ -0,0 +1,18 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+"This is the deprecated pyomo.core.base.template_expr module"
+
+from pyomo.core.expr.template_expr import (
+ IndexTemplate,
+ _GetItemIndexer,
+ TemplateExpressionError,
+)
diff --git a/pyomo/common/__init__.py b/pyomo/common/__init__.py
index d7297c067c9..cee0ae3cb05 100644
--- a/pyomo/common/__init__.py
+++ b/pyomo/common/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -28,3 +28,12 @@
from .deprecation import deprecated
from .errors import DeveloperError
from ._command import pyomo_command, get_pyomo_commands
+
+#
+# declare deprecation paths for removed modules
+#
+from .deprecation import moved_module
+
+moved_module('pyomo.common.getGSL', 'pyomo.common.gsl', version='6.5.0')
+moved_module('pyomo.common.plugin', 'pyomo.common.plugin_base', version='6.5.0')
+del moved_module
diff --git a/pyomo/common/_command.py b/pyomo/common/_command.py
index ad521659aa7..2e26efca465 100644
--- a/pyomo/common/_command.py
+++ b/pyomo/common/_command.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/_common.py b/pyomo/common/_common.py
index 0d50f74537a..61f7ff39f55 100644
--- a/pyomo/common/_common.py
+++ b/pyomo/common/_common.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/autoslots.py b/pyomo/common/autoslots.py
index 89fefaf4f21..3b5b3b00154 100644
--- a/pyomo/common/autoslots.py
+++ b/pyomo/common/autoslots.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,22 +9,23 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
+import collections
import types
-from collections import namedtuple
from copy import deepcopy
from weakref import ref as _weakref_ref
-_autoslot_info = namedtuple(
+_autoslot_info = collections.namedtuple(
'_autoslot_info', ['has_dict', 'slots', 'slot_mappers', 'field_mappers']
)
def _deepcopy_tuple(obj, memo, _id):
ans = []
+ _append = ans.append
unchanged = True
for item in obj:
new_item = fast_deepcopy(item, memo)
- ans.append(new_item)
+ _append(new_item)
if new_item is not item:
unchanged = False
if unchanged:
@@ -46,22 +47,43 @@ def _deepcopy_tuple(obj, memo, _id):
def _deepcopy_list(obj, memo, _id):
# Two steps here because a list can include itself
memo[_id] = ans = []
- ans.extend(fast_deepcopy(x, memo) for x in obj)
+ _append = ans.append
+ for x in obj:
+ _append(fast_deepcopy(x, memo))
return ans
def _deepcopy_dict(obj, memo, _id):
# Two steps here because a dict can include itself
memo[_id] = ans = {}
+ _setter = ans.__setitem__
for key, val in obj.items():
- ans[fast_deepcopy(key, memo)] = fast_deepcopy(val, memo)
+ _setter(fast_deepcopy(key, memo), fast_deepcopy(val, memo))
return ans
-def _deepcopier(obj, memo, _id):
+def _deepcopy_dunder_deepcopy(obj, memo, _id):
+ ans = memo[_id] = obj.__deepcopy__(memo)
+ return ans
+
+
+def _deepcopy(obj, memo, _id):
return deepcopy(obj, memo)
+class _DeepcopyDispatcher(collections.defaultdict):
+ def __missing__(self, key):
+ if hasattr(key, '__deepcopy__'):
+ ans = _deepcopy_dunder_deepcopy
+ else:
+ ans = _deepcopy
+ self[key] = ans
+ return ans
+
+
+_deepcopy_dispatcher = _DeepcopyDispatcher(
+ None, {tuple: _deepcopy_tuple, list: _deepcopy_list, dict: _deepcopy_dict}
+)
_atomic_types = {
int,
float,
@@ -76,8 +98,6 @@ def _deepcopier(obj, memo, _id):
types.FunctionType,
}
-_deepcopy_mapper = {tuple: _deepcopy_tuple, list: _deepcopy_list, dict: _deepcopy_dict}
-
def fast_deepcopy(obj, memo):
"""A faster implementation of copy.deepcopy()
@@ -87,6 +107,29 @@ def fast_deepcopy(obj, memo):
deepcopy that provides special handling to circumvent some of the
slowest parts of deepcopy().
+ Note
+ ----
+
+ This implementation is not as aggressive about keeping the copied
+ state alive until the end of the deepcopy operation. In particular,
+ the ``dict``, ``list`` and ``tuple`` handlers do not register their
+ source objects with the memo. This is acceptable, as
+ fast_deepcopy() is only called in situations where we are ensuring
+ that the source object will persist:
+
+ - :meth:`AutoSlots.__deepcopy_state__` explicitly preserved the
+ source state
+ - :meth:`Component.__deepcopy_field__` is only called by
+ :meth:`AutoSlots.__deepcopy_state__` -
+ - :meth:`IndexedComponent._create_objects_for_deepcopy` is
+ deepcopying the raw keys from the source ``_data`` dict (which is
+ not a temporary object and will persist)
+
+ If other consumers wish to make use of this function (e.g., within
+ their implementation of ``__deepcopy__``), they must remember that
+ they are responsible to ensure that any temporary source ``obj``
+ persists.
+
"""
if obj.__class__ in _atomic_types:
return obj
@@ -94,7 +137,7 @@ def fast_deepcopy(obj, memo):
if _id in memo:
return memo[_id]
else:
- return _deepcopy_mapper.get(obj.__class__, _deepcopier)(obj, memo, _id)
+ return _deepcopy_dispatcher[obj.__class__](obj, memo, _id)
class AutoSlots(type):
@@ -269,12 +312,104 @@ def __deepcopy__(self, memo):
"""
# Note: this implementation avoids deepcopying the temporary
# 'state' list, significantly speeding things up.
- memo[id(self)] = ans = self.__class__.__new__(self.__class__)
- ans.__setstate__(
- [fast_deepcopy(field, memo) for field in self.__getstate__()]
- )
+ ans = self.__class__.__new__(self.__class__)
+ self.__deepcopy_state__(memo, ans)
return ans
+ def __deepcopy_state__(self, memo, new_object):
+ """This implements the state copy from a source object to the new
+ instance in the deepcopy memo.
+
+ This splits out the logic for actually duplicating the
+ object state from the "boilerplate" that creates a new
+ object and registers the object in the memo. This allows us
+ to create new schemes for duplicating / registering objects
+ that reuse all the logic here for copying the state.
+
+ """
+ #
+ # At this point we know we need to deepcopy this object.
+ # But, we can't do the "obvious", since this is a
+ # (partially) slot-ized class and the __dict__ structure is
+ # nonauthoritative:
+ #
+ # for key, val in self.__dict__.iteritems():
+ # object.__setattr__(ans, key, deepcopy(val, memo))
+ #
+ # Further, __slots__ is also nonauthoritative (this may be a
+ # derived class that also has a __dict__), or this may be a
+ # derived class with several layers of slots. So, we will
+ # piggyback on the __getstate__/__setstate__ logic and
+ # resort to partially "pickling" the object, deepcopying the
+ # state, and then restoring the copy into the new instance.
+ #
+ # [JDS 7/7/14] I worry about the efficiency of using both
+ # getstate/setstate *and* deepcopy, but we need to update
+ # fields like weakrefs correctly (and that logic is all in
+ # __getstate__/__setstate__).
+ #
+ # There is a particularly subtle bug with 'uncopyable'
+ # attributes: if the exception is thrown while copying a
+ # complex data structure, we can be in a state where objects
+ # have been created and assigned to the memo in the try
+ # block, but they haven't had their state set yet. When the
+ # exception moves us into the except block, we need to
+ # effectively "undo" those partially copied classes. The
+ # only way is to restore the memo to the state it was in
+ # before we started. We will make use of the knowledge that
+ # 1) memo entries are never reassigned during a deepcopy(),
+ # and 2) dict are ordered by insertion order in Python >=
+ # 3.7. As a result, we do not need to preserve the whole
+ # memo before calling __getstate__/__setstate__, and can get
+ # away with only remembering the number of items in the
+ # memo.
+ #
+ state = self.__getstate__()
+ # It is important to keep this temporary state alive (which
+ # in turn keeps things like the temporary fields dict alive)
+ # until after deepcopy is finished in order to prevent
+ # accidentally recycling id()'s for temporary objects that
+ # were recorded in the memo. We will follow the pattern
+ # used by copy._keep_alive():
+ try:
+ memo['__auto_slots__'].append(state)
+ except KeyError:
+ memo['__auto_slots__'] = [state]
+
+ memo_size = len(memo)
+ try:
+ new_state = [fast_deepcopy(field, memo) for field in state]
+ except:
+ # We hit an error deepcopying the state. Attempt to
+ # reset things and try again, but in a more cautious
+ # manner.
+ #
+ # We want to remove any new entries added to the memo
+ # during the failed try above.
+ for _ in range(len(memo) - memo_size):
+ memo.popitem()
+ #
+ # Now we are going to continue on, but in a more
+ # cautious manner: we will clone entries field at a time
+ # so that we can get the most "complete" copy possible.
+ #
+ # Note: if has_dict, then __auto_slots__.slots will be 1
+ # shorter than the state (the last element is the
+ # __dict__). Zip will ignore it.
+ _copier = getattr(self, '__deepcopy_field__', _deepcopy)
+ new_state = [
+ _copier(value, memo, slot)
+ for slot, value in zip(self.__auto_slots__.slots, state)
+ ]
+ if self.__auto_slots__.has_dict:
+ new_state.append(
+ {
+ slot: _copier(value, memo, slot)
+ for slot, value in state[-1].items()
+ }
+ )
+ new_object.__setstate__(new_state)
+
def __getstate__(self):
"""Generic implementation of `__getstate__`
@@ -300,7 +435,7 @@ def __getstate__(self):
if self.__auto_slots__.has_dict:
fields = dict(self.__dict__)
# Map (encode) any field values. It is not an error if
- # the field if not present.
+ # the field is not present.
for name, mapper in self.__auto_slots__.field_mappers.items():
if name in fields:
fields[name] = mapper(True, fields[name])
diff --git a/pyomo/common/backports.py b/pyomo/common/backports.py
index e70b0f6d267..5ec7f7b2122 100644
--- a/pyomo/common/backports.py
+++ b/pyomo/common/backports.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/cmake_builder.py b/pyomo/common/cmake_builder.py
index 523dbf64c91..39918bda06c 100644
--- a/pyomo/common/cmake_builder.py
+++ b/pyomo/common/cmake_builder.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/collections/__init__.py b/pyomo/common/collections/__init__.py
index 717caf87b2c..2b6587bb4f0 100644
--- a/pyomo/common/collections/__init__.py
+++ b/pyomo/common/collections/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/collections/bunch.py b/pyomo/common/collections/bunch.py
index 2ae9cf8c517..34568565994 100644
--- a/pyomo/common/collections/bunch.py
+++ b/pyomo/common/collections/bunch.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/collections/component_map.py b/pyomo/common/collections/component_map.py
index 8dcfdb6c837..b0d4e9fb4ac 100644
--- a/pyomo/common/collections/component_map.py
+++ b/pyomo/common/collections/component_map.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -47,6 +47,18 @@ def _unhashable(val):
def _tuple(self, val):
return tuple(self[i.__class__](i) for i in val)
+ def hashable(self, obj, hashable=None):
+ if isinstance(obj, type):
+ cls = obj
+ else:
+ cls = type(obj)
+ if hashable is None:
+ fcn = self.get(cls, None)
+ if fcn is None:
+ raise KeyError(obj)
+ return fcn is self._hashable
+ self[cls] = self._hashable if hashable else self._unhashable
+
_hasher = _Hasher()
@@ -78,6 +90,8 @@ class ComponentMap(AutoSlots.Mixin, collections.abc.MutableMapping):
__slots__ = ("_dict",)
__autoslot_mappers__ = {'_dict': _rehash_keys}
+ # Expose a "public" interface to the global _hasher dict
+ hasher = _hasher
def __init__(self, *args, **kwds):
# maps id_hash(obj) -> (obj,val)
diff --git a/pyomo/common/collections/component_set.py b/pyomo/common/collections/component_set.py
index 6e12bad7277..82e40670801 100644
--- a/pyomo/common/collections/component_set.py
+++ b/pyomo/common/collections/component_set.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -61,6 +61,8 @@ class ComponentSet(AutoSlots.Mixin, collections_MutableSet):
__slots__ = ("_data",)
__autoslot_mappers__ = {'_data': _rehash_keys}
+ # Expose a "public" interface to the global _hasher dict
+ hasher = _hasher
def __init__(self, iterable=None):
# maps id_hash(obj) -> obj
diff --git a/pyomo/common/collections/orderedset.py b/pyomo/common/collections/orderedset.py
index 834101e3896..c364e016246 100644
--- a/pyomo/common/collections/orderedset.py
+++ b/pyomo/common/collections/orderedset.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/config.py b/pyomo/common/config.py
index 238bdd78e9d..806501d7df9 100644
--- a/pyomo/common/config.py
+++ b/pyomo/common/config.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -40,8 +40,8 @@
relocated_module_attribute,
)
from pyomo.common.fileutils import import_file
+from pyomo.common.flags import building_documentation, NOTSET
from pyomo.common.formatting import wrap_reStructuredText
-from pyomo.common.modeling import NOTSET
logger = logging.getLogger(__name__)
@@ -298,7 +298,7 @@ def __call__(self, value):
raise ValueError("%r is not a valid %s" % (value, self._domain.__name__))
def domain_name(self):
- return f'InEnum[{self._domain.__name__}]'
+ return f'InEnum[{_domain_name(self._domain)}]'
class IsInstance(object):
@@ -361,8 +361,8 @@ def __call__(self, obj):
raise ValueError(msg)
def domain_name(self):
- class_names = (self._get_class_name(kls) for kls in self.baseClasses)
- return f"IsInstance({', '.join(class_names)})"
+ class_names = (_domain_name(kls) for kls in self.baseClasses)
+ return f"IsInstance[{', '.join(class_names)}]"
class ListOf(object):
@@ -442,23 +442,22 @@ class Module(object):
name, by module name, or by module object. Regardless of how the module is
specified, what is stored in the configuration is a module object.
- .. doctest::
+ .. testcode::
- >>> from pyomo.common.config import (
- ... ConfigDict, ConfigValue, Module
- ... )
- >>> config = ConfigDict()
- >>> config.declare('my_module', ConfigValue(
- ... domain=Module(),
- ... ))
-
- >>> # Set using file path
- >>> config.my_module = '../../pyomo/common/tests/config_plugin.py'
- >>> # Set using python module name, as a string
- >>> config.my_module = 'os.path'
- >>> # Set using an imported module object
- >>> import os.path
- >>> config.my_module = os.path
+ from pyomo.common.config import (
+ ConfigDict, ConfigValue, Module
+ )
+ config = ConfigDict()
+ config.declare('my_module', ConfigValue(
+ domain=Module(),
+ ))
+ # Set using file path
+ config.my_module = '../../pyomo/common/tests/config_plugin.py'
+ # Set using python module name, as a string
+ config.my_module = 'os.path'
+ # Set using an imported module object
+ import os.path
+ config.my_module = os.path
"""
@@ -533,7 +532,7 @@ def __call__(self, path):
base = self.basePath
else:
base = Path.BasePath
- if type(base) is ConfigValue:
+ if isinstance(base, ConfigValue):
base = base.value()
if base is None:
base = ""
@@ -558,7 +557,7 @@ def __call__(self, path):
return ans
def domain_name(self):
- return type(self).__name__
+ return _domain_name(type(self))
class PathList(Path):
@@ -613,18 +612,24 @@ class DynamicImplicitDomain(object):
>>> import pyomo.common.fileutils
>>> from pyomo.common.config import ConfigDict, DynamicImplicitDomain
- .. doctest::
+ Then we can declare a `:class:``ConfigDict`` that imports the domain
+ for specific keys from a module that matches the key name:
+
+ .. testcode::
+
+ def _pluginImporter(name, config):
+ mod = importlib.import_module(name)
+ return mod.get_configuration(config)
+ config = ConfigDict()
+ config.declare('plugins', ConfigDict(
+ implicit=True,
+ implicit_domain=DynamicImplicitDomain(_pluginImporter)))
+ config.plugins['pyomo.common.tests.config_plugin'] = {'key1': 5}
+ config.display()
+
+
+ .. testoutput::
- >>> def _pluginImporter(name, config):
- ... mod = importlib.import_module(name)
- ... return mod.get_configuration(config)
- >>> config = ConfigDict()
- >>> config.declare('plugins', ConfigDict(
- ... implicit=True,
- ... implicit_domain=DynamicImplicitDomain(_pluginImporter)))
-
- >>> config.plugins['pyomo.common.tests.config_plugin'] = {'key1': 5}
- >>> config.display()
plugins:
pyomo.common.tests.config_plugin:
key1: 5
@@ -699,35 +704,37 @@ def from_enum_or_string(cls, arg):
Python's dict and list classes, respectively.
At its simplest, the Config system allows for developers to specify a
-dictionary of documented configuration entries, allow users to provide
-values for those entries, and retrieve the current values:
+dictionary of documented configuration entries:
+
+.. testcode::
+
+ from pyomo.common.config import (
+ ConfigDict, ConfigList, ConfigValue
+ )
+ config = ConfigDict()
+ config.declare('filename', ConfigValue(
+ default=None,
+ domain=str,
+ description="Input file name",
+ ))
+ config.declare("bound tolerance", ConfigValue(
+ default=1E-5,
+ domain=float,
+ description="Bound tolerance",
+ doc="Relative tolerance for bound feasibility checks"
+ ))
+ config.declare("iteration limit", ConfigValue(
+ default=30,
+ domain=int,
+ description="Iteration limit",
+ doc="Number of maximum iterations in the decomposition methods"
+ ))
+
+Users can then provide values for those entries, and retrieve the
+current values:
.. doctest::
- >>> from pyomo.common.config import (
- ... ConfigDict, ConfigList, ConfigValue
- ... )
- >>> config = ConfigDict()
- >>> config.declare('filename', ConfigValue(
- ... default=None,
- ... domain=str,
- ... description="Input file name",
- ... ))
-
- >>> config.declare("bound tolerance", ConfigValue(
- ... default=1E-5,
- ... domain=float,
- ... description="Bound tolerance",
- ... doc="Relative tolerance for bound feasibility checks"
- ... ))
-
- >>> config.declare("iteration limit", ConfigValue(
- ... default=30,
- ... domain=int,
- ... description="Iteration limit",
- ... doc="Number of maximum iterations in the decomposition methods"
- ... ))
-
>>> config['filename'] = 'tmp.txt'
>>> print(config['filename'])
tmp.txt
@@ -882,45 +889,40 @@ class will still create ``c`` instances that only have the single
simpler, the :py:meth:`declare` method returns the declared Config
object so that the argument declaration can be done inline:
-.. doctest::
-
- >>> import argparse
- >>> config = ConfigDict()
- >>> config.declare('iterlim', ConfigValue(
- ... domain=int,
- ... default=100,
- ... description="iteration limit",
- ... )).declare_as_argument()
-
- >>> config.declare('lbfgs', ConfigValue(
- ... domain=bool,
- ... description="use limited memory BFGS update",
- ... )).declare_as_argument()
-
- >>> config.declare('linesearch', ConfigValue(
- ... domain=bool,
- ... default=True,
- ... description="use line search",
- ... )).declare_as_argument()
-
- >>> config.declare('relative tolerance', ConfigValue(
- ... domain=float,
- ... description="relative convergence tolerance",
- ... )).declare_as_argument('--reltol', '-r', group='Tolerances')
-
- >>> config.declare('absolute tolerance', ConfigValue(
- ... domain=float,
- ... description="absolute convergence tolerance",
- ... )).declare_as_argument('--abstol', '-a', group='Tolerances')
-
+.. testcode::
+
+ import argparse
+ config = ConfigDict()
+ config.declare('iterlim', ConfigValue(
+ domain=int,
+ default=100,
+ description="iteration limit",
+ )).declare_as_argument()
+ config.declare('lbfgs', ConfigValue(
+ domain=bool,
+ description="use limited memory BFGS update",
+ )).declare_as_argument()
+ config.declare('linesearch', ConfigValue(
+ domain=bool,
+ default=True,
+ description="use line search",
+ )).declare_as_argument()
+ config.declare('relative tolerance', ConfigValue(
+ domain=float,
+ description="relative convergence tolerance",
+ )).declare_as_argument('--reltol', '-r', group='Tolerances')
+ config.declare('absolute tolerance', ConfigValue(
+ domain=float,
+ description="absolute convergence tolerance",
+ )).declare_as_argument('--abstol', '-a', group='Tolerances')
The ConfigDict can then be used to initialize (or augment) an argparse
ArgumentParser object:
-.. doctest::
+.. testcode::
- >>> parser = argparse.ArgumentParser("tester")
- >>> config.initialize_argparse(parser)
+ parser = argparse.ArgumentParser("tester")
+ config.initialize_argparse(parser)
Key information from the ConfigDict is automatically transferred over
@@ -945,10 +947,8 @@ class will still create ``c`` instances that only have the single
--disable-linesearch [DON'T] use line search
Tolerances:
- --reltol FLOAT, -r FLOAT
- relative convergence tolerance
- --abstol FLOAT, -a FLOAT
- absolute convergence tolerance
+ --reltol... -r FLOAT relative convergence tolerance
+ --abstol... -a FLOAT absolute convergence tolerance
.. doctest::
@@ -996,34 +996,34 @@ class will still create ``c`` instances that only have the single
:py:meth:`generate_documentation()`. The simplest is
:py:meth:`display()`, which prints out the current values of the
configuration object (and if it is a container type, all of it's
-children). :py:meth:`generate_yaml_template` is simular to
+children). :py:meth:`generate_yaml_template` is similar to
:py:meth:`display`, but also includes the description fields as
formatted comments.
+.. testcode::
+
+ solver_config = config
+ config = ConfigDict()
+ config.declare('output', ConfigValue(
+ default='results.yml',
+ domain=str,
+ description='output results filename'
+ ))
+ config.declare('verbose', ConfigValue(
+ default=0,
+ domain=int,
+ description='output verbosity',
+ doc='This sets the system verbosity. The default (0) only logs '
+ 'warnings and errors. Larger integer values will produce '
+ 'additional log messages.',
+ ))
+ config.declare('solvers', ConfigList(
+ domain=solver_config,
+ description='list of solvers to apply',
+ ))
+
.. doctest::
- >>> solver_config = config
- >>> config = ConfigDict()
- >>> config.declare('output', ConfigValue(
- ... default='results.yml',
- ... domain=str,
- ... description='output results filename'
- ... ))
-
- >>> config.declare('verbose', ConfigValue(
- ... default=0,
- ... domain=int,
- ... description='output verbosity',
- ... doc='This sets the system verbosity. The default (0) only logs '
- ... 'warnings and errors. Larger integer values will produce '
- ... 'additional log messages.',
- ... ))
-
- >>> config.declare('solvers', ConfigList(
- ... domain=solver_config,
- ... description='list of solvers to apply',
- ... ))
-
>>> config.display()
output: results.yml
verbose: 0
@@ -1116,6 +1116,8 @@ def _dump(*args, **kwds):
def dump(x, **args):
if type(x) is bool:
return str(x).lower()
+ if type(x) is type:
+ return str(type(x))
return str(x)
assert '_dump' in globals()
@@ -1133,12 +1135,26 @@ def _munge_name(name, space_to_dash=True):
def _domain_name(domain):
if domain is None:
return ""
- elif hasattr(domain, 'domain_name'):
- return domain.domain_name()
- elif domain.__class__ is type:
- return domain.__name__
+ if hasattr(domain, 'domain_name') and not isinstance(domain, type):
+ dn = domain.domain_name
+ if hasattr(dn, '__call__'):
+ return dn()
+ else:
+ return dn
+ if domain.__module__ == 'builtins':
+ module = ""
+ else:
+ module = "~" + domain.__module__ + '.'
+ if isinstance(domain, type):
+ if building_documentation():
+ return module + domain.__qualname__
+ else:
+ return domain.__name__
elif inspect.isfunction(domain):
- return domain.__name__
+ if building_documentation():
+ return module + domain.__qualname__
+ else:
+ return domain.__name__
else:
return None
@@ -1168,17 +1184,17 @@ def _value2string(prefix, value, obj):
_str = prefix
if value is not None:
try:
- _data = value._data if value is obj else value
- if getattr(builtins, _data.__class__.__name__, None) is not None:
+ data = value.value(False) if value is obj else value
+ if getattr(builtins, data.__class__.__name__, None) is not None:
_str += _dump(
- _data, default_flow_style=True, allow_unicode=True
+ data, default_flow_style=True, allow_unicode=True
).rstrip()
if _str.endswith("..."):
_str = _str[:-3].rstrip()
else:
- _str += str(_data)
+ _str += str(data)
except:
- _str += str(type(_data))
+ _str += str(type(data))
return _str.rstrip()
@@ -1186,12 +1202,12 @@ def _value2yaml(prefix, value, obj):
_str = prefix
if value is not None:
try:
- _data = value._data if value is obj else value
- _str += _dump(_data, default_flow_style=True).rstrip()
+ data = value.value(False) if value is obj else value
+ _str += _dump(data, default_flow_style=True).rstrip()
if _str.endswith("..."):
_str = _str[:-3].rstrip()
except:
- _str += str(type(_data))
+ _str += str(type(data))
return _str.rstrip()
@@ -1201,7 +1217,7 @@ def __init__(self, obj):
self._name = obj.name(True)
def __call__(self, arg):
- logging.error(
+ logger.error(
"""%s '%s' was pickled with an unpicklable domain.
The domain was stripped and lost during the pickle process. Setting
new values on the restored object cannot be mapped into the correct
@@ -1483,7 +1499,7 @@ def _item_body(self, indent, obj):
(
'optional'
if obj._default is None
- else f'default={repr(obj._default)}'
+ else f'default={obj._default!r}'
),
],
)
@@ -1516,7 +1532,7 @@ def _item_body(self, indent, obj):
self.wrapper,
)
if itemdoc:
- self.out.write(itemdoc + '\n')
+ self.out.write('\n' + itemdoc + '\n')
def _finalize(self):
return inspect.cleandoc(self.out.getvalue())
@@ -1660,15 +1676,83 @@ def __call__(self, fcn):
return fcn
+class UninitializedMixin(object):
+ """Mixin class to support delayed data initialization.
+
+ This mixin can be used to create a derived Config class that hides
+ the (uninitialized) ``_data`` attribute behind a property. Any
+ attempt to access the ``_data`` will trigger the initialization of the
+ Config object from its ``_default`` value. Setting the ``_data``
+ attribute will also trigger resolution of the Config object, but
+ without processing the ``_default__``.
+
+ """
+
+ __slots__ = ()
+
+ @property
+ def _data(self):
+ #
+ # We assume that _default is usually a concrete value. But, we
+ # also accept a types (classes) and initialization functions as
+ # defaults, in which case we will construct an instance of that
+ # class and use that as the default. If they both raise
+ # exceptions, we will let the original exception propagate up.
+ #
+ try:
+ self._setter(self._default)
+ except:
+ if hasattr(self._default, '__call__'):
+ _default_val = self._default()
+ try:
+ self._setter(_default_val)
+ return self._data
+ except:
+ pass
+ raise
+ return self._data
+
+ @_data.setter
+ def _data(self, value):
+ _mro = self.__class__.__mro__
+ # There is an edge case in multithreaded environments where this
+ # function could actually be called more than once for a single
+ # ConfigValue. We want to make sure that only the first of the
+ # calls actually updates the __class__ (the others will
+ # recursively lookup the _data attribute and the second lookup
+ # will resolve to normal attribute assignment).
+ #
+ # We first encountered this issue for Config objects stores as
+ # class attributes (i.e., the default Config for something like
+ # a solver or writer) and multiple threads were simultaneously
+ # creating instances of the class (each of which was resolving
+ # the default values for the class attribute).
+ #
+ # Note that this explicitly assumes that the uninitialized
+ # Config object was defined as:
+ #
+ # class UninitializedConfig(UninitializedMixin, Config)
+ #
+ # and that the resulting class was never inherited from. If
+ # this assumption is ever violated, attempts to use the
+ # uninitialized config object will generate infinite recursion
+ # (and that is OK, as the developer should immediately be
+ # informed of their error)
+ if _mro[1] is UninitializedMixin:
+ self.__class__ = _mro[2]
+ self._data = value
+
+
class ConfigBase(object):
+ # Note: __getstate__ relies on this field ordering. Do not change.
__slots__ = (
'_parent',
+ '_domain',
'_name',
'_userSet',
'_userAccessed',
'_data',
'_default',
- '_domain',
'_description',
'_doc',
'_visibility',
@@ -1690,13 +1774,15 @@ def __init__(
self._userSet = False
self._userAccessed = False
- self._data = None
+ self._data = NOTSET
self._default = default
self._domain = domain
self._description = _strip_indentation(description)
self._doc = _strip_indentation(doc)
self._visibility = visibility
self._argparse = None
+ if self._UninitializedClass is not None:
+ self.__class__ = self._UninitializedClass
def __getstate__(self):
# Nominally, __getstate__() should return:
@@ -1714,13 +1800,15 @@ def __getstate__(self):
# can allocate the state dictionary. If it is not, then we call
# the super-class's __getstate__ (since that class is NOT
# 'object').
- state = {key: getattr(self, key) for key in ConfigBase.__slots__}
- state['_domain'] = _picklable(state['_domain'], self)
- state['_parent'] = None
+ state = [None, _picklable(self._domain, self)]
+ # Note: [2:] skips _parent and _domain (intentionally): We just
+ # wrapped _domain in _picklable and explicitly set _parent to
+ # None (it will be restored in __setstate__).
+ state.extend(getattr(self, key) for key in ConfigBase.__slots__[2:])
return state
def __setstate__(self, state):
- for key, val in state.items():
+ for key, val in zip(ConfigBase.__slots__, state):
# Note: per the Python data model docs, we explicitly
# set the attribute using object.__setattr__() instead
# of setting self.__dict__[key] = val.
@@ -1752,7 +1840,11 @@ def __call__(
assert default is NOTSET
else:
fields += ('domain',)
- kwds['default'] = self.value() if default is NOTSET else default
+ if default is NOTSET:
+ default = self.value()
+ if default is NOTSET:
+ default = None
+ kwds['default'] = default
assert implicit is NOTSET
assert implicit_domain is NOTSET
for field in fields:
@@ -1768,9 +1860,7 @@ def __call__(
# Initialize the new config object
ans = self.__class__(**kwds)
- if not isinstance(self, ConfigDict):
- ans.reset()
- else:
+ if isinstance(self, ConfigDict):
# Copy over any Dict definitions
for k, v in self._data.items():
if preserve_implicit or k in self._declared:
@@ -1836,17 +1926,9 @@ def _cast(self, value):
return value
def reset(self):
- #
- # This is a dangerous construct, the failure in the first try block
- # can mask a real problem.
- #
- try:
- self.set_value(self._default)
- except:
- if hasattr(self._default, '__call__'):
- self.set_value(self._default())
- else:
- raise
+ # Reset the object back to its default value and clear the
+ # userSet and userAccessed flags
+ self._UninitializedClass._data.fget(self)
self._userAccessed = False
self._userSet = False
@@ -2167,20 +2249,18 @@ class ConfigValue(ConfigBase):
"""
- def __init__(self, *args, **kwds):
- ConfigBase.__init__(self, *args, **kwds)
- self.reset()
+ __slots__ = ()
def value(self, accessValue=True):
if accessValue:
self._userAccessed = True
return self._data
- def set_value(self, value):
- # Trap self-assignment (useful for providing editor completion)
- if value is self:
- return
+ def _setter(self, value):
self._data = self._cast(value)
+
+ def set_value(self, value):
+ self._setter(value)
self._userSet = True
def _data_collector(self, level, prefix, visibility=None, docMode=False):
@@ -2189,17 +2269,28 @@ def _data_collector(self, level, prefix, visibility=None, docMode=False):
yield (level, prefix, self, self)
+ConfigValue._UninitializedClass = type(
+ 'UninitializedConfigValue', (UninitializedMixin, ConfigValue), {'__slots__': ()}
+)
+
+
class ImmutableConfigValue(ConfigValue):
+ __slots__ = ()
+
def __new__(self, *args, **kwds):
# ImmutableConfigValue objects are never directly created, and
# any attempt to copy one will generate a mutable ConfigValue
# object
return ConfigValue(*args, **kwds)
- def set_value(self, value):
- if self._cast(value) != self._data:
- raise RuntimeError(str(self) + ' is currently immutable')
- super(ImmutableConfigValue, self).set_value(value)
+ def _setter(self, value):
+ try:
+ _data = self._data
+ super()._setter(value)
+ if _data != self._data:
+ raise RuntimeError(f"'{self.name(True)}' is currently immutable")
+ finally:
+ self._data = _data
class MarkImmutable(object):
@@ -2214,14 +2305,48 @@ class MarkImmutable(object):
Examples
--------
- >>> config = ConfigDict()
- >>> config.declare('a', ConfigValue(default=1, domain=int))
- >>> config.declare('b', ConfigValue(default=1, domain=int))
- >>> locker = MarkImmutable(config.get('a'), config.get('b'))
+ .. testcode::
+
+ config = ConfigDict()
+ config.declare('a', ConfigValue(default=1, domain=int))
+ config.declare('b', ConfigValue(default=1, domain=int))
+ locker = MarkImmutable(config.get('a'), config.get('b'))
+
+ Now, config.a and config.b cannot be changed:
+
+ .. doctest::
+
+ >>> config.a = 5
+ Traceback (most recent call last):
+ ...
+ RuntimeError: ConfigValue 'a' is currently immutable
+ >>> print(config.a)
+ 1
- Now, config.a and config.b cannot be changed. To make them mutable again,
+ To make them mutable again,
+
+ .. doctest::
+
+ >>> locker.release_lock()
+ >>> config.a = 5
+ >>> print(config.a)
+ 5
+
+ Note that this can be used as a context manager as well:
+
+ .. doctest::
+
+ >>> with MarkImmutable(config.get('a'), config.get('b')):
+ ... config.a = 10
+ Traceback (most recent call last):
+ ...
+ RuntimeError: ConfigValue 'a' is currently immutable
+ >>> print(config.a)
+ 5
+ >>> config.a = 10
+ >>> print(config.a)
+ 10
- >>> locker.release_lock()
"""
def __init__(self, *args):
@@ -2233,9 +2358,13 @@ def lock(self):
try:
for cfg in self._targets:
if type(cfg) is not ConfigValue:
- raise ValueError(
- 'Only ConfigValue instances can be marked immutable.'
- )
+ if isinstance(cfg, ConfigValue):
+ # Resolve any UninitializedConfigValue
+ cfg._data
+ else:
+ raise ValueError(
+ 'Only ConfigValue instances can be marked immutable.'
+ )
cfg.__class__ = ImmutableConfigValue
self._locked.append(cfg)
except:
@@ -2295,15 +2424,25 @@ class ConfigList(ConfigBase, Sequence):
"""
- def __init__(self, *args, **kwds):
- ConfigBase.__init__(self, *args, **kwds)
- if self._domain is None:
- self._domain = ConfigValue()
- elif isinstance(self._domain, ConfigBase):
+ __slots__ = ()
+
+ def __init__(
+ self, default=None, domain=None, description=None, doc=None, visibility=0
+ ):
+ if domain is None:
+ domain = ConfigValue()
+ elif isinstance(domain, ConfigBase):
pass
else:
- self._domain = ConfigValue(None, domain=self._domain)
- self.reset()
+ domain = ConfigValue(None, domain=domain)
+ ConfigBase.__init__(
+ self,
+ default=default,
+ domain=domain,
+ description=description,
+ doc=doc,
+ visibility=visibility,
+ )
def __setstate__(self, state):
state = super(ConfigList, self).__setstate__(state)
@@ -2352,43 +2491,43 @@ def value(self, accessValue=True):
self._userAccessed = True
return [config.value(accessValue) for config in self._data]
- def set_value(self, value):
- # If the set_value fails part-way through the list values, we
+ def _setter(self, value):
+ # If the _setter fails part-way through the list values, we
# want to restore a deterministic state. That is, either
# set_value succeeds completely, or else nothing happens.
- _old = self._data
- self._data = []
- try:
- if isinstance(value, str):
- value = list(_default_string_list_lexer(value))
- if (type(value) is list) or isinstance(value, ConfigList):
- for val in value:
- self.append(val)
- else:
- self.append(value)
- except:
- self._data = _old
- raise
- self._userSet = True
+ _data = []
+ if isinstance(value, str):
+ value = list(_default_string_list_lexer(value))
+ if (type(value) is list) or isinstance(value, ConfigList):
+ for val in value:
+ self._append(_data, val)
+ else:
+ self._append(_data, value)
+ self._data = _data
- def reset(self):
- ConfigBase.reset(self)
- # Because the base reset() calls set_value, any deefault list
- # entries will get their userSet flag set. This is wrong, as
- # reset() should conceptually reset the object to it's default
- # state (e.g., before the user ever had a chance to mess with
- # things). As the list could contain a ConfigDict, this is a
- # recursive operation to put the userSet values back.
- for val in self.user_values():
- val._userSet = False
+ def set_value(self, value):
+ self._setter(value)
+ self._userSet = True
+ for _data in self._data:
+ _data._userSet = True
- def append(self, value=NOTSET):
+ def _append(self, _data, value):
val = self._cast(value)
if val is None:
return
- self._data.append(val)
- self._data[-1]._parent = self
- self._data[-1]._name = '[%s]' % (len(self._data) - 1,)
+ val._parent = self
+ val._name = f'[{len(_data)}]'
+ # We need to reset the _userSet to False because the List domain
+ # is a ConfigValue and __call__ will trigger set_value(), which
+ # will set the _userSet flag. As we get here during _default
+ # processing, we want to clear that flag. If this is actually
+ # getting triggered through set_value() / append(), then
+ # append() will be responsible for setting _userSet.
+ val._userSet = False
+ _data.append(val)
+
+ def append(self, value=NOTSET):
+ self._append(self._data, value)
self._data[-1]._userSet = True
# Adding something to the container should not change the
# userSet on the container (see Pyomo/pyomo#352; now
@@ -2431,6 +2570,11 @@ def _data_collector(self, level, prefix, visibility=None, docMode=False):
yield v
+ConfigList._UninitializedClass = type(
+ 'UninitializedConfigList', (UninitializedMixin, ConfigList), {'__slots__': ()}
+)
+
+
class ConfigDict(ConfigBase, Mapping):
"""Store and manipulate a dictionary of configuration values.
@@ -2465,8 +2609,9 @@ class ConfigDict(ConfigBase, Mapping):
content_filters = {None, 'all', 'userdata'}
- __slots__ = ('_declared', '_implicit_declaration', '_implicit_domain')
- _all_slots = set(__slots__ + ConfigBase.__slots__)
+ # Note: __getstate__ relies on this field ordering. Do not change.
+ __slots__ = ('_implicit_domain', '_declared', '_implicit_declaration')
+ _reserved_words = set()
def __init__(
self,
@@ -2493,13 +2638,17 @@ def domain_name(self):
return _munge_name(self.name(), False)
def __getstate__(self):
- state = super(ConfigDict, self).__getstate__()
- state.update((key, getattr(self, key)) for key in ConfigDict.__slots__)
- state['_implicit_domain'] = _picklable(state['_implicit_domain'], self)
+ state = super().__getstate__()
+ state.append(_picklable(self._implicit_domain, self))
+ # Note: [1:] intentionally skips the _implicit_domain (which we
+ # just handled)
+ state.extend(getattr(self, key) for key in ConfigDict.__slots__[1:])
return state
def __setstate__(self, state):
- state = super(ConfigDict, self).__setstate__(state)
+ super().__setstate__(state)
+ for key, val in zip(ConfigDict.__slots__, state[len(ConfigBase.__slots__) :]):
+ object.__setattr__(self, key, val)
for x in self._data.values():
x._parent = self
@@ -2545,8 +2694,11 @@ def __setitem__(self, key, val):
if _key not in self._data:
self.add(key, val)
else:
- self._data[_key].set_value(val)
- # self._userAccessed = True
+ cfg = self._data[_key]
+ # Trap self-assignment (useful for providing editor completion)
+ if cfg is val:
+ return
+ cfg.set_value(val)
def __delitem__(self, key):
# Note that this will produce a KeyError if the key is not valid
@@ -2566,20 +2718,23 @@ def __len__(self):
def __iter__(self):
return map(attrgetter('_name'), self._data.values())
- def __getattr__(self, name):
+ def __getattr__(self, attr):
# Note: __getattr__ is only called after all "usual" attribute
# lookup methods have failed. So, if we get here, we already
# know that key is not a __slot__ or a method, etc...
- # if name in ConfigDict._all_slots:
- # return super(ConfigDict,self).__getattribute__(name)
- _name = name.replace(' ', '_')
- if _name not in self._data:
- raise AttributeError("Unknown attribute '%s'" % name)
- return ConfigDict.__getitem__(self, _name)
+ _attr = attr.replace(' ', '_')
+ # Note: we test for "_data" because finding attributes on a
+ # partially constructed ConfigDict (before the _data attribute
+ # was declared) can lead to infinite recursion.
+ if _attr == "_data" or _attr not in self._data:
+ raise AttributeError(
+ f"'{type(self).__name__}' object has no attribute '{attr}'"
+ )
+ return ConfigDict.__getitem__(self, _attr)
def __setattr__(self, name, value):
- if name in ConfigDict._all_slots:
- super(ConfigDict, self).__setattr__(name, value)
+ if name in ConfigDict._reserved_words:
+ super().__setattr__(name, value)
else:
ConfigDict.__setitem__(self, name, value)
@@ -2764,5 +2919,8 @@ def _data_collector(self, level, prefix, visibility=None, docMode=False):
yield from cfg._data_collector(level, cfg._name + ': ', visibility, docMode)
+ConfigDict._UninitializedClass = None
+ConfigDict._reserved_words.update(dir(ConfigDict))
+
# Backwards compatibility: ConfigDict was originally named ConfigBlock.
ConfigBlock = ConfigDict
diff --git a/pyomo/common/dependencies.py b/pyomo/common/dependencies.py
index 9e96fdd5860..61fbb645e3c 100644
--- a/pyomo/common/dependencies.py
+++ b/pyomo/common/dependencies.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,16 +9,24 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from collections.abc import Mapping
import inspect
import importlib
+import importlib.util
import logging
import sys
import warnings
-from .deprecation import deprecated, deprecation_warning, in_testing_environment
-from .errors import DeferredImportError
-
+from collections.abc import Mapping
+from types import ModuleType
+from typing import List
+
+from pyomo.common.deprecation import deprecated, deprecation_warning
+from pyomo.common.errors import DeferredImportError
+from pyomo.common.flags import (
+ in_testing_environment,
+ building_documentation,
+ serializing,
+)
SUPPRESS_DEPENDENCY_WARNINGS = False
@@ -67,10 +75,9 @@ def __init__(self, name, message, version_error, import_error, package):
self._moduleunavailable_info_ = (message, version_error, import_error, package)
def __getattr__(self, attr):
- if attr in ModuleUnavailable._getattr_raises_attributeerror:
- raise AttributeError(
- "'%s' object has no attribute '%s'" % (type(self).__name__, attr)
- )
+ if serializing() or attr in ModuleUnavailable._getattr_raises_attributeerror:
+ msg = "'%s' object has no attribute '%s'" % (type(self).__name__, attr)
+ raise AttributeError(msg)
raise DeferredImportError(self._moduleunavailable_message())
def __getstate__(self):
@@ -127,7 +134,7 @@ class DeferredImportModule(object):
This object is returned by :py:func:`attempt_import()` in lieu of
the module when :py:func:`attempt_import()` is called with
- ``defer_check=True``. Any attempts to access attributes on this
+ ``defer_import=True``. Any attempts to access attributes on this
object will trigger the actual module import and return either the
appropriate module attribute or else if the module import fails,
raise a :py:class:`.DeferredImportError` exception.
@@ -223,6 +230,13 @@ def UnavailableClass(unavailable_module):
As does attempting to access class attributes on the derived class:
+ .. testcode::
+ :hide:
+
+ # We suppress this exception when building the documentation
+ # from pyomo.common.flags import building_documentation
+ building_documentation(False)
+
.. doctest::
>>> MyPlugin.create_instance()
@@ -233,10 +247,21 @@ def UnavailableClass(unavailable_module):
dependency was not found (import raised ModuleNotFoundError: No module
named 'bogus_unavailable_class')
+ .. testcode::
+ :hide:
+
+ building_documentation(None)
+
"""
class UnavailableMeta(type):
def __getattr__(cls, name):
+ if building_documentation():
+ # If we are building documentation, avoid the
+ # DeferredImportError (we will still raise one if
+ # someone attempts to *create* an instance of this
+ # class)
+ return getattr(super(), name)
raise DeferredImportError(
unavailable_module._moduleunavailable_message(
f"The class attribute '{cls.__name__}.{name}' is not available "
@@ -312,6 +337,12 @@ def __init__(
self._module = None
self._available = None
self._deferred_submodules = deferred_submodules
+ # If this import has a callback, then record this deferred
+ # import so that any direct imports of this module also trigger
+ # the resolution of this DeferredImportIndicator (and the
+ # corresponding callback)
+ if callback is not None:
+ DeferredImportCallbackFinder._callbacks.setdefault(name, []).append(self)
def __bool__(self):
self.resolve()
@@ -433,6 +464,102 @@ def check_min_version(module, min_version):
check_min_version._parser = None
+#
+# Note that we are duck-typing the Loader and MetaPathFinder base
+# classes from importlib.abc. This avoids a (surprisingly costly)
+# import of importlib.abc
+#
+class DeferredImportCallbackLoader:
+ """Custom Loader to resolve registered :py:class:`DeferredImportIndicator` objects
+
+ This :py:class:`importlib.abc.Loader` loader wraps a regular loader
+ and automatically resolves the registered
+ :py:class:`DeferredImportIndicator` objects after the module is
+ loaded.
+
+ """
+
+ def __init__(self, loader, deferred_indicators: List[DeferredImportIndicator]):
+ self._loader = loader
+ self._deferred_indicators = deferred_indicators
+
+ def module_repr(self, module: ModuleType) -> str:
+ return self._loader.module_repr(module)
+
+ def create_module(self, spec) -> ModuleType:
+ return self._loader.create_module(spec)
+
+ def exec_module(self, module: ModuleType) -> None:
+ self._loader.exec_module(module)
+ # Now that the module has been loaded, trigger the resolution of
+ # the deferred indicators (and their associated callbacks)
+ for deferred in self._deferred_indicators:
+ deferred.resolve()
+
+ def load_module(self, fullname) -> ModuleType:
+ return self._loader.load_module(fullname)
+
+
+class DeferredImportCallbackFinder:
+ """Custom Finder that will wrap the normal loader to trigger callbacks
+
+ This :py:class:`importlib.abc.MetaPathFinder` finder will wrap the
+ normal loader returned by ``PathFinder`` with a loader that will
+ trigger custom callbacks after the module is loaded. We use this to
+ trigger the post import callbacks registered through
+ :py:func:`attempt_import` even when a user imports the target library
+ directly (and not through attribute access on the
+ :py:class:`DeferredImportModule`.
+
+ """
+
+ _callbacks = {}
+
+ def find_spec(self, fullname, path, target=None):
+ if fullname not in self._callbacks:
+ return None
+
+ spec = None
+ # Continue looking for the finder that would have originally
+ # loaded the deferred import module by starting at the next
+ # finder in sys.meta_path (this way, we are agnostic to where
+ # the module is coming from: file system, registry, etc.)
+ for finder in sys.meta_path[sys.meta_path.index(self) + 1 :]:
+ if hasattr(finder, 'find_spec'):
+ # Support standard importlib MetaPathFinders
+ spec = finder.find_spec(fullname, path, target)
+ if spec is not None:
+ break
+ else:
+ # Support for imp finders/loaders (deprecated, but
+ # supported through Python 3.11)
+ loader = finder.find_module(fullname, path)
+ if loader is not None:
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ break
+ else:
+ # Module not found. Returning None will proceed to the next
+ # finder (which will eventually raise a ModuleNotFoundError)
+ return None
+ # Override the loader to trigger the finalization callback
+ # after the original loader is finished
+ spec.loader = DeferredImportCallbackLoader(
+ spec.loader, self._callbacks[fullname]
+ )
+ return spec
+
+ def invalidate_caches(self):
+ pass
+
+
+_DeferredImportCallbackFinder = DeferredImportCallbackFinder()
+# Insert the DeferredImportCallbackFinder at the beginning of the
+# sys.meta_path so that it is found before the standard finders (so that
+# we can correctly inject the resolution of the DeferredImportIndicators
+# -- which triggers the needed callbacks)
+sys.meta_path.insert(0, _DeferredImportCallbackFinder)
+
+
def attempt_import(
name,
error_message=None,
@@ -441,7 +568,8 @@ def attempt_import(
alt_names=None,
callback=None,
importer=None,
- defer_check=True,
+ defer_check=None,
+ defer_import=None,
deferred_submodules=None,
catch_exceptions=None,
):
@@ -495,7 +623,8 @@ def attempt_import(
The message for the exception raised by :py:class:`ModuleUnavailable`
only_catch_importerror: bool, optional
- DEPRECATED: use catch_exceptions instead or only_catch_importerror.
+ DEPRECATED: use ``catch_exceptions`` instead of ``only_catch_importerror``.
+
If True (the default), exceptions other than ``ImportError`` raised
during module import will be reraised. If False, any exception
will result in returning a :py:class:`ModuleUnavailable` object.
@@ -506,13 +635,14 @@ def attempt_import(
``module.__version__``)
alt_names: list, optional
- DEPRECATED: alt_names no longer needs to be specified and is ignored.
+ DEPRECATED: ``alt_names`` no longer needs to be specified and is ignored.
+
A list of common alternate names by which to look for this
module in the ``globals()`` namespaces. For example, the alt_names
for NumPy would be ``['np']``. (deprecated in version 6.0)
- callback: function, optional
- A function with the signature "``fcn(module, available)``" that
+ callback: Callable[[ModuleType, bool], None], optional
+ A function with the signature ``fcn(module, available)`` that
will be called after the import is first attempted.
importer: function, optional
@@ -522,10 +652,16 @@ def attempt_import(
want to import/return the first one that is available.
defer_check: bool, optional
- If True (the default), then the attempted import is deferred
- until the first use of either the module or the availability
- flag. The method will return instances of :py:class:`DeferredImportModule`
- and :py:class:`DeferredImportIndicator`.
+ DEPRECATED: renamed to ``defer_import`` (deprecated in version 6.7.2)
+
+ defer_import: bool, optional
+ If True, then the attempted import is deferred until the first
+ use of either the module or the availability flag. The method
+ will return instances of :py:class:`DeferredImportModule` and
+ :py:class:`DeferredImportIndicator`. If False, the import will
+ be attempted immediately. If not set, then the import will be
+ deferred unless the ``name`` is already present in
+ ``sys.modules``.
deferred_submodules: Iterable[str], optional
If provided, an iterable of submodule names within this module
@@ -576,9 +712,26 @@ def attempt_import(
if catch_exceptions is None:
catch_exceptions = (ImportError,)
+ if defer_check is not None:
+ deprecation_warning(
+ 'defer_check=%s is deprecated. Please use defer_import' % (defer_check,),
+ version='6.7.2',
+ )
+ assert defer_import is None
+ defer_import = defer_check
+
+ # If the module has already been imported, there is no reason to
+ # further defer things: just import it.
+ if defer_import is None:
+ if name in sys.modules:
+ defer_import = False
+ deferred_submodules = None
+ else:
+ defer_import = True
+
# If we are going to defer the check until later, return the
# deferred import module object
- if defer_check:
+ if defer_import:
if deferred_submodules:
if isinstance(deferred_submodules, Mapping):
deprecation_warning(
@@ -621,7 +774,7 @@ def attempt_import(
return DeferredImportModule(indicator, deferred, None), indicator
if deferred_submodules:
- raise ValueError("deferred_submodules is only valid if defer_check==True")
+ raise ValueError("deferred_submodules is only valid if defer_import==True")
return _perform_import(
name=name,
@@ -672,6 +825,11 @@ def _perform_import(
return module, False
+@deprecated(
+ "``declare_deferred_modules_as_importable()`` is deprecated. "
+ "Use the :py:class:`declare_modules_as_importable` context manager.",
+ version='6.7.2',
+)
def declare_deferred_modules_as_importable(globals_dict):
"""Make all :py:class:`DeferredImportModules` in ``globals_dict`` importable
@@ -698,6 +856,7 @@ def declare_deferred_modules_as_importable(globals_dict):
... 'scipy', callback=_finalize_scipy,
... deferred_submodules=['stats', 'sparse', 'spatial', 'integrate'])
>>> declare_deferred_modules_as_importable(globals())
+ WARNING: DEPRECATED: ...
Which enables users to use:
@@ -712,20 +871,87 @@ def declare_deferred_modules_as_importable(globals_dict):
:py:class:`ModuleUnavailable` instance.
"""
- _global_name = globals_dict['__name__'] + '.'
- deferred = list(
- (k, v) for k, v in globals_dict.items() if type(v) is DeferredImportModule
- )
- while deferred:
- name, mod = deferred.pop(0)
- mod.__path__ = None
- mod.__spec__ = None
- sys.modules[_global_name + name] = mod
- deferred.extend(
- (name + '.' + k, v)
- for k, v in mod.__dict__.items()
- if type(v) is DeferredImportModule
- )
+ return declare_modules_as_importable(globals_dict).__exit__(None, None, None)
+
+
+class declare_modules_as_importable(object):
+ """Make all :py:class:`ModuleType` and :py:class:`DeferredImportModules`
+ importable through the ``globals_dict`` context.
+
+ This context manager will detect all modules imported into the
+ specified ``globals_dict`` environment (either directly or through
+ :py:func:`attempt_import`) and will make those modules importable
+ from the specified ``globals_dict`` context. It works by detecting
+ changes in the specified ``globals_dict`` dictionary and adding any new
+ modules or instances of :py:class:`DeferredImportModule` that it
+ finds (and any of their deferred submodules) to ``sys.modules`` so
+ that the modules can be imported through the ``globals_dict``
+ namespace.
+
+ For example, ``pyomo/common/dependencies.py`` declares:
+
+ .. doctest::
+ :hide:
+
+ >>> from pyomo.common.dependencies import (
+ ... attempt_import, _finalize_scipy, __dict__ as dep_globals,
+ ... declare_modules_as_importable, )
+ >>> # Sphinx does not provide a proper globals()
+ >>> def globals(): return dep_globals
+
+ .. doctest::
+
+ >>> with declare_modules_as_importable(globals()):
+ ... scipy, scipy_available = attempt_import(
+ ... 'scipy', callback=_finalize_scipy,
+ ... deferred_submodules=['stats', 'sparse', 'spatial', 'integrate'])
+
+ Which enables users to use:
+
+ .. doctest::
+
+ >>> import pyomo.common.dependencies.scipy.sparse as spa
+
+ If the deferred import has not yet been triggered, then the
+ :py:class:`DeferredImportModule` is returned and named ``spa``.
+ However, if the import has already been triggered, then ``spa`` will
+ either be the ``scipy.sparse`` module, or a
+ :py:class:`ModuleUnavailable` instance.
+
+ """
+
+ def __init__(self, globals_dict):
+ self.globals_dict = globals_dict
+ self.init_dict = {}
+ self.init_modules = None
+
+ def __enter__(self):
+ self.init_dict.update(self.globals_dict)
+ self.init_modules = set(sys.modules)
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ _global_name = self.globals_dict['__name__'] + '.'
+ deferred = {
+ k: v
+ for k, v in self.globals_dict.items()
+ if k not in self.init_dict
+ and isinstance(v, (ModuleType, DeferredImportModule))
+ }
+ if self.init_modules:
+ for name in set(sys.modules) - self.init_modules:
+ if '.' in name and name.split('.', 1)[0] in deferred:
+ sys.modules[_global_name + name] = sys.modules[name]
+ while deferred:
+ name, mod = deferred.popitem()
+ sys.modules[_global_name + name] = mod
+ if isinstance(mod, DeferredImportModule):
+ mod.__path__ = None
+ mod.__spec__ = None
+ deferred.update(
+ (name + '.' + k, v)
+ for k, v in mod.__dict__.items()
+ if type(v) is DeferredImportModule
+ )
#
@@ -778,11 +1004,24 @@ def _finalize_matplotlib(module, available):
if in_testing_environment():
module.use('Agg')
import matplotlib.pyplot
+ import matplotlib.pylab
+ import matplotlib.backends
+
+
+def _finalize_mpi4py(module, available):
+ if not available:
+ return
+ import mpi4py.MPI
def _finalize_numpy(np, available):
if not available:
return
+ # scipy has a dependence on numpy.testing, and if we don't import it
+ # as part of resolving numpy, then certain deferred scipy imports
+ # fail when run under pytest.
+ import numpy.testing
+
from . import numeric_types
# Register ndarray as a native type to prevent 1-element ndarrays
@@ -807,10 +1046,13 @@ def _finalize_numpy(np, available):
# registration here (to bypass the deprecation warning) until we
# finally remove all support for it
numeric_types._native_boolean_types.add(t)
- _floats = [np.float_, np.float16, np.float32, np.float64]
+ _floats = [np.float16, np.float32, np.float64]
# float96 and float128 may or may not be defined in this particular
# numpy build (it depends on platform and version).
# Register them only if they are present
+ if hasattr(np, 'float_'):
+ # Prepend to preserve previous functionality
+ _floats.insert(0, np.float_)
if hasattr(np, 'float96'):
_floats.append(np.float96)
if hasattr(np, 'float128'):
@@ -821,10 +1063,13 @@ def _finalize_numpy(np, available):
# registration here (to bypass the deprecation warning) until we
# finally remove all support for it
numeric_types._native_boolean_types.add(t)
- _complex = [np.complex_, np.complex64, np.complex128]
+ _complex = [np.complex64, np.complex128]
# complex192 and complex256 may or may not be defined in this
# particular numpy build (it depends on platform and version).
# Register them only if they are present
+ if hasattr(np, 'np.complex_'):
+ # Prepend to preserve functionality
+ _complex.insert(0, np.complex_)
if hasattr(np, 'complex192'):
_complex.append(np.complex192)
if hasattr(np, 'complex256'):
@@ -842,41 +1087,50 @@ 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')
-numpy, numpy_available = attempt_import('numpy', callback=_finalize_numpy)
-pandas, pandas_available = attempt_import('pandas')
-plotly, plotly_available = attempt_import('plotly')
-pympler, pympler_available = attempt_import('pympler', callback=_finalize_pympler)
-pyutilib, pyutilib_available = attempt_import('pyutilib', importer=_pyutilib_importer)
-scipy, scipy_available = attempt_import(
- 'scipy',
- callback=_finalize_scipy,
- deferred_submodules=['stats', 'sparse', 'spatial', 'integrate'],
-)
-yaml, yaml_available = attempt_import('yaml', callback=_finalize_yaml)
-
-# Note that matplotlib.pyplot can generate a runtime error on OSX when
-# not installed as a Framework (as is the case in the CI systems)
-matplotlib, matplotlib_available = attempt_import(
- 'matplotlib',
- callback=_finalize_matplotlib,
- deferred_submodules=['pyplot', 'pylab'],
- catch_exceptions=(ImportError, RuntimeError),
-)
+with declare_modules_as_importable(globals()):
+ # 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', deferred_submodules=['MPI'], callback=_finalize_mpi4py
+ )
+ networkx, networkx_available = attempt_import('networkx')
+ numpy, numpy_available = attempt_import('numpy', callback=_finalize_numpy)
+ pandas, pandas_available = attempt_import('pandas')
+ pathlib, pathlib_available = attempt_import('pathlib')
+ pint, pint_available = attempt_import(
+ 'pint',
+ # TypeError for pint<=0.24.3 and python>=3.13
+ catch_exceptions=(ImportError, TypeError),
+ )
+ plotly, plotly_available = attempt_import('plotly')
+ pympler, pympler_available = attempt_import('pympler', callback=_finalize_pympler)
+ pyutilib, pyutilib_available = attempt_import(
+ 'pyutilib', importer=_pyutilib_importer
+ )
+ scipy, scipy_available = attempt_import(
+ 'scipy',
+ callback=_finalize_scipy,
+ deferred_submodules=['stats', 'sparse', 'spatial', 'integrate'],
+ )
+ yaml, yaml_available = attempt_import('yaml', callback=_finalize_yaml)
+
+ # Note that matplotlib.pyplot can generate a runtime error on OSX when
+ # not installed as a Framework (as is the case in the CI systems)
+ matplotlib, matplotlib_available = attempt_import(
+ 'matplotlib',
+ callback=_finalize_matplotlib,
+ deferred_submodules=['pyplot', 'pylab', 'backends'],
+ catch_exceptions=(ImportError, RuntimeError),
+ )
try:
import cPickle as pickle
except ImportError:
import pickle
-
-declare_deferred_modules_as_importable(globals())
diff --git a/pyomo/common/deprecation.py b/pyomo/common/deprecation.py
index 5a6ca456079..1246de84b8c 100644
--- a/pyomo/common/deprecation.py
+++ b/pyomo/common/deprecation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -22,13 +22,16 @@
import logging
import functools
+import importlib
import inspect
import itertools
import sys
import textwrap
import types
+import typing
from pyomo.common.errors import DeveloperError
+from pyomo.common.flags import NOTSET, in_testing_environment, building_documentation
_doc_flag = '.. deprecated::'
@@ -101,7 +104,7 @@ def _wrap_class(cls, msg, logger, version, remove_in):
if msg is not None or _doc is None:
_doc = _deprecation_docstring(cls, msg, version, remove_in)
if cls.__doc__:
- _doc = cls.__doc__ + '\n\n' + _doc
+ _doc = inspect.cleandoc(cls.__doc__) + '\n\n' + _doc
cls.__doc__ = 'DEPRECATED.\n\n' + _doc
if _flagIdx < 0:
@@ -131,7 +134,7 @@ def wrapper(*args, **kwargs):
return func(*args, **kwargs)
wrapper.__doc__ = 'DEPRECATED.\n\n'
- _doc = func.__doc__ or ''
+ _doc = inspect.cleandoc(func.__doc__ or '')
if _doc:
wrapper.__doc__ += _doc + '\n\n'
wrapper.__doc__ += _deprecation_docstring(func, msg, version, remove_in)
@@ -151,17 +154,6 @@ def _find_calling_frame(module_offset):
return calling_frame
-def in_testing_environment():
- """Return True if we are currently running in a "testing" environment
-
- This currently includes if nose, nose2, pytest, or Sphinx are
- running (imported).
-
- """
-
- return any(mod in sys.modules for mod in ('nose', 'nose2', 'pytest', 'sphinx'))
-
-
def deprecation_warning(
msg, logger=None, version=None, remove_in=None, calling_frame=None
):
@@ -238,7 +230,11 @@ def deprecation_warning(
logger.warning(msg)
-if in_testing_environment():
+# We do not want to cache / suppress repeated warnings when we are
+# testing or when we are building the documentation. Note that doctest
+# doesn't set the "in_testing" flag until after pyomo.common is
+# imported.
+if in_testing_environment() or building_documentation():
deprecation_warning.emitted_warnings = None
else:
deprecation_warning.emitted_warnings = set()
@@ -292,10 +288,8 @@ def wrap(obj):
def _import_object(name, target, version, remove_in, msg):
- from importlib import import_module
-
modname, targetname = target.rsplit('.', 1)
- _object = getattr(import_module(modname), targetname)
+ _object = getattr(importlib.import_module(modname), targetname)
if msg is None:
if inspect.isclass(_object):
_type = 'class'
@@ -311,15 +305,27 @@ def _import_object(name, target, version, remove_in, msg):
return _object
+@deprecated(
+ "relocated_module() has been deprecated. Please use moved_module()",
+ version='6.8.1',
+)
def relocated_module(new_name, msg=None, logger=None, version=None, remove_in=None):
"""Provide a deprecation path for moved / renamed modules
Upon import, the old module (that called `relocated_module()`) will
- be replaced in `sys.modules` by an alias that points directly to the
+ be replaced in :data:`sys.modules` by an alias that points directly to the
new module. As a result, the old module should have only two lines
of executable Python code (the import of `relocated_module` and the
call to it).
+ Note
+ ----
+ This method (which was placed in the old module that is
+ being removed) is deprecated and should be replaced by calls to
+ :func:`moved_module()`, which can be called in any parent scope of
+ the removed module and does not require that the old module continue
+ to exist in the project.
+
Parameters
----------
new_name: str
@@ -345,17 +351,15 @@ def relocated_module(new_name, msg=None, logger=None, version=None, remove_in=No
-------
>>> from pyomo.common.deprecation import relocated_module
>>> relocated_module('pyomo.common.deprecation', version='1.2.3')
- WARNING: DEPRECATED: The '...' module has been moved to
+ WARNING: DEPRECATED: ... The '...' module has been moved to
'pyomo.common.deprecation'. Please update your import.
(deprecated in 1.2.3) ...
"""
- from importlib import import_module
-
- new_module = import_module(new_name)
+ new_module = importlib.import_module(new_name)
# The relevant module (the one being deprecated) is the one that
- # holds the function/method that called deprecated_module(). The
+ # holds the function/method that called relocated_module(). The
# relevant calling frame for the deprecation warning is the first
# frame in the stack that doesn't look like the importer (i.e., the
# thing that imported the deprecated module).
@@ -542,7 +546,7 @@ def __renamed__warning__(msg):
if new_class is None and '__renamed__new_class__' not in classdict:
if not any(
- hasattr(base, '__renamed__new_class__')
+ hasattr(mro, '__renamed__new_class__')
for mro in itertools.chain.from_iterable(
base.__mro__ for base in renamed_bases
)
@@ -574,3 +578,170 @@ def __subclasscheck__(cls, subclass):
return issubclass(subclass, getattr(cls, '__renamed__new_class__'))
else:
return super().__subclasscheck__(subclass)
+
+
+class MovedModuleLoader:
+ """Custom module loader that supports loading modules through alternate names
+
+ This class implements the :class:`importlib.abc.Loader` interface
+ (through duck-typing to avoid a surprisingly costly import of
+ :mod:`importlib.abc`). Calls to :meth:`create_module()` and
+ :meth:`exec_module()` are delegated to corresponding methods on the
+ loader for the new module name.
+
+ """
+
+ def __init__(self, info):
+ self._info = info
+
+ def create_module(self, spec) -> types.ModuleType:
+ msg = self._info.msg
+ if msg is NOTSET:
+ msg = (
+ f"The '{spec.name}' module has been moved to '{self._info.new_name}'. "
+ 'Please update your import.'
+ )
+ if msg is not None:
+ deprecation_warning(
+ msg, self._info.logger, self._info.version, self._info.remove_in
+ )
+ if self._info.new_name in sys.modules:
+ return sys.modules[self._info.new_name]
+ return importlib.import_module(self._info.new_name)
+
+ def exec_module(self, module: types.ModuleType) -> None:
+ pass
+
+
+class MovedModuleFinder:
+ """Custom finder that supports loading a module through an alternative name.
+
+ This class implements the :class:`importlib.abc.Finder` interface
+ (through duck-typing to avoid a surprisingly costly import of
+ :mod:`importlib.abc`).
+
+ Pyomo automatically registers a single instance of this finder with
+ :mod:`importlib` by appending it to the end of the
+ :data:`sys.meta_path` list when this module is imported.
+ Subsequent calls to :func:`moved_module` register the association
+ between the old and new module names with the ``mapping`` class
+ attribute.
+
+ """
+
+ mapping = {}
+ ":class:`dict` that maps (removed) module names to :class:`MovedModuleInfo` objects"
+
+ def find_spec(self, fullname, path, target=None):
+ if fullname not in self.mapping:
+ return None
+
+ info = MovedModuleFinder.mapping[fullname]
+ src_spec = importlib.util.find_spec(info.new_name)
+ return importlib.machinery.ModuleSpec(
+ name=fullname,
+ loader=MovedModuleLoader(info),
+ origin=getattr(src_spec, 'origin', None),
+ )
+
+ def invalidate_caches(self):
+ pass
+
+
+# Insert the MovedModuleFinder at the end of the sys.meta_path. This
+# way, it has no impact on the performance of importing "normal"
+# (present) modules, and instead is called as a "last-chance" finder
+# before Python would raise an ImportError
+sys.meta_path.append(MovedModuleFinder())
+
+
+MovedModuleInfo = typing.NamedTuple(
+ 'MovedModuleInfo',
+ [
+ ('old_name', str),
+ ('new_name', str),
+ ('msg', str),
+ ('logger', str),
+ ('version', str),
+ ('remove_in', str),
+ ],
+)
+
+
+def moved_module(
+ old_name, new_name, msg=NOTSET, logger=None, version=None, remove_in=None
+):
+ """Provide a deprecation path for moved / renamed modules
+
+ This function hooks into the Python :mod:`importlib` to cause any
+ import of the ``old_name`` to instead import and return the module
+ from ``new_name``. The new module is automatically registered with
+ :data:`sys.modules` under both the old and new names.
+
+ Because :func:`moved_module()` works through the Python
+ :mod:`importlib` system, the old module file can be completely
+ deleted (in contrast to the [deprecated] :func:`relocated_module()`
+ function). Calls to :func:`moved_module` should be placed in any
+ package above the removed module in the package hierarchy (or in any
+ other location that is guaranteeded to be imported / executed before
+ any attempts at importng the module through its old name.
+
+ Any import of the module through the old name will emit a
+ deprecation warning unless the ``msg`` is ``None`` (see also
+ :func:`deprecated`).
+
+ Parameters
+ ----------
+ old_name: str
+ The original (fully-qualified) module name (that has been removed)
+
+ new_name: str
+ The new (fully-qualified) module name
+
+ msg: str
+ A custom deprecation message. If None, the deprecation message
+ will be suppressed. If NOTSET (default), a generic deprecation
+ message will be logged.
+
+ logger: str
+ The logger to use for emitting the warning (default: the calling
+ pyomo package, or "pyomo")
+
+ version: str [required]
+ The version in which the module was renamed or moved. General
+ practice is to set version to the current development version
+ (from `pyomo --version`) during development and update it to the
+ actual release as part of the release process.
+
+ remove_in: str
+ The version in which the module will be removed from the code.
+
+ Example
+ -------
+ >>> from pyomo.common.deprecation import moved_module
+ >>> moved_module(
+ ... 'pyomo.common.old_deprecation',
+ ... 'pyomo.common.deprecation',
+ ... version='1.2.3',
+ ... )
+ >>> import pyomo.common.old_deprecation
+ WARNING: DEPRECATED: The 'pyomo.common.old_deprecation' module has
+ been moved to 'pyomo.common.deprecation'. Please update your import.
+ (deprecated in 1.2.3) ...
+ >>> import pyomo.common.deprecation
+ >>> pyomo.common.old_deprecation is pyomo.common.deprecation
+ True
+
+ """
+ if old_name in MovedModuleFinder.mapping:
+ _current = MovedModuleFinder.mapping[old_name].new_name
+ if new_name == _current:
+ return
+ raise RuntimeError(
+ "Duplicate module alias declaration.\n"
+ f"\toriginal: {old_name} -> {_current}\n"
+ f"\tconflict: {old_name} -> {new_name}\n"
+ )
+ MovedModuleFinder.mapping[old_name] = MovedModuleInfo(
+ old_name, new_name, msg, logger, version, remove_in
+ )
diff --git a/pyomo/common/download.py b/pyomo/common/download.py
index 5332287cfc7..4fc26deb102 100644
--- a/pyomo/common/download.py
+++ b/pyomo/common/download.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -29,6 +29,7 @@
urllib_error = attempt_import('urllib.error')[0]
ssl = attempt_import('ssl')[0]
zipfile = attempt_import('zipfile')[0]
+tarfile = attempt_import('tarfile')[0]
gzip = attempt_import('gzip')[0]
distro, distro_available = attempt_import('distro')
@@ -176,6 +177,7 @@ def get_os_version(cls, normalize=True):
This method was designed to help identify compatible binaries,
and will return strings similar to:
+
- rhel6
- fedora24
- ubuntu18.04
@@ -371,7 +373,7 @@ def get_zip_archive(self, url, dirOffset=0):
# Simple sanity checks
for info in zip_file.infolist():
f = info.filename
- if f[0] in '\\/' or '..' in f:
+ if f[0] in '\\/' or '..' in f or os.path.isabs(f):
logger.error(
"malformed (potentially insecure) filename (%s) "
"found in zip archive. Skipping file." % (f,)
@@ -387,6 +389,61 @@ def get_zip_archive(self, url, dirOffset=0):
info.filename = target[-1] + '/' if f[-1] == '/' else target[-1]
zip_file.extract(f, os.path.join(self._fname, *tuple(target[dirOffset:-1])))
+ def get_tar_archive(self, url, dirOffset=0):
+ if self._fname is None:
+ raise DeveloperError(
+ "target file name has not been initialized "
+ "with set_destination_filename"
+ )
+ if os.path.exists(self._fname) and not os.path.isdir(self._fname):
+ raise RuntimeError(
+ "Target directory (%s) exists, but is not a directory" % (self._fname,)
+ )
+
+ def filter_fcn(info):
+ # this mocks up the `tarfile` filter introduced in Python
+ # 3.12 and backported to later releases of Python (e.g.,
+ # 3.8.17, 3.9.17, 3.10.12, and 3.11.4)
+ f = info.name
+ if os.path.isabs(f) or '..' in f or f.startswith(('/', os.sep)):
+ logger.error(
+ "malformed or potentially insecure filename (%s). "
+ "Skipping file." % (f,)
+ )
+ return False
+ target = self._splitpath(f)
+ if len(target) <= dirOffset:
+ if not info.isdir():
+ logger.warning(
+ "Skipping file (%s) in tar archive due to dirOffset." % (f,)
+ )
+ return False
+ info.name = f = '/'.join(target[dirOffset:])
+ target = os.path.realpath(os.path.join(dest, f))
+ try:
+ if os.path.commonpath([target, dest]) != dest:
+ logger.error(
+ "potentially insecure filename (%s) resolves outside target "
+ "directory. Skipping file." % (f,)
+ )
+ return False
+ except ValueError:
+ # commonpath() will raise ValueError for paths that
+ # don't have anything in common (notably, when files are
+ # on different drives on Windows)
+ logger.error(
+ "potentially insecure filename (%s) resolves outside target "
+ "directory. Skipping file." % (f,)
+ )
+ return False
+ # Strip high bits & group/other write bits
+ info.mode &= 0o755
+ return True
+
+ with tarfile.open(fileobj=io.BytesIO(self.retrieve_url(url))) as TAR:
+ dest = os.path.realpath(self._fname)
+ TAR.extractall(dest, filter(filter_fcn, TAR.getmembers()))
+
def get_gzipped_binary_file(self, url):
if self._fname is None:
raise DeveloperError(
diff --git a/pyomo/common/enums.py b/pyomo/common/enums.py
new file mode 100644
index 00000000000..0c90d358d65
--- /dev/null
+++ b/pyomo/common/enums.py
@@ -0,0 +1,217 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+"""This module provides standard :py:class:`enum.Enum` definitions used in
+Pyomo, along with additional utilities for working with custom Enums
+
+Utilities:
+
+.. autosummary::
+
+ ExtendedEnumType
+ NamedIntEnum
+
+Standard Enums:
+
+.. autosummary::
+
+ ObjectiveSense
+
+"""
+
+import enum
+import itertools
+import re
+import sys
+
+# A local alias for enum.Enum so that clients can use
+# :py:mod:`pyomo.common.enums` like they would :py:mod:`enum`.
+Enum = enum.Enum
+
+if sys.version_info[:2] < (3, 11):
+ _EnumType = enum.EnumMeta
+else:
+ _EnumType = enum.EnumType
+if sys.version_info[:2] < (3, 13):
+ # prior to 3.13 the int.{to,from}_bytes docstrings had LaTeX-like
+ # "`..'" quotations, which Sphinx can't parse correctly.
+ def _fix_doc(ref):
+ def _rewrite(func):
+ func.__doc__ = re.sub(r"`(\S+)'", r"`\1`", ref.__doc__)
+ return func
+
+ return _rewrite
+
+ class IntEnum(enum.IntEnum):
+ __doc__ = (
+ """A compatibility wrapper around :class:`enum.IntEnum`
+
+ This wrapper class updates the :meth:`to_bytes` and
+ :meth:`from_bytes` docstrings in Python <= 3.12 to suppress
+ warnings generated by Sphinx.
+
+ .. rubric:: IntEnum
+
+ """
+ + enum.IntEnum.__doc__
+ )
+
+ @_fix_doc(enum.IntEnum.to_bytes)
+ def to_bytes(self, /, length=1, byteorder='big', *, signed=False):
+ return super().to_bytes(length=length, byteorder=byteorder, signed=signed)
+
+ # Note: we need to use a decorator to set the __doc__ *before*
+ # the @classmethod (which makes __doc__ read-only).
+ @classmethod
+ @_fix_doc(enum.IntEnum.from_bytes)
+ def from_bytes(cls, bytes, byteorder='big', *, signed=False):
+ return super()(bytes, byteorder=byteorder, signed=signed)
+
+else:
+ IntEnum = enum.IntEnum
+
+
+class ExtendedEnumType(_EnumType):
+ """Metaclass for creating an :py:class:`enum.Enum` that extends another Enum
+
+ In general, :py:class:`enum.Enum` classes are not extensible: that is,
+ they are frozen when defined and cannot be the base class of another
+ Enum. This Metaclass provides a workaround for creating a new Enum
+ that extends an existing enum. Members in the base Enum are all
+ present as members on the extended enum.
+
+ Example
+ -------
+
+ .. testcode::
+ :hide:
+
+ import enum
+ from pyomo.common.enums import ExtendedEnumType
+
+ .. testcode::
+
+ class ObjectiveSense(enum.IntEnum):
+ minimize = 1
+ maximize = -1
+
+ class ProblemSense(enum.IntEnum, metaclass=ExtendedEnumType):
+ __base_enum__ = ObjectiveSense
+
+ unknown = 0
+
+ .. doctest::
+
+ >>> list(ProblemSense)
+ [, , ]
+ >>> ProblemSense.unknown
+
+ >>> ProblemSense.maximize
+
+ >>> ProblemSense(0)
+
+ >>> ProblemSense(1)
+
+ >>> ProblemSense('unknown')
+
+ >>> ProblemSense('maximize')
+
+ >>> hasattr(ProblemSense, 'minimize')
+ True
+ >>> ProblemSense.minimize is ObjectiveSense.minimize
+ True
+ >>> ProblemSense.minimize in ProblemSense
+ True
+
+ """
+
+ def __getattr__(cls, attr):
+ try:
+ return getattr(cls.__base_enum__, attr)
+ except:
+ return super().__getattr__(attr)
+
+ def __iter__(cls):
+ # The members of this Enum are the base enum members joined with
+ # the local members
+ return itertools.chain(super().__iter__(), cls.__base_enum__.__iter__())
+
+ def __contains__(cls, member):
+ # This enum "contains" both its local members and the members in
+ # the __base_enum__ (necessary for good auto-enum[sphinx] docs)
+ return super().__contains__(member) or member in cls.__base_enum__
+
+ def __dir__(self):
+ _dir = set(super().__dir__())
+ _dir.update(e.name for e in self)
+ return _dir
+
+ def __instancecheck__(cls, instance):
+ if cls.__subclasscheck__(type(instance)):
+ return True
+ # Also pretend that members of the extended enum are subclasses
+ # of the __base_enum__. This is needed to circumvent error
+ # checking in enum.__new__ (e.g., for `ProblemSense('minimize')`)
+ return cls.__base_enum__.__subclasscheck__(type(instance))
+
+ def _missing_(cls, value):
+ # Support attribute lookup by value or name
+ for attr in ('value', 'name'):
+ for member in cls:
+ if getattr(member, attr) == value:
+ return member
+ return None
+
+ def __new__(metacls, cls, bases, classdict, **kwds):
+ # Support lookup by name - but only if the new Enum doesn't
+ # specify its own implementation of _missing_
+ if '_missing_' not in classdict:
+ classdict['_missing_'] = classmethod(ExtendedEnumType._missing_)
+ return super().__new__(metacls, cls, bases, classdict, **kwds)
+
+
+class NamedIntEnum(IntEnum):
+ """An extended version of :py:class:`~pyomo.common.enums.IntEnum` that supports
+ creating members by name as well as value.
+
+ """
+
+ @classmethod
+ def _missing_(cls, value):
+ for member in cls:
+ if member.name == value:
+ return member
+ return None
+
+
+class ObjectiveSense(NamedIntEnum):
+ """Flag indicating if an objective is minimizing (1) or maximizing (-1).
+
+ While the numeric values are arbitrary, there are parts of Pyomo
+ that rely on this particular choice of value. These values are also
+ consistent with some solvers (notably Gurobi).
+
+ """
+
+ minimize = 1
+ maximize = -1
+
+ # Overloading __str__ is needed to match the behavior of the old
+ # pyutilib.enum class (removed June 2020). There are spots in the
+ # code base that expect the string representation for items in the
+ # enum to not include the class name. New uses of enum shouldn't
+ # need to do this.
+ def __str__(self):
+ return self.name
+
+
+minimize = ObjectiveSense.minimize
+maximize = ObjectiveSense.maximize
diff --git a/pyomo/common/env.py b/pyomo/common/env.py
index ee07cdc1e6a..d372b061e51 100644
--- a/pyomo/common/env.py
+++ b/pyomo/common/env.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -405,7 +405,6 @@ class CtypesEnviron(object):
:hide:
import os
- from pyomo.common.env import TemporaryEnv
orig_env_val = os.environ.get('TEMP_ENV_VAR', None)
.. doctest::
@@ -415,7 +414,7 @@ class CtypesEnviron(object):
original value
>>> with CtypesEnviron(TEMP_ENV_VAR='temporary value'):
- ... print(os.envion['TEMP_ENV_VAR'])
+ ... print(os.environ['TEMP_ENV_VAR'])
temporary value
>>> print(os.environ['TEMP_ENV_VAR'])
diff --git a/pyomo/common/envvar.py b/pyomo/common/envvar.py
index 1f933d4b08c..36ed5910781 100644
--- a/pyomo/common/envvar.py
+++ b/pyomo/common/envvar.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/errors.py b/pyomo/common/errors.py
index 3c82f2b07c1..58139fbd5eb 100644
--- a/pyomo/common/errors.py
+++ b/pyomo/common/errors.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/extensions.py b/pyomo/common/extensions.py
index 0ac27f125a7..7ccb81d165c 100644
--- a/pyomo/common/extensions.py
+++ b/pyomo/common/extensions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/factory.py b/pyomo/common/factory.py
index c449cf826b4..e1cb8543f74 100644
--- a/pyomo/common/factory.py
+++ b/pyomo/common/factory.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/fileutils.py b/pyomo/common/fileutils.py
index 2cade36154d..4a0b2beb36b 100644
--- a/pyomo/common/fileutils.py
+++ b/pyomo/common/fileutils.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -38,6 +38,7 @@
import os
import platform
import importlib.util
+import subprocess
import sys
from . import envvar
@@ -285,10 +286,17 @@ def find_dir(
)
-_exeExt = {'linux': None, 'windows': '.exe', 'cygwin': '.exe', 'darwin': None}
+_exeExt = {
+ 'linux': None,
+ 'freebsd': None,
+ 'windows': '.exe',
+ 'cygwin': '.exe',
+ 'darwin': None,
+}
_libExt = {
'linux': ('.so', '.so.*'),
+ 'freebsd': ('.so', '.so.*'),
'windows': ('.dll', '.pyd'),
'cygwin': ('.dll', '.so', '.so.*'),
'darwin': ('.dylib', '.so', '.so.*'),
@@ -375,9 +383,27 @@ def find_library(libname, cwd=True, include_PATH=True, pathlist=None):
if libname_base.startswith('lib') and _system() != 'windows':
libname_base = libname_base[3:]
if ext.lower().startswith(('.so', '.dll', '.dylib')):
- return ctypes.util.find_library(libname_base)
+ lib = ctypes.util.find_library(libname_base)
else:
- return ctypes.util.find_library(libname)
+ lib = ctypes.util.find_library(libname)
+ if lib and os.path.sep not in lib:
+ # work around https://github.com/python/cpython/issues/65241,
+ # where python does not return the absolute path on *nix
+ try:
+ libname = lib + ' '
+ with subprocess.Popen(
+ ['/sbin/ldconfig', '-p'],
+ stdin=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ env={'LC_ALL': 'C', 'LANG': 'C'},
+ ) as p:
+ for line in os.fsdecode(p.stdout.read()).splitlines():
+ if line.lstrip().startswith(libname):
+ return os.path.realpath(line.split()[-1])
+ except:
+ pass
+ return lib
def find_executable(exename, cwd=True, include_PATH=True, pathlist=None):
@@ -687,7 +713,7 @@ class PathManager(object):
The ``Executable`` singleton uses :py:class:`ExecutableData`, an
extended form of the :py:class:`PathData` class, which provides the
- ``executable`` property as an alais for :py:meth:`path()` and
+ ``executable`` property as an alias for :py:meth:`path()` and
:py:meth:`set_path()`:
.. doctest::
diff --git a/pyomo/common/flags.py b/pyomo/common/flags.py
new file mode 100644
index 00000000000..d589a20dbf0
--- /dev/null
+++ b/pyomo/common/flags.py
@@ -0,0 +1,139 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import inspect
+import sys
+
+
+class FlagType(type):
+ """Metaclass to help generate "Flag Types".
+
+ This is useful for defining "flag types" that are default arguments
+ in functions so that the Sphinx-generated documentation is
+ "cleaner". These types are not constructable (attempts to construct
+ the class return the class) and simplify the repr(type) and
+ str(type).
+
+ This metaclass redefines the ``str()`` and ``repr()`` of resulting
+ classes. The str() of the class returns only the class' ``__name__``,
+ whereas the repr() returns either the qualified class name
+ (``__qualname__``) if Sphinx has been imported, or else the
+ fully-qualified class name (``__module__ + '.' + __qualname__``).
+
+ """
+
+ def __new__(mcs, name, bases, dct):
+ # Ensure that attempts to construct instances of a Flag type
+ # return the type.
+ def __new_flag__(cls, *args, **kwargs):
+ return cls
+
+ dct["__new__"] = __new_flag__
+ return type.__new__(mcs, name, bases, dct)
+
+ def __repr__(cls):
+ if building_documentation():
+ return cls.__qualname__
+ else:
+ return cls.__module__ + "." + cls.__qualname__
+
+ def __str__(cls):
+ return cls.__name__
+
+
+class NOTSET(object, metaclass=FlagType):
+ """
+ Class to be used to indicate that an optional argument
+ was not specified, if `None` may be ambiguous. Usage:
+
+ Examples
+ --------
+ >>> def foo(value=NOTSET):
+ ... if value is NOTSET:
+ ... pass # no argument was provided to `value`
+
+ """
+
+ pass
+
+
+def in_testing_environment(state=NOTSET):
+ """Return True if we are currently running in a "testing" environment
+
+ This currently includes if ``nose``, ``nose2``, or ``pytest`` are
+ running (imported).
+
+ Parameters
+ ----------
+ state : bool or None
+ If provided, sets the current state of the testing environment
+ (Setting to None reverts to the normal interrogation of
+ ``sys.modules``)
+
+ Returns
+ -------
+ bool
+
+ """
+ if state is not NOTSET:
+ in_testing_environment.state = state
+ if in_testing_environment.state is not None:
+ return bool(in_testing_environment.state)
+ return any(mod in sys.modules for mod in ('nose', 'nose2', 'pytest'))
+
+
+in_testing_environment.state = None
+
+
+def building_documentation(state=NOTSET):
+ """True if we are building the Sphinx documentation
+
+ We detect if we are building the documentation by looking if the
+ ``sphinx`` or ``Sphinx`` modules are imported.
+
+ Parameters
+ ----------
+ state : bool or None
+ If provided, sets the current state of the building environment
+ flag (Setting to None reverts to the normal interrogation of
+ ``sys.modules``)
+
+ Returns
+ -------
+ bool
+
+ """
+ if state is not NOTSET:
+ building_documentation.state = state
+ if building_documentation.state is not None:
+ return bool(building_documentation.state)
+ return 'sphinx' in sys.modules or 'Sphinx' in sys.modules
+
+
+building_documentation.state = None
+
+
+def serializing():
+ """True if it looks like we are serializing objects
+
+ This looks through the call stack and returns True if it finds a
+ `dump` function anywhere in the call stack. While not foolproof,
+ this should reliably catch most serializers, including ``pickle``
+ and `yaml``.
+
+ """
+ # Start by skipping this function
+ frame = inspect.currentframe().f_back
+ while frame is not None:
+ if frame.f_code.co_name == 'dump':
+ return True
+ frame = frame.f_back
+ return False
diff --git a/pyomo/common/formatting.py b/pyomo/common/formatting.py
index 430ec96ca09..71798565417 100644
--- a/pyomo/common/formatting.py
+++ b/pyomo/common/formatting.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/gc_manager.py b/pyomo/common/gc_manager.py
index 751eb95cf18..5745fe1a97e 100644
--- a/pyomo/common/gc_manager.py
+++ b/pyomo/common/gc_manager.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/gsl.py b/pyomo/common/gsl.py
index 1c14b64bd70..fde7eeded79 100644
--- a/pyomo/common/gsl.py
+++ b/pyomo/common/gsl.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -23,8 +23,8 @@
)
def get_gsl(downloader):
logger.info(
- "As of February 9, 2023, AMPL GSL can no longer be downloaded\
- through download-extensions. Visit https://portal.ampl.com/\
+ "As of February 9, 2023, AMPL GSL can no longer be downloaded \
+ through download-extensions. Visit https://portal.ampl.com/ \
to download the AMPL GSL binaries."
)
diff --git a/pyomo/common/log.py b/pyomo/common/log.py
index d61ed62f373..b8275290839 100644
--- a/pyomo/common/log.py
+++ b/pyomo/common/log.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -21,6 +21,7 @@
import inspect
import io
import logging
+import os
import re
import sys
import textwrap
@@ -28,21 +29,21 @@
from pyomo.version.info import releaselevel
from pyomo.common.deprecation import deprecated
from pyomo.common.fileutils import PYOMO_ROOT_DIR
+from pyomo.common.flags import in_testing_environment, building_documentation
from pyomo.common.formatting import wrap_reStructuredText
_indentation_re = re.compile(r'\s*')
-_RTD_URL = "https://pyomo.readthedocs.io/en/%s/errors.html" % (
- 'stable'
- if (releaselevel == 'final' or 'sphinx' in sys.modules or 'Sphinx' in sys.modules)
- else 'latest'
-)
+_RTD_URL = "https://pyomo.readthedocs.io/en/%s/errors.html"
def RTD(_id):
_id = str(_id).lower()
+ _release = (
+ 'stable' if releaselevel == 'final' or in_testing_environment() else 'latest'
+ )
assert _id[0] in 'wex'
- return f"{_RTD_URL}#{_id}"
+ return (_RTD_URL % (_release,)) + f"#{_id}"
_DEBUG = logging.DEBUG
@@ -234,7 +235,12 @@ def __init__(self):
self.logger = logging.getLogger()
def filter(self, record):
- return not self.logger.handlers
+ # We will not emit messages using the default Pyomo log handler
+ # if someone has registered a global handler. However, we will
+ # ignore this if we are building documentation
+ # (sphinx.ext.doctest adds a handler, but we want to ignore that
+ # handler when we are testing our documentation!)
+ return not self.logger.handlers or building_documentation()
# This mocks up the historical Pyomo logging system, which uses a
@@ -267,7 +273,7 @@ def __init__(self, base='', stream=None, level=logging.NOTSET, verbosity=None):
class LoggingIntercept(object):
- """Context manager for intercepting messages sent to a log stream
+ r"""Context manager for intercepting messages sent to a log stream
This class is designed to enable easy testing of log messages.
@@ -281,28 +287,52 @@ class LoggingIntercept(object):
----------
output: io.TextIOBase
the file stream to send log messages to
+
module: str
- the target logger name to intercept
+ the target logger name to intercept. `logger` and `module` are
+ mutually exclusive.
+
level: int
the logging level to intercept
+
formatter: logging.Formatter
the formatter to use when rendering the log messages. If not
specified, uses `'%(message)s'`
- Examples:
- >>> import io, logging
- >>> from pyomo.common.log import LoggingIntercept
- >>> buf = io.StringIO()
- >>> with LoggingIntercept(buf, 'pyomo.core', logging.WARNING):
- ... logging.getLogger('pyomo.core').warning('a simple message')
- >>> buf.getvalue()
+ logger: logging.Logger
+ the target logger to intercept. `logger` and `module` are
+ mutually exclusive.
+
+ Examples
+ --------
+ >>> import io, logging
+ >>> from pyomo.common.log import LoggingIntercept
+ >>> buf = io.StringIO()
+ >>> with LoggingIntercept(buf, 'pyomo.core', logging.WARNING):
+ ... logging.getLogger('pyomo.core').warning('a simple message')
+ >>> buf.getvalue()
+ 'a simple message\n'
"""
- def __init__(self, output=None, module=None, level=logging.WARNING, formatter=None):
+ def __init__(
+ self,
+ output=None,
+ module=None,
+ level=logging.WARNING,
+ formatter=None,
+ logger=None,
+ ):
self.handler = None
self.output = output
- self.module = module
+ if logger is not None:
+ if module is not None:
+ raise ValueError(
+ "LoggingIntercept: only one of 'module' and 'logger' is allowed"
+ )
+ self._logger = logger
+ else:
+ self._logger = logging.getLogger(module)
self._level = level
if formatter is None:
formatter = logging.Formatter('%(message)s')
@@ -310,6 +340,11 @@ def __init__(self, output=None, module=None, level=logging.WARNING, formatter=No
self._save = None
def __enter__(self):
+ # Get the logger for the scope we will be overriding
+ logger = self._logger
+ self._save = logger.level, logger.propagate, logger.handlers
+ if self._level is None:
+ self._level = logger.getEffectiveLevel()
# Set up the handler
output = self.output
if output is None:
@@ -319,22 +354,24 @@ def __enter__(self):
self.handler.setFormatter(self._formatter)
self.handler.setLevel(self._level)
# Register the handler with the appropriate module scope
- logger = logging.getLogger(self.module)
- self._save = logger.level, logger.propagate, logger.handlers
logger.handlers = []
- logger.propagate = 0
+ logger.propagate = False
logger.setLevel(self.handler.level)
logger.addHandler(self.handler)
return output
def __exit__(self, et, ev, tb):
- logger = logging.getLogger(self.module)
+ logger = self._logger
logger.removeHandler(self.handler)
self.handler = None
logger.setLevel(self._save[0])
logger.propagate = self._save[1]
- for h in self._save[2]:
- logger.handlers.append(h)
+ assert not logger.handlers
+ logger.handlers.extend(self._save[2])
+
+ @property
+ def module(self):
+ return self._logger.name
class LogStream(io.TextIOBase):
@@ -350,6 +387,8 @@ def __init__(self, level, logger):
self._buffer = ''
def write(self, s: str) -> int:
+ if not s:
+ return 0
res = len(s)
if self._buffer:
s = self._buffer + s
@@ -362,3 +401,90 @@ def write(self, s: str) -> int:
def flush(self):
if self._buffer:
self.write('\n')
+
+ def redirect_streams(self, redirects):
+ """Redirect StreamHandler objects to the original file descriptors
+
+ This utility method for py:class:`~pyomo.common.tee.capture_output`
+ locates any StreamHandlers that would process messages from the
+ logger assigned to this :py:class:`LogStream` that would write
+ to the file descriptors redirected by `capture_output` and
+ yields context managers that will redirect those StreamHandlers
+ back to duplicates of the original file descriptors.
+
+ """
+ found = 0
+ logger = self._logger
+ while isinstance(logger, logging.LoggerAdapter):
+ logger = logger.logger
+ while logger:
+ for handler in logger.handlers:
+ found += 1
+ if not isinstance(handler, logging.StreamHandler):
+ continue
+ try:
+ fd = handler.stream.fileno()
+ except (AttributeError, OSError):
+ fd = None
+ if fd not in redirects:
+ continue
+ yield _StreamRedirector(handler, redirects[fd].original_fd)
+ if not logger.propagate:
+ break
+ else:
+ logger = logger.parent
+ if not found:
+ fd = logging.lastResort.stream.fileno()
+ if not redirects:
+ yield _LastResortRedirector(fd)
+ elif fd in redirects:
+ yield _LastResortRedirector(redirects[fd].original_fd)
+
+
+class _StreamRedirector(object):
+ def __init__(self, handler, fd):
+ self.handler = handler
+ self.fd = fd
+ self.orig_stream = None
+
+ def __enter__(self):
+ self.orig_stream = self.handler.stream
+ # Note: ideally, we would use closefd=True and let Python handle
+ # closing the local file descriptor that we are about to create.
+ # However, it appears that closefd is ignored on Windows (see
+ # #3587), so we will just handle it explicitly ourselves.
+ self.handler.stream = os.fdopen(
+ os.dup(self.fd), mode="w", closefd=False
+ ).__enter__()
+
+ def __exit__(self, et, ev, tb):
+ try:
+ fd = self.handler.stream.fileno()
+ self.handler.stream.__exit__(et, ev, tb)
+ os.close(fd)
+ finally:
+ self.handler.stream = self.orig_stream
+
+
+class _LastResortRedirector(object):
+ def __init__(self, fd):
+ self.fd = fd
+ self.orig_stream = None
+
+ def __enter__(self):
+ self.orig = logging.lastResort
+ # Note: ideally, we would use closefd=True and let Python handle
+ # closing the local file descriptor that we are about to create.
+ # However, it appears that closefd is ignored on Windows (see
+ # #3587), so we will just handle it explicitly ourselves.
+ logging.lastResort = logging.StreamHandler(
+ os.fdopen(os.dup(self.fd), mode="w", closefd=False).__enter__()
+ )
+
+ def __exit__(self, et, ev, tb):
+ try:
+ fd = logging.lastResort.stream.fileno()
+ logging.lastResort.stream.close()
+ os.close(fd)
+ finally:
+ logging.lastResort = self.orig
diff --git a/pyomo/common/modeling.py b/pyomo/common/modeling.py
index 4c07048d77a..d9901c8525d 100644
--- a/pyomo/common/modeling.py
+++ b/pyomo/common/modeling.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,9 +9,14 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-import sys
from .dependencies import random
+# [Aug 24] Importing for backwards compatibility; may deprecate this import later
+from .flags import FlagType, NOTSET
+
+# Backward compatibility with the previous name for this flag
+NoArgumentGiven = NOTSET
+
def randint(a, b):
"""Our implementation of random.randint.
@@ -35,49 +40,3 @@ def unique_component_name(instance, name):
return name
else:
name += str(randint(0, 9))
-
-
-class FlagType(type):
- """Metaclass to simplify the repr(type) and str(type)
-
- This metaclass redefines the ``str()`` and ``repr()`` of resulting
- classes. The str() of the class returns only the class' ``__name__``,
- whereas the repr() returns either the qualified class name
- (``__qualname__``) if Sphinx has been imported, or else the
- fully-qualified class name (``__module__ + '.' + __qualname__``).
-
- This is useful for defining "flag types" that are default arguments
- in functions so that the Sphinx-generated documentation is "cleaner"
-
- """
-
- if 'sphinx' in sys.modules or 'Sphinx' in sys.modules:
-
- def __repr__(cls):
- return cls.__qualname__
-
- else:
-
- def __repr__(cls):
- return cls.__module__ + "." + cls.__qualname__
-
- def __str__(cls):
- return cls.__name__
-
-
-class NOTSET(object, metaclass=FlagType):
- """
- Class to be used to indicate that an optional argument
- was not specified, if `None` may be ambiguous. Usage:
-
- >>> def foo(value=NOTSET):
- >>> if value is NOTSET:
- >>> pass # no argument was provided to `value`
-
- """
-
- pass
-
-
-# Backward compatibility with the previous name for this flag
-NoArgumentGiven = NOTSET
diff --git a/pyomo/common/multithread.py b/pyomo/common/multithread.py
index a2dace2be0f..b029029d1f3 100644
--- a/pyomo/common/multithread.py
+++ b/pyomo/common/multithread.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/numeric_types.py b/pyomo/common/numeric_types.py
index ba104203667..96fd228c43f 100644
--- a/pyomo/common/numeric_types.py
+++ b/pyomo/common/numeric_types.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -12,7 +12,6 @@
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
@@ -44,13 +43,12 @@
#: like numpy, which may be registered by users.
#:
#: Note that :data:`native_numeric_types` does NOT include
-#: :py:`complex`, as that is not a valid constant in Pyomo numeric
+#: :py:class:`complex`, as that is not a valid constant in Pyomo numeric
#: expressions.
native_numeric_types = {int, float}
native_integer_types = {int}
native_logical_types = {bool}
native_complex_types = {complex}
-pyomo_constant_types = set() # includes NumericConstant
_native_boolean_types = {int, bool, str, bytes}
relocated_module_attribute(
@@ -62,6 +60,16 @@
"be treated as if they were bool (as was the case for the other "
"native_*_types sets). Users likely should use native_logical_types.",
)
+_pyomo_constant_types = set() # includes NumericConstant, _PythonCallbackFunctionID
+relocated_module_attribute(
+ 'pyomo_constant_types',
+ 'pyomo.common.numeric_types._pyomo_constant_types',
+ version='6.7.2',
+ msg="The pyomo_constant_types set will be removed in the future: the set "
+ "contained only NumericConstant and _PythonCallbackFunctionID, and provided "
+ "no meaningful value to clients or walkers. Users should likely handle "
+ "these types in the same manner as immutable Params.",
+)
#: Python set used to identify numeric constants and related native
@@ -90,8 +98,8 @@ def RegisterNumericType(new_type: type):
Parameters
----------
- new_type: type
- The new numeric type (e.g, numpy.float64)
+ new_type : type
+ The new numeric type (e.g, `numpy.float64`)
"""
native_numeric_types.add(new_type)
@@ -114,8 +122,8 @@ def RegisterIntegerType(new_type: type):
Parameters
----------
- new_type: type
- The new integer type (e.g, numpy.int64)
+ new_type : type
+ The new integer type (e.g, `numpy.int64`)
"""
native_numeric_types.add(new_type)
@@ -141,8 +149,8 @@ def RegisterBooleanType(new_type: type):
Parameters
----------
- new_type: type
- The new logical type (e.g, numpy.bool_)
+ new_type : type
+ The new logical type (e.g, `numpy.bool_`)
"""
_native_boolean_types.add(new_type)
@@ -163,8 +171,8 @@ def RegisterComplexType(new_type: type):
Parameters
----------
- new_type: type
- The new complex type (e.g, numpy.complex128)
+ new_type : type
+ The new complex type (e.g, `numpy.complex128`)
"""
native_types.add(new_type)
@@ -184,8 +192,8 @@ def RegisterLogicalType(new_type: type):
Parameters
----------
- new_type: type
- The new logical type (e.g, numpy.bool_)
+ new_type : type
+ The new logical type (e.g, `numpy.bool_`)
"""
_native_boolean_types.add(new_type)
@@ -194,6 +202,67 @@ def RegisterLogicalType(new_type: type):
nonpyomo_leaf_types.add(new_type)
+def check_if_native_type(obj):
+ if isinstance(obj, (str, bytes)):
+ native_types.add(obj.__class__)
+ return True
+ if check_if_logical_type(obj):
+ return True
+ if check_if_numeric_type(obj):
+ return True
+ return False
+
+
+def check_if_logical_type(obj):
+ """Test if the argument behaves like a logical type.
+
+ We check for "logical types" by checking if the type returns sane
+ results for Boolean operators (``^``, ``|``, ``&``) and if it maps
+ ``1`` and ``2`` both to the same equivalent instance. If that
+ works, then we register the type in :py:attr:`native_logical_types`.
+
+ """
+ obj_class = obj.__class__
+ # Do not re-evaluate known native types
+ if obj_class in native_types:
+ return obj_class in native_logical_types
+
+ try:
+ # It is not an error if you can't initialize the type from an
+ # int, but if you can, it should map !0 to True
+ if obj_class(1) != obj_class(2):
+ return False
+ except:
+ pass
+
+ try:
+ # Native logical types *must* be hashable
+ hash(obj)
+ # Native logical types must honor standard Boolean operators
+ if all(
+ (
+ obj_class(False) != obj_class(True),
+ obj_class(False) ^ obj_class(False) == obj_class(False),
+ obj_class(False) ^ obj_class(True) == obj_class(True),
+ obj_class(True) ^ obj_class(False) == obj_class(True),
+ obj_class(True) ^ obj_class(True) == obj_class(False),
+ obj_class(False) | obj_class(False) == obj_class(False),
+ obj_class(False) | obj_class(True) == obj_class(True),
+ obj_class(True) | obj_class(False) == obj_class(True),
+ obj_class(True) | obj_class(True) == obj_class(True),
+ obj_class(False) & obj_class(False) == obj_class(False),
+ obj_class(False) & obj_class(True) == obj_class(False),
+ obj_class(True) & obj_class(False) == obj_class(False),
+ obj_class(True) & obj_class(True) == obj_class(True),
+ )
+ ):
+ RegisterLogicalType(obj_class)
+ return True
+ except:
+ pass
+ return False
+
+
def check_if_numeric_type(obj):
"""Test if the argument behaves like a numeric type.
@@ -208,46 +277,55 @@ 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_types:
- return obj_class in native_numeric_types
-
try:
obj_plus_0 = obj + 0
obj_p0_class = obj_plus_0.__class__
- # ensure that the object is comparable to 0 in a meaningful way
- # (among other things, this prevents numpy.ndarray objects from
- # being added to native_numeric_types)
+ # Native numeric types *must* be hashable
+ hash(obj)
+ except:
+ return False
+ if obj_p0_class is not obj_class and obj_p0_class not in native_numeric_types:
+ return False
+ #
+ # Check if the numeric type behaves like a complex type
+ #
+ try:
+ if 1.41 < abs(obj_class(1j + 1)) < 1.42:
+ RegisterComplexType(obj_class)
+ return False
+ except:
+ pass
+ #
+ # Ensure that the object is comparable to 0 in a meaningful way
+ #
+ try:
if not ((obj < 0) ^ (obj >= 0)):
return False
- # Native types *must* be hashable
- hash(obj)
except:
return False
- if obj_p0_class is obj_class or obj_p0_class in native_numeric_types:
- #
- # If we get here, this is a reasonably well-behaving
- # numeric type: add it to the native numeric types
- # so that future lookups will be faster.
- #
- RegisterNumericType(obj_class)
- #
- # Generate a warning, since Pyomo's management of third-party
- # numeric types is more robust when registering explicitly.
- #
- logger.warning(
- f"""Dynamically registering the following numeric type:
+ #
+ # If we get here, this is a reasonably well-behaving
+ # numeric type: add it to the native numeric types
+ # so that future lookups will be faster.
+ #
+ RegisterNumericType(obj_class)
+ try:
+ if obj_class(0.4) == obj_class(0):
+ RegisterIntegerType(obj_class)
+ except:
+ pass
+ #
+ # Generate a warning, since Pyomo's management of third-party
+ # numeric types is more robust when registering explicitly.
+ #
+ logger.warning(
+ f"""Dynamically registering the following numeric type:
{obj_class.__module__}.{obj_class.__name__}
Dynamic registration is supported for convenience, but there are known
limitations to this approach. We recommend explicitly registering
numeric types using RegisterNumericType() or RegisterIntegerType()."""
- )
- return True
- else:
- return False
+ )
+ return True
def value(obj, exception=True):
@@ -274,22 +352,10 @@ def value(obj, exception=True):
"""
if obj.__class__ in native_types:
return obj
- if obj.__class__ in pyomo_constant_types:
- #
- # I'm commenting this out for now, but I think we should never expect
- # to see a numeric constant with value None.
- #
- # if exception and obj.value is None:
- # raise ValueError(
- # "No value for uninitialized NumericConstant object %s"
- # % (obj.name,))
- return obj.value
#
# Test if we have a duck typed Pyomo expression
#
- try:
- obj.is_numeric_type()
- except AttributeError:
+ if not hasattr(obj, 'is_numeric_type'):
#
# TODO: Historically we checked for new *numeric* types and
# raised exceptions for anything else. That is inconsistent
@@ -304,7 +370,7 @@ def value(obj, exception=True):
return None
raise TypeError(
"Cannot evaluate object with unknown type: %s" % obj.__class__.__name__
- ) from None
+ )
#
# Evaluate the expression object
#
diff --git a/pyomo/common/plugin_base.py b/pyomo/common/plugin_base.py
index 75b8657d1a9..f33bff09026 100644
--- a/pyomo/common/plugin_base.py
+++ b/pyomo/common/plugin_base.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/plugins.py b/pyomo/common/plugins.py
index ed44f8bf776..bb008ffacc9 100644
--- a/pyomo/common/plugins.py
+++ b/pyomo/common/plugins.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/pyomo_typing.py b/pyomo/common/pyomo_typing.py
index 22ec3480842..35f3567432a 100644
--- a/pyomo/common/pyomo_typing.py
+++ b/pyomo/common/pyomo_typing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/shutdown.py b/pyomo/common/shutdown.py
index a96a6bc04fc..1741993dcce 100644
--- a/pyomo/common/shutdown.py
+++ b/pyomo/common/shutdown.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/sorting.py b/pyomo/common/sorting.py
index 4f78a7892b8..bb5ea13f55e 100644
--- a/pyomo/common/sorting.py
+++ b/pyomo/common/sorting.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tee.py b/pyomo/common/tee.py
index 500f7b6f58d..fdafcc39847 100644
--- a/pyomo/common/tee.py
+++ b/pyomo/common/tee.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -16,13 +16,15 @@
# the U.S. Government retains certain rights in this software.
# ___________________________________________________________________________
#
+import collections.abc
import io
import logging
import os
import sys
import threading
import time
-from io import StringIO
+
+from pyomo.common.log import LoggingIntercept, LogStream
_poll_interval = 0.0001
_poll_rampup_limit = 0.099
@@ -35,6 +37,7 @@
_poll_timeout = 3 # 15 rounds: 0.0001 * 2**15 == 3.2768
_poll_timeout_deadlock = 200 # 21 rounds: 0.0001 * 2**21 == 209.7152
+_noop = lambda: None
_mswindows = sys.platform.startswith('win')
try:
if _mswindows:
@@ -50,6 +53,53 @@
logger = logging.getLogger(__name__)
+class _SignalFlush(object):
+ def __init__(self, ostream, handle):
+ super().__setattr__('_ostream', ostream)
+ super().__setattr__('_handle', handle)
+
+ def flush(self):
+ self._ostream.flush()
+ self._handle.flush = True
+
+ def __getattr__(self, attr):
+ return getattr(self._ostream, attr)
+
+ def __setattr__(self, attr, val):
+ return setattr(self._ostream, attr, val)
+
+
+class _AutoFlush(_SignalFlush):
+ def write(self, data):
+ self._ostream.write(data)
+ self.flush()
+
+ def writelines(self, data):
+ self._ostream.writelines(data)
+ self.flush()
+
+
+class _fd_closer(object):
+ """A context manager to handle closing a specified file descriptor
+
+ Ideally we would use `os.fdopen(... closefd=True)`; however, it
+ appears that Python ignores `closefd` on Windows. This would
+ eventually lead to the process exceeding the maximum number of open
+ files (see Pyomo/pyomo#3587). So, we will explicitly manage closing
+ the file descriptors that we open using this context manager.
+
+ """
+
+ def __init__(self, fd):
+ self.fd = fd
+
+ def __enter__(self):
+ return self.fd
+
+ def __exit__(self, et, ev, tb):
+ os.close(self.fd)
+
+
class redirect_fd(object):
"""Redirect a file descriptor to a new file or file descriptor.
@@ -67,13 +117,15 @@ class redirect_fd(object):
fd: int
The file descriptor to redirect
- output: int or str
+ output: int or str or None
The new output target for `fd`: either another valid file
- descriptor (int) or a string with the file to open.
+ descriptor (int) or a string with the file to open. If `None`,
+ then the fd is redirected to `os.devnull`.
synchronize: bool
If True, and `fd` is 1 or 2, then update `sys.stdout` or
`sys.stderr` to also point to the new file descriptor
+
"""
def __init__(self, fd=1, output=None, synchronize=True):
@@ -90,8 +142,10 @@ def __init__(self, fd=1, output=None, synchronize=True):
def __enter__(self):
if self.std:
- # important: flush the current file buffer when redirecting
- getattr(sys, self.std).flush()
+ # We used to flush original_file here. We have removed that
+ # because the std* streams are flushed by capture_output.
+ # Flushing again here caused intermittent errors due to
+ # closed file handles on OSX
self.original_file = getattr(sys, self.std)
# Duplicate the original standard file descriptor(file
# descriptor 1 or 2) to a different file descriptor number
@@ -104,39 +158,22 @@ def __enter__(self):
out_fd = os.open(self.target, os.O_WRONLY)
# Duplicate the file descriptor for the opened file, closing and
- # overwriting the value for stdout (file descriptor 1). Only
- # make the new FD inheritable if it is stdout/stderr
+ # overwriting/replacing the original fd. Only make the new FD
+ # inheritable if it is stdout/stderr
os.dup2(out_fd, self.fd, inheritable=bool(self.std))
# We no longer need this original file descriptor
- if out_fd is not self.target:
+ if not isinstance(self.target, int):
os.close(out_fd)
- if self.std:
- if self.synchronize:
- # Cause Python's stdout to point to our new file
- fd = self.fd
- else:
- # IF we are not synchronizing the std file object with
- # the redirected file descriptor, and IF the current
- # file object is pointing to the original file
- # descriptor that we just redirected, then we want to
- # retarget the std file to the original (duplicated)
- # target file descriptor. This allows, e.g. Python to
- # still write to stdout when we redirect fd=1 to
- # /dev/null
- try:
- old_std_fd = getattr(sys, self.std).fileno()
- fd = self.original_fd if old_std_fd == self.fd else None
- except (io.UnsupportedOperation, AttributeError):
- fd = None
- if fd is not None:
- self.target_file = os.fdopen(fd, 'w', closefd=False)
- setattr(sys, self.std, self.target_file)
+ if self.synchronize and self.std:
+ # Cause Python's stdout to point to our new file
+ self.target_file = os.fdopen(self.fd, 'w', closefd=False)
+ setattr(sys, self.std, self.target_file)
return self
- def __exit__(self, t, v, traceback):
+ def __exit__(self, et, ev, tb):
# Close output: this either closes the new file that we opened,
# or else the new file that points to the original (duplicated)
# file descriptor
@@ -152,56 +189,240 @@ def __exit__(self, t, v, traceback):
class capture_output(object):
- """
- Drop-in substitute for PyUtilib's capture_output.
- Takes in a StringIO, file-like object, or filename and temporarily
- redirects output to a string buffer.
+ """Context manager to capture output sent to sys.stdout and sys.stderr
+
+ This is a drop-in substitute for PyUtilib's capture_output to
+ temporarily redirect output to the provided stream or file.
+
+ Parameters
+ ----------
+ output : io.TextIOBase, Sequence[io.TextIOBase], TeeStream, str, or None
+
+ Output stream where all captured stdout/stderr data is sent. If
+ a ``str`` is provided, it is used as a file name and opened
+ (potentially overwriting any existing file). If ``None``, a
+ :class:`io.StringIO` object is created and used.
+
+ capture_fd : bool
+
+ If True, we will also redirect the process file descriptors
+ ``1`` (stdout), ``2`` (stderr), and the file descriptors from
+ ``sys.stdout.fileno()`` and ``sys.stderr.fileno()`` to the
+ ``output``. This is useful for capturing output emitted
+ directly to the process stdout / stderr by external compiled
+ modules.
+
+ Capturing and redirecting the file descriptors can cause loops
+ in the output stream (where one of the `output` streams points
+ to a file descriptor we just captured).
+ :py:class:`capture_output` will attempt to locate
+ :py:class:`io.IOBase` streams in `output` that point to file
+ descriptors that we just captured and replace them with
+ temporary streams that point to (copies of) the original file
+ descriptor. In addition, :py:class:`capture_output` will look
+ for :py:class:`~pyomo.common.log.LogStream` objects and will
+ attempt to locate :py:class:`logging.StreamHandle` objects that
+ would output to a redirected file descriptor and temporarily
+ redirect those handlers to (copies of) the original file
+ descriptor.
+
+ Note that this process will cover the most common cases, but is
+ by no means perfect. Use of other output classes or customized
+ log handlers may still result in output loops (usually
+ manifesting in an error message about text being left in the
+ output buffer).
+
+ Returns
+ -------
+ io.TextIOBase
+
+ This is the output stream object where all data is sent.
+
"""
def __init__(self, output=None, capture_fd=False):
if output is None:
- output = StringIO()
+ output = io.StringIO()
self.output = output
- self.output_file = None
self.old = None
self.tee = None
self.capture_fd = capture_fd
- self.fd_redirect = None
+ self.context_stack = []
- def __enter__(self):
- if isinstance(self.output, str):
- self.output_stream = open(self.output, 'w')
+ def _enter_context(self, cm, prior_to=None):
+ """Add the context manager to the context stack and return the result
+ from calling the context manager's `__enter__()`
+
+ """
+ if prior_to is None:
+ self.context_stack.append(cm)
else:
- self.output_stream = self.output
+ self.context_stack.insert(self.context_stack.index(prior_to), cm)
+ return cm.__enter__()
+
+ def _exit_context_stack(self, et, ev, tb):
+ """Flush the context stack, calling __exit__() on all context managers
+
+ One would usually use the contextlib.ExitStack to implement/manage
+ the collection of context managers we are putting together. The
+ problem is that ExitStack will only call the __exit__ handlers
+ up to the first one that returns an exception. As we are
+ expecting the possibility of one of the CMs here to raise an
+ exception (usually from TeeStream when joining the reader
+ threads), we will explicitly implement the stack management here
+ so that we will guarantee that all __exit__ handlers will always
+ be called.
+
+ """
+ FAIL = []
+ while self.context_stack:
+ try:
+ cm = self.context_stack.pop()
+ cm.__exit__(et, ev, tb)
+ except:
+ _stack = self.context_stack
+ FAIL.append(f"{sys.exc_info()[1]} ({len(_stack)+1}: {cm}@{id(cm):x})")
+ return FAIL
+
+ def __enter__(self):
self.old = (sys.stdout, sys.stderr)
- self.tee = TeeStream(self.output_stream)
- self.tee.__enter__()
+ old_fd = []
+ for stream in self.old:
+ stream.flush()
+ try:
+ old_fd.append(stream.fileno())
+ except (AttributeError, OSError):
+ old_fd.append(None)
+ try:
+ # We have an issue where we are (very aggressively)
+ # commandeering the terminal. This is what we intend, but the
+ # side effect is that any errors generated by this module (e.g.,
+ # because the user gave us an invalid output stream) get
+ # completely suppressed. So, we will make an exception to the
+ # output that we are catching and let messages logged to THIS
+ # logger to still be emitted to the original stderr.
+ if self.capture_fd:
+ # Because we are also commandeering the FD that underlies
+ # sys.stderr, we cannot just write to that stream and
+ # instead will open a new stream to the "original" FD
+ # (Note that we need to duplicate that FD, as we will
+ # overwrite it when we get to redirect_fd below). If
+ # sys.stderr doesn't have a file descriptor, we will
+ # fall back on the process stderr (FD=2).
+ #
+ # Note that we would like to use closefd=True, but can't
+ # (see _fd_closer docs)
+ log_stream = self._enter_context(
+ os.fdopen(
+ self._enter_context(_fd_closer(os.dup(old_fd[1] or 2))),
+ mode="w",
+ closefd=False,
+ )
+ )
+ else:
+ log_stream = self.old[1]
+ self._enter_context(LoggingIntercept(log_stream, logger=logger, level=None))
+
+ if isinstance(self.output, str):
+ self.output_stream = self._enter_context(open(self.output, 'w'))
+ else:
+ self.output_stream = self.output
+ if isinstance(self.output, TeeStream):
+ self.tee = self._enter_context(self.output)
+ elif isinstance(self.output_stream, collections.abc.Sequence):
+ self.tee = self._enter_context(TeeStream(*self.output_stream))
+ else:
+ self.tee = self._enter_context(TeeStream(self.output_stream))
+ fd_redirect = {}
+ if self.capture_fd:
+ tee_fd = (self.tee.STDOUT.fileno(), self.tee.STDERR.fileno())
+ for i in range(2):
+ # Redirect the standard process file descriptor (1 or 2)
+ fd_redirect[i + 1] = self._enter_context(
+ redirect_fd(i + 1, tee_fd[i], synchronize=False)
+ )
+ # Redirect the file descriptor currently associated with
+ # sys.stdout / sys.stderr
+ fd = old_fd[i]
+ if fd and fd not in fd_redirect:
+ fd_redirect[fd] = self._enter_context(
+ redirect_fd(fd, tee_fd[i], synchronize=False)
+ )
+ # We need to make sure that we didn't just capture the FD
+ # that underlies a stream that we are outputting to. Note
+ # that when capture_fd==False, normal streams will be left
+ # alone, but the lastResort _StderrHandler() will still be
+ # replaced (needed because that handler uses the *current*
+ # value of sys.stderr)
+ ostreams = []
+ for stream in self.tee.ostreams:
+ if isinstance(stream, LogStream):
+ for handler_redirect in stream.redirect_streams(fd_redirect):
+ self._enter_context(handler_redirect, prior_to=self.tee)
+ else:
+ try:
+ fd = stream.fileno()
+ except (AttributeError, OSError):
+ fd = None
+ if fd in fd_redirect:
+ # We just redirected this file descriptor so
+ # we can capture the output. This makes a
+ # loop that we really want to break. Undo
+ # the redirect by pointing our output stream
+ # back to the original file descriptor.
+ #
+ # Note that we would like to use closefd=True, but can't
+ # (see _fd_closer docs)
+ stream = self._enter_context(
+ os.fdopen(
+ self._enter_context(
+ _fd_closer(os.dup(fd_redirect[fd].original_fd)),
+ prior_to=self.tee,
+ ),
+ mode="w",
+ closefd=False,
+ ),
+ prior_to=self.tee,
+ )
+ ostreams.append(stream)
+ self.tee.ostreams = ostreams
+ except:
+ # Note: we will ignore any exceptions raised while exiting
+ # the context managers and just reraise the original
+ # exception.
+ self._exit_context_stack(*sys.exc_info())
+ raise
sys.stdout = self.tee.STDOUT
sys.stderr = self.tee.STDERR
- if self.capture_fd:
- self.fd_redirect = (
- redirect_fd(1, sys.stdout.fileno()),
- redirect_fd(2, sys.stderr.fileno()),
- )
- self.fd_redirect[0].__enter__()
- self.fd_redirect[1].__enter__()
- return self.output_stream
+ buf = self.tee.ostreams
+ if len(buf) == 1:
+ buf = buf[0]
+ return buf
def __exit__(self, et, ev, tb):
- if self.fd_redirect is not None:
- self.fd_redirect[1].__exit__(et, ev, tb)
- self.fd_redirect[0].__exit__(et, ev, tb)
- self.fd_redirect = None
- FAIL = self.tee.STDOUT is not sys.stdout
- self.tee.__exit__(et, ev, tb)
- if self.output_stream is not self.output:
- self.output_stream.close()
+ # Check that we were nested correctly
+ FAIL = []
+ if self.tee._stdout is not None and self.tee.STDOUT is not sys.stdout:
+ FAIL.append(
+ 'Captured output (%s) does not match sys.stdout (%s).'
+ % (self.tee._stdout, sys.stdout)
+ )
+ if self.tee._stderr is not None and self.tee.STDERR is not sys.stderr:
+ FAIL.append(
+ 'Captured output (%s) does not match sys.stderr (%s).'
+ % (self.tee._stdout, sys.stdout)
+ )
+ # Exit all context managers. This includes
+ # - Restore any file descriptors we commandeered
+ # - Close / join the TeeStream
+ # - Close any opened files
+ FAIL.extend(self._exit_context_stack(et, ev, tb))
sys.stdout, sys.stderr = self.old
self.old = None
self.tee = None
self.output_stream = None
if FAIL:
- raise RuntimeError('Captured output does not match sys.stdout.')
+ raise RuntimeError("\n".join(FAIL))
def __del__(self):
if self.tee is not None:
@@ -217,9 +438,22 @@ def reset(self):
class _StreamHandle(object):
+ """A stream handler object used by TeeStream
+
+ This handler holds the two sides of the pipe used to communicate
+ output generated by the main thread out to the handler thread (which
+ passes the output on to the TeeStream's output streams).
+
+ Note that this class is intimately tied to TeeStream and relies on
+ that class for certain termination / cleanup events (including
+ flushing and closing buffers)
+
+ """
+
def __init__(self, mode, buffering, encoding, newline):
self.buffering = buffering
self.newlines = newline
+ self.flush = False
self.read_pipe, self.write_pipe = os.pipe()
if not buffering and 'b' not in mode:
# While we support "unbuffered" behavior in text mode,
@@ -233,6 +467,13 @@ def __init__(self, mode, buffering, encoding, newline):
newline=newline,
closefd=False,
)
+ if not self.buffering and buffering:
+ # We want this stream to be unbuffered, but Python doesn't
+ # allow it for text streams. Mock up an unbuffered stream
+ # using AutoFlush
+ self.write_file = _AutoFlush(self.write_file, self)
+ else:
+ self.write_file = _SignalFlush(self.write_file, self)
self.decoder_buffer = b''
try:
self.encoding = encoding or self.write_file.encoding
@@ -243,9 +484,6 @@ def __init__(self, mode, buffering, encoding, newline):
else:
self.output_buffer = b''
- def __repr__(self):
- return "%s(%s)" % (self.buffering, id(self))
-
def fileno(self):
return self.read_pipe
@@ -253,7 +491,9 @@ def close(self):
# Close both the file and the underlying file descriptor. Note
# that this may get called more than once.
if self.write_file is not None:
- self.write_file.close()
+ if not self.write_file.closed:
+ self.write_file.flush()
+ self.write_file.close()
self.write_file = None
if self.write_pipe is not None:
@@ -266,19 +506,14 @@ def close(self):
self.write_pipe = None
def finalize(self, ostreams):
+ # Note that this expects to be called by TeeStream *after*
+ # TeeStream has called close(), so the output_buffer should have
+ # been flushed and emptied.
self.decodeIncomingBuffer()
if ostreams:
- # Turn off buffering for the final write
- self.buffering = 0
- self.writeOutputBuffer(ostreams)
+ self.writeOutputBuffer(ostreams, True)
os.close(self.read_pipe)
- if self.output_buffer:
- logger.error(
- "Stream handle closed with a partial line "
- "in the output buffer that was not emitted to the "
- "output stream(s):\n\t'%s'" % (self.output_buffer,)
- )
if self.decoder_buffer:
logger.error(
"Stream handle closed with un-decoded characters "
@@ -307,10 +542,10 @@ def decodeIncomingBuffer(self):
self.output_buffer += chars
self.decoder_buffer = self.decoder_buffer[raw_len:]
- def writeOutputBuffer(self, ostreams):
+ def writeOutputBuffer(self, ostreams, flush):
if not self.encoding:
ostring, self.output_buffer = self.output_buffer, b''
- elif self.buffering == 1:
+ elif self.buffering > 0 and not flush:
EOL = self.output_buffer.rfind(self.newlines or '\n') + 1
ostring = self.output_buffer[:EOL]
self.output_buffer = self.output_buffer[EOL:]
@@ -324,41 +559,80 @@ def writeOutputBuffer(self, ostreams):
try:
written = stream.write(ostring)
except:
- written = 0
- if written and not self.buffering:
- stream.flush()
+ my_repr = "<%s.%s @ %s>" % (
+ stream.__class__.__module__,
+ stream.__class__.__name__,
+ hex(id(stream)),
+ )
+ if my_repr in ostring:
+ # In the case of nested capture_outputs, all the
+ # handlers are left on the logger. We want to make
+ # sure that we don't create an infinite loop by
+ # re-printing a message *this* object generated.
+ continue
+ et, e, tb = sys.exc_info()
+ msg = "Error writing to output stream %s:\n %s: %s\n" % (
+ my_repr,
+ et.__name__,
+ e,
+ )
+ if getattr(stream, 'closed', False):
+ msg += "Output stream closed before all output was written to it."
+ else:
+ msg += "Is this a writeable TextIOBase object?"
+ logger.error(
+ f"{msg}\nThe following was left in the output buffer:\n"
+ f" {ostring!r}"
+ )
+ continue
+ if flush or (written and not self.buffering):
+ getattr(stream, 'flush', _noop)()
# Note: some derived file-like objects fail to return the
# number of characters written (and implicitly return None).
# If we get None, we will just assume that everything was
# fine (as opposed to tossing the incomplete write error).
if written is not None and written != len(ostring):
+ my_repr = "<%s.%s @ %s>" % (
+ stream.__class__.__module__,
+ stream.__class__.__name__,
+ hex(id(stream)),
+ )
+ if my_repr in ostring[written:]:
+ continue
logger.error(
- "Output stream (%s) closed before all output was "
- "written to it. The following was left in "
- "the output buffer:\n\t%r" % (stream, ostring[written:])
+ "Incomplete write to output stream %s.\nThe following was "
+ "left in the output buffer:\n %r" % (my_repr, ostring[written:])
)
class TeeStream(object):
- def __init__(self, *ostreams, encoding=None):
+ def __init__(self, *ostreams, encoding=None, buffering=-1):
self.ostreams = ostreams
self.encoding = encoding
+ self.buffering = buffering
self._stdout = None
self._stderr = None
self._handles = []
self._active_handles = []
self._threads = []
+ self._enter_count = 0
@property
def STDOUT(self):
if self._stdout is None:
- self._stdout = self.open(buffering=1)
+ b = self.buffering
+ if b == -1:
+ b = 1
+ self._stdout = self.open(buffering=b)
return self._stdout
@property
def STDERR(self):
if self._stderr is None:
- self._stderr = self.open(buffering=0)
+ b = self.buffering
+ if b == -1:
+ b = 0
+ self._stderr = self.open(buffering=b)
return self._stderr
def open(self, mode='w', buffering=-1, encoding=None, newline=None):
@@ -393,6 +667,7 @@ def close(self, in_exception=False):
# Join all stream processing threads
_poll = _poll_interval
+ FAIL = False
while True:
for th in self._threads:
th.join(_poll)
@@ -403,16 +678,21 @@ def close(self, in_exception=False):
if _poll_timeout <= _poll < 2 * _poll_timeout:
if in_exception:
# We are already processing an exception: no reason
- # to trigger another, nor to deadlock for an extended time
+ # to trigger another, nor to deadlock for an
+ # extended time. Silently clean everything up
+ # (because emitting logger messages could trigger
+ # yet another exception and mask the true cause).
break
logger.warning(
"Significant delay observed waiting to join reader "
"threads, possible output stream deadlock"
)
elif _poll >= _poll_timeout_deadlock:
- raise RuntimeError(
- "TeeStream: deadlock observed joining reader threads"
- )
+ logger.error("TeeStream: deadlock observed joining reader threads")
+ # Defer raising the exception until after we have
+ # cleaned things up
+ FAIL = True
+ break
for h in list(self._handles):
h.finalize(self.ostreams)
@@ -422,16 +702,22 @@ def close(self, in_exception=False):
self._active_handles.clear()
self._stdout = None
self._stderr = None
+ if FAIL:
+ raise RuntimeError("TeeStream: deadlock observed joining reader threads")
def __enter__(self):
+ self._enter_count += 1
return self
def __exit__(self, et, ev, tb):
+ if not self._enter_count:
+ raise RuntimeError("TeeStream: exiting a context that was not entered")
+ self._enter_count -= 1
self.close(et is not None)
def __del__(self):
# Implement __del__ to guarantee that file descriptors are closed
- # ... but only if we are not called by the GC in the handler thread
+ # ... but only if we are not called by the GC in a handler thread
if threading.current_thread() not in self._threads:
self.close()
@@ -454,15 +740,21 @@ def _start(self, handle):
def _streamReader(self, handle):
while True:
new_data = os.read(handle.read_pipe, io.DEFAULT_BUFFER_SIZE)
- if not new_data:
+ if handle.flush:
+ flush = True
+ handle.flush = False
+ else:
+ flush = False
+ if new_data:
+ handle.decoder_buffer += new_data
+ elif not flush:
break
- handle.decoder_buffer += new_data
# At this point, we have new data sitting in the
# handle.decoder_buffer
handle.decodeIncomingBuffer()
# Now, output whatever we have decoded to the output streams
- handle.writeOutputBuffer(self.ostreams)
+ handle.writeOutputBuffer(self.ostreams, flush)
#
# print("STREAM READER: DONE")
@@ -473,6 +765,7 @@ def _mergedReader(self):
_fast_poll_ct = _poll_rampup
new_data = '' # something not None
while handles:
+ flush = False
if new_data is None:
# For performance reasons, we use very aggressive
# polling at the beginning (_poll_interval) and then
@@ -492,6 +785,9 @@ def _mergedReader(self):
if _mswindows:
for handle in list(handles):
try:
+ if handle.flush:
+ flush = True
+ handle.flush = False
pipe = get_osfhandle(handle.read_pipe)
numAvail = PeekNamedPipe(pipe, 0)[1]
if numAvail:
@@ -500,8 +796,8 @@ def _mergedReader(self):
break
except:
handles.remove(handle)
- new_data = None
- if new_data is None:
+ new_data = '' # not None so the poll interval doesn't increase
+ if new_data is None and not flush:
# PeekNamedPipe is non-blocking; to avoid swamping
# the core, sleep for a "short" amount of time
time.sleep(_poll)
@@ -515,22 +811,32 @@ def _mergedReader(self):
# deadlocks when handles are added while select() is
# waiting
ready_handles = select(list(handles), noop, noop, _poll)[0]
- if not ready_handles:
- new_data = None
- continue
+ if ready_handles:
+ handle = ready_handles[0]
+ new_data = os.read(handle.read_pipe, io.DEFAULT_BUFFER_SIZE)
+ if new_data:
+ handle.decoder_buffer += new_data
+ else:
+ handles.remove(handle)
+ new_data = '' # not None so the poll interval doesn't increase
+ else:
+ for handle in handles:
+ if handle.flush:
+ new_data = ''
+ break
+ else:
+ new_data = None
+ continue
- handle = ready_handles[0]
- new_data = os.read(handle.read_pipe, io.DEFAULT_BUFFER_SIZE)
- if not new_data:
- handles.remove(handle)
- continue
- handle.decoder_buffer += new_data
+ if handle.flush:
+ flush = True
+ handle.flush = False
# At this point, we have new data sitting in the
# handle.decoder_buffer
handle.decodeIncomingBuffer()
# Now, output whatever we have decoded to the output streams
- handle.writeOutputBuffer(self.ostreams)
+ handle.writeOutputBuffer(self.ostreams, flush)
#
# print("MERGED READER: DONE")
diff --git a/pyomo/common/tempfiles.py b/pyomo/common/tempfiles.py
index b9dface71b2..7d8c81cd641 100644
--- a/pyomo/common/tempfiles.py
+++ b/pyomo/common/tempfiles.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -100,24 +100,25 @@ def __del__(self):
def shutdown(self, remove=True):
if not self._context_stack:
return
- if any(ctx.tempfiles for ctx in self._context_stack):
- logger.error(
- "Temporary files created through TempfileManager "
- "contexts have not been deleted (observed during "
- "TempfileManager instance shutdown).\n"
- "Undeleted entries:\n\t"
- + "\n\t".join(
- fname if isinstance(fname, str) else fname.decode()
- for ctx in self._context_stack
- for fd, fname in ctx.tempfiles
+ if logger is not None:
+ if any(ctx.tempfiles for ctx in self._context_stack):
+ logger.error(
+ "Temporary files created through TempfileManager "
+ "contexts have not been deleted (observed during "
+ "TempfileManager instance shutdown).\n"
+ "Undeleted entries:\n\t"
+ + "\n\t".join(
+ fname if isinstance(fname, str) else fname.decode()
+ for ctx in self._context_stack
+ for fd, fname in ctx.tempfiles
+ )
+ )
+ if self._context_stack:
+ logger.warning(
+ "TempfileManagerClass instance: un-popped tempfile "
+ "contexts still exist during TempfileManager instance "
+ "shutdown"
)
- )
- if self._context_stack:
- logger.warning(
- "TempfileManagerClass instance: un-popped tempfile "
- "contexts still exist during TempfileManager instance "
- "shutdown"
- )
self.clear_tempfiles(remove)
# Delete the stack so that subsequent operations generate an
# exception
@@ -252,6 +253,13 @@ def __init__(self, manager):
self.manager = weakref.ref(manager)
self.tempfiles = []
self.tempdir = None
+ # Create a local reference from the TempfileContext to the os
+ # and shutil modules so that this object is deleted before the
+ # os and shutil modules are deallocated (since
+ # TempfileContext.__del__ can call methods in those modules
+ # through TempfileContext.release()).
+ self.os = os
+ self.shutil = shutil
def __del__(self):
self.release()
@@ -410,11 +418,11 @@ def release(self, remove=True):
remove: bool
If ``True``, delete all managed files / directories
"""
- if remove:
+ if remove and self.tempfiles:
for fd, name in reversed(self.tempfiles):
if fd is not None:
try:
- os.close(fd)
+ self.os.close(fd)
except OSError:
pass
self._remove_filesystem_object(name)
@@ -443,11 +451,11 @@ def _resolve_tempdir(self, dir=None):
return None
def _remove_filesystem_object(self, name):
- if not os.path.exists(name):
+ if not self.os.path.exists(name):
return
- if os.path.isfile(name) or os.path.islink(name):
+ if self.os.path.isfile(name) or self.os.path.islink(name):
try:
- os.remove(name)
+ self.os.remove(name)
except WindowsError:
# Sometimes Windows doesn't release the
# file lock immediately when the process
@@ -455,7 +463,7 @@ def _remove_filesystem_object(self, name):
# second and try again.
try:
time.sleep(1)
- os.remove(name)
+ self.os.remove(name)
except WindowsError:
if deletion_errors_are_fatal:
raise
@@ -465,8 +473,8 @@ def _remove_filesystem_object(self, name):
logger = logging.getLogger(__name__)
logger.warning("Unable to delete temporary file %s" % (name,))
return
- assert os.path.isdir(name)
- shutil.rmtree(name, ignore_errors=not deletion_errors_are_fatal)
+ assert self.os.path.isdir(name)
+ self.shutil.rmtree(name, ignore_errors=not deletion_errors_are_fatal)
# The global Pyomo TempfileManager instance
diff --git a/pyomo/common/tests/__init__.py b/pyomo/common/tests/__init__.py
index d8d8856e52f..1304f66162b 100644
--- a/pyomo/common/tests/__init__.py
+++ b/pyomo/common/tests/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/config_plugin.py b/pyomo/common/tests/config_plugin.py
index 6aebc40806a..50846504460 100644
--- a/pyomo/common/tests/config_plugin.py
+++ b/pyomo/common/tests/config_plugin.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/dep_mod.py b/pyomo/common/tests/dep_mod.py
index f6add596ed4..f6fdaab14d2 100644
--- a/pyomo/common/tests/dep_mod.py
+++ b/pyomo/common/tests/dep_mod.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,8 +13,8 @@
__version__ = '1.5'
-numpy, numpy_available = attempt_import('numpy', defer_check=True)
+numpy, numpy_available = attempt_import('numpy', defer_import=True)
bogus_nonexisting_module, bogus_nonexisting_module_available = attempt_import(
- 'bogus_nonexisting_module', alt_names=['bogus_nem'], defer_check=True
+ 'bogus_nonexisting_module', alt_names=['bogus_nem'], defer_import=True
)
diff --git a/pyomo/common/tests/dep_mod_except.py b/pyomo/common/tests/dep_mod_except.py
index 16936996eeb..31616f79e78 100644
--- a/pyomo/common/tests/dep_mod_except.py
+++ b/pyomo/common/tests/dep_mod_except.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/deps.py b/pyomo/common/tests/deps.py
index d00281553f4..876858fd125 100644
--- a/pyomo/common/tests/deps.py
+++ b/pyomo/common/tests/deps.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -23,15 +23,16 @@
bogus_nonexisting_module_available as has_bogus_nem,
)
-bogus, bogus_available = attempt_import('nonexisting.module.bogus', defer_check=True)
+bogus, bogus_available = attempt_import('nonexisting.module.bogus', defer_import=True)
pkl_test, pkl_available = attempt_import(
- 'nonexisting.module.pickle_test', deferred_submodules=['submod'], defer_check=True
+ 'nonexisting.module.pickle_test', deferred_submodules=['submod'], defer_import=True
)
pyo, pyo_available = attempt_import(
'pyomo',
alt_names=['pyo'],
+ defer_import=True,
deferred_submodules={'version': None, 'common.tests.dep_mod': ['dm']},
)
diff --git a/pyomo/common/tests/import_ex.py b/pyomo/common/tests/import_ex.py
index 73375bdc819..b305ec6ec6e 100644
--- a/pyomo/common/tests/import_ex.py
+++ b/pyomo/common/tests/import_ex.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/mod.py b/pyomo/common/tests/mod.py
new file mode 100644
index 00000000000..495aae457df
--- /dev/null
+++ b/pyomo/common/tests/mod.py
@@ -0,0 +1,17 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+#
+
+# This is a simple module used as part of testing import callbacks
+
+
+class Foo(object):
+ data = 42
diff --git a/pyomo/common/tests/moved.py b/pyomo/common/tests/moved.py
new file mode 100644
index 00000000000..55912a76213
--- /dev/null
+++ b/pyomo/common/tests/moved.py
@@ -0,0 +1,17 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+#
+
+# This is a simple module used as part of testing moved_module()
+
+
+class Bar(object):
+ data = 42
diff --git a/pyomo/common/tests/relo_mod.py b/pyomo/common/tests/relo_mod.py
index 4881caba671..266ac913206 100644
--- a/pyomo/common/tests/relo_mod.py
+++ b/pyomo/common/tests/relo_mod.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/relo_mod_new.py b/pyomo/common/tests/relo_mod_new.py
index 0f59f3beebc..d616574aa99 100644
--- a/pyomo/common/tests/relo_mod_new.py
+++ b/pyomo/common/tests/relo_mod_new.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/relocated.py b/pyomo/common/tests/relocated.py
index 90cb28c23ba..b7572f7db36 100644
--- a/pyomo/common/tests/relocated.py
+++ b/pyomo/common/tests/relocated.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_bunch.py b/pyomo/common/tests/test_bunch.py
index 8c10df83005..70149761486 100644
--- a/pyomo/common/tests/test_bunch.py
+++ b/pyomo/common/tests/test_bunch.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_component_map.py b/pyomo/common/tests/test_component_map.py
index 7cd4ec2c458..13cb49c06e1 100644
--- a/pyomo/common/tests/test_component_map.py
+++ b/pyomo/common/tests/test_component_map.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -49,6 +49,27 @@ def test_tuple(self):
self.assertIn((1, (2, m.v)), m.cm)
self.assertNotIn((1, (2, m.v)), i.cm)
+ def test_hasher(self):
+ m = ComponentMap()
+ a = 'str'
+ m[a] = 5
+ self.assertTrue(m.hasher.hashable(a))
+ self.assertTrue(m.hasher.hashable(str))
+ self.assertEqual(m._dict, {a: (a, 5)})
+ del m[a]
+
+ m.hasher.hashable(a, False)
+ m[a] = 5
+ self.assertFalse(m.hasher.hashable(a))
+ self.assertFalse(m.hasher.hashable(str))
+ self.assertEqual(m._dict, {id(a): (a, 5)})
+
+ class TMP:
+ pass
+
+ with self.assertRaises(KeyError):
+ m.hasher.hashable(TMP)
+
class TestDefaultComponentMap(unittest.TestCase):
def test_default_component_map(self):
diff --git a/pyomo/common/tests/test_config.py b/pyomo/common/tests/test_config.py
index 0bbed43423d..da87e5fe340 100644
--- a/pyomo/common/tests/test_config.py
+++ b/pyomo/common/tests/test_config.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -88,6 +88,7 @@ def _display(obj, *args):
class GlobalClass(object):
"test class for test_known_types"
+
pass
@@ -481,9 +482,7 @@ def __repr__(self):
None, IsInstance(int, TestClass, document_full_base_names=True)
),
)
- self.assertRegex(
- c.get("val3").domain_name(), r"IsInstance\(int, .*\.TestClass\)"
- )
+ self.assertRegex(c.get("val3").domain_name(), r"IsInstance\[int, TestClass\]")
c.val3 = 2
self.assertEqual(c.val3, 2)
exc_str = (
@@ -499,7 +498,7 @@ def __repr__(self):
None, IsInstance(int, TestClass, document_full_base_names=False)
),
)
- self.assertEqual(c.get("val4").domain_name(), "IsInstance(int, TestClass)")
+ self.assertEqual(c.get("val4").domain_name(), "IsInstance[int, TestClass]")
c.val4 = 2
self.assertEqual(c.val4, 2)
exc_str = (
@@ -1175,7 +1174,6 @@ def _validateTemplate(self, config, reference_template, **kwds):
test = config.generate_yaml_template(**kwds)
width = kwds.get('width', 80)
indent = kwds.get('indent_spacing', 2)
- sys.stdout.write(test)
for l in test.splitlines():
self.assertLessEqual(len(l), width)
if l.strip().startswith("#"):
@@ -1337,7 +1335,6 @@ def test_display_default(self):
response time: 60.0
"""
test = _display(self.config)
- sys.stdout.write(test)
self.assertEqual(test, reference)
def test_display_list(self):
@@ -1376,18 +1373,15 @@ def test_display_list(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = _display(self.config)
- sys.stdout.write(test)
self.assertEqual(test, reference)
def test_display_userdata_default(self):
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_display_userdata_list(self):
self.config['scenarios'].append()
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios:
@@ -1399,7 +1393,6 @@ def test_display_userdata_list_nonDefault(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios:
@@ -1414,7 +1407,6 @@ def test_display_userdata_add_block(self):
self.config.add("foo", ConfigValue(0, int, None, None))
self.config.add("bar", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""foo: 0
@@ -1426,7 +1418,6 @@ def test_display_userdata_add_block_nonDefault(self):
self.config.add("foo", ConfigValue(0, int, None, None))
self.config.add("bar", ConfigDict(implicit=True)).add("baz", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""foo: 0
@@ -1435,42 +1426,48 @@ def test_display_userdata_add_block_nonDefault(self):
""",
)
+ def test_display_nondata_type(self):
+ class NOOP(object):
+ def __getattr__(self, attr):
+ def noop(*args, **kwargs):
+ pass
+
+ return noop
+
+ cfg = ConfigDict()
+ cfg.declare('callback', ConfigValue(default=NOOP))
+ self.assertEqual(_display(cfg), "callback: \n")
+
def test_display_userdata_declare_block(self):
self.config.declare("foo", ConfigValue(0, int, None, None))
self.config.declare("bar", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_display_userdata_declare_block_nonDefault(self):
self.config.declare("foo", ConfigValue(0, int, None, None))
self.config.declare("bar", ConfigDict(implicit=True)).add("baz", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(test, "bar:\n baz:\n")
def test_unusedUserValues_default(self):
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_unusedUserValues_scalar(self):
self.config['scenario']['merlion'] = True
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "scenario.merlion")
def test_unusedUserValues_list(self):
self.config['scenarios'].append()
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, """scenarios[0]""")
def test_unusedUserValues_list_nonDefault(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1485,7 +1482,6 @@ def test_unusedUserValues_list_nonDefault_listAccessed(self):
for x in self.config['scenarios']:
pass
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1499,7 +1495,6 @@ def test_unusedUserValues_list_nonDefault_itemAccessed(self):
self.config['scenarios'].append({'merlion': True, 'detection': []})
self.config['scenarios'][1]['merlion']
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1509,52 +1504,43 @@ def test_unusedUserValues_list_nonDefault_itemAccessed(self):
def test_unusedUserValues_add_topBlock(self):
self.config.add('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "foo")
test = '\n'.join(x.name(True) for x in self.config.foo.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "foo")
def test_unusedUserValues_add_subBlock(self):
self.config['scenario'].add('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, """scenario.foo""")
def test_unusedUserValues_declare_topBlock(self):
self.config.declare('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_unusedUserValues_declare_subBlock(self):
self.config['scenario'].declare('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.unused_user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_UserValues_default(self):
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_UserValues_scalar(self):
self.config['scenario']['merlion'] = True
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "scenario.merlion")
def test_UserValues_list(self):
self.config['scenarios'].append()
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, """scenarios[0]""")
def test_UserValues_list_nonDefault(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1569,7 +1555,6 @@ def test_UserValues_list_nonDefault_listAccessed(self):
for x in self.config['scenarios']:
pass
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1583,7 +1568,6 @@ def test_UserValues_list_nonDefault_itemAccessed(self):
self.config['scenarios'].append({'merlion': True, 'detection': []})
self.config['scenarios'][1]['merlion']
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios[0]
@@ -1595,34 +1579,28 @@ def test_UserValues_list_nonDefault_itemAccessed(self):
def test_UserValues_add_topBlock(self):
self.config.add('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "foo")
test = '\n'.join(x.name(True) for x in self.config.foo.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "foo")
def test_UserValues_add_subBlock(self):
self.config['scenario'].add('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, """scenario.foo""")
def test_UserValues_declare_topBlock(self):
self.config.declare('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
def test_UserValues_declare_subBlock(self):
self.config['scenario'].declare('foo', ConfigDict())
test = '\n'.join(x.name(True) for x in self.config.user_values())
- sys.stdout.write(test)
self.assertEqual(test, "")
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
def test_parseDisplayAndValue_default(self):
test = _display(self.config)
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), self.config.value())
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
@@ -1630,20 +1608,17 @@ def test_parseDisplayAndValue_list(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = _display(self.config)
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), self.config.value())
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
def test_parseDisplay_userdata_default(self):
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), None)
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
def test_parseDisplay_userdata_list(self):
self.config['scenarios'].append()
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), {'scenarios': [None]})
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
@@ -1651,7 +1626,6 @@ def test_parseDisplay_userdata_list_nonDefault(self):
self.config['scenarios'].append()
self.config['scenarios'].append({'merlion': True, 'detection': []})
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
yaml_load(test), {'scenarios': [None, {'merlion': True, 'detection': []}]}
)
@@ -1661,7 +1635,6 @@ def test_parseDisplay_userdata_add_block(self):
self.config.add("foo", ConfigValue(0, int, None, None))
self.config.add("bar", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), {'foo': 0, 'bar': None})
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
@@ -1669,7 +1642,6 @@ def test_parseDisplay_userdata_add_block_nonDefault(self):
self.config.add("foo", ConfigValue(0, int, None, None))
self.config.add("bar", ConfigDict(implicit=True)).add("baz", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), {'bar': {'baz': None}, 'foo': 0})
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
@@ -1677,7 +1649,6 @@ def test_parseDisplay_userdata_add_block(self):
self.config.declare("foo", ConfigValue(0, int, None, None))
self.config.declare("bar", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), None)
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
@@ -1685,7 +1656,6 @@ def test_parseDisplay_userdata_add_block_nonDefault(self):
self.config.declare("foo", ConfigValue(0, int, None, None))
self.config.declare("bar", ConfigDict(implicit=True)).add("baz", ConfigDict())
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(yaml_load(test), {'bar': {'baz': None}})
def test_value_ConfigValue(self):
@@ -1889,11 +1859,24 @@ def test_default_function(self):
c.reset()
self.assertEqual(c.value(), 10)
+ c = ConfigValue(default=lambda x: 10 * x, domain=int)
with self.assertRaisesRegex(TypeError, r"\(\) .* argument"):
- c = ConfigValue(default=lambda x: 10 * x, domain=int)
+ c.value()
- with self.assertRaisesRegex(ValueError, 'invalid value for configuration'):
- c = ConfigValue('a', domain=int)
+ c = ConfigValue('a', domain=int)
+ with self.assertRaisesRegex(
+ ValueError, '(?s)invalid value for configuration.*casting a'
+ ):
+ c.value()
+
+ # Test that if both the default and the result from calling the
+ # default raise exceptions, the propagated exception is from
+ # castig the original default:
+ c = ConfigValue(default=lambda: 'a', domain=int)
+ with self.assertRaisesRegex(
+ ValueError, "(?s)invalid value for configuration.*lambda"
+ ):
+ c.value()
def test_set_default(self):
c = ConfigValue()
@@ -2098,7 +2081,6 @@ def test_generate_custom_documentation(self):
"generate_documentation is deprecated.",
LOG,
)
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -2113,7 +2095,6 @@ def test_generate_custom_documentation(self):
)
)
self.assertEqual(LOG.getvalue(), "")
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -2159,7 +2140,6 @@ def test_generate_custom_documentation(self):
"generate_documentation is deprecated.",
LOG,
)
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -2424,7 +2404,6 @@ def test_list_manipulation(self):
self.config['scenarios'].append({'merlion': True, 'detection': []})
self.assertEqual(len(self.config['scenarios']), 3)
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios:
@@ -2438,7 +2417,6 @@ def test_list_manipulation(self):
self.config['scenarios'][0] = {'merlion': True, 'detection': []}
self.assertEqual(len(self.config['scenarios']), 3)
test = _display(self.config, 'userdata')
- sys.stdout.write(test)
self.assertEqual(
test,
"""scenarios:
@@ -2452,7 +2430,6 @@ def test_list_manipulation(self):
""",
)
test = _display(self.config['scenarios'])
- sys.stdout.write(test)
self.assertEqual(
test,
"""-
@@ -2577,7 +2554,6 @@ def test_argparse_help_implicit_disable(self):
parser = argparse.ArgumentParser(prog='tester')
self.config.initialize_argparse(parser)
help = parser.format_help()
- self.maxDiff = None
self.assertIn(
"""
-h, --help show this help message and exit
@@ -2772,7 +2748,9 @@ def test_getattr_setattr(self):
):
config.baz = 10
- with self.assertRaisesRegex(AttributeError, "Unknown attribute 'baz'"):
+ with self.assertRaisesRegex(
+ AttributeError, "'ConfigDict' object has no attribute 'baz'"
+ ):
a = config.baz
def test_nonString_keys(self):
@@ -2919,6 +2897,18 @@ def test_call_options(self):
self.assertEqual(mod_copy._description, "new description")
self.assertEqual(mod_copy._visibility, 0)
+ def test_template_nondata(self):
+ class NOOP(object):
+ def __getattr__(self, attr):
+ def noop(*args, **kwargs):
+ pass
+
+ return noop
+
+ cfg = ConfigDict()
+ cfg.declare('callback', ConfigValue(default=NOOP, description="docstr"))
+ self._validateTemplate(cfg, "callback: # docstr\n")
+
def test_pickle(self):
def anon_domain(domain):
def cast(x):
@@ -3106,8 +3096,6 @@ def test_declare_from(self):
cfg2.declare_from({})
def test_docstring_decorator(self):
- self.maxDiff = None
-
@document_kwargs_from_configdict('CONFIG')
class ExampleClass(object):
CONFIG = ExampleConfig()
@@ -3126,16 +3114,19 @@ def fcn(self):
Keyword Arguments
-----------------
option_1: int, default=5
+
The first configuration option
solver_options: dict, optional
solver_option_1: float, default=1
+
[DEVELOPER option]
The first solver configuration option
solver_option_2: float, default=1
+
The second solver configuration option
With a very long line containing wrappable text in a long, silly
@@ -3144,6 +3135,7 @@ def fcn(self):
#) with two bullets
solver_option_3: float, default=1
+
The third solver configuration option
This has a leading newline and a very long line containing
@@ -3155,6 +3147,7 @@ def fcn(self):
#) with two bullets
option_2: int, default=5
+
The second solver configuration option with a very long line
containing wrappable text in a long, silly paragraph with little
actual information."""
@@ -3165,11 +3158,13 @@ def fcn(self):
Keyword Arguments
-----------------
option_1: int, default=5
+
The first configuration option
solver_options: dict, optional
solver_option_2: float, default=1
+
The second solver configuration option
With a very long line containing wrappable text in a long, silly
@@ -3178,6 +3173,7 @@ def fcn(self):
#) with two bullets
solver_option_3: float, default=1
+
The third solver configuration option
This has a leading newline and a very long line containing
@@ -3189,6 +3185,7 @@ def fcn(self):
#) with two bullets
option_2: int, default=5
+
The second solver configuration option with a very long line
containing wrappable text in a long, silly paragraph with little
actual information."""
@@ -3198,11 +3195,13 @@ def fcn(self):
Keyword Arguments
-----------------
option_1: int, default=5
+
The first configuration option
solver_options: dict, optional
solver_option_2: float, default=1
+
The second solver configuration option
With a very long line containing wrappable text in a long, silly paragraph with little actual information.
@@ -3210,6 +3209,7 @@ def fcn(self):
#) with two bullets
solver_option_3: float, default=1
+
The third solver configuration option
This has a leading newline and a very long line containing wrappable text in a long, silly paragraph with little actual information.
@@ -3219,6 +3219,7 @@ def fcn(self):
#) with two bullets
option_2: int, default=5
+
The second solver configuration option with a very long line containing wrappable text in a long, silly paragraph with little actual information."""
with LoggingIntercept() as LOG:
self.assertEqual(add_docstring_list("", ExampleClass.CONFIG), ref)
@@ -3265,6 +3266,91 @@ def __init__(
OUT.getvalue().replace('null', 'None'),
)
+ def test_domain_name(self):
+ cfg = ConfigDict()
+
+ cfg.declare('none', ConfigValue())
+ self.assertEqual(cfg.get('none').domain_name(), '')
+
+ def fcn(val):
+ return val
+
+ cfg.declare('fcn', ConfigValue(domain=fcn))
+ self.assertEqual(cfg.get('fcn').domain_name(), 'fcn')
+
+ fcn.domain_name = 'custom fcn'
+ self.assertEqual(cfg.get('fcn').domain_name(), 'custom fcn')
+
+ class functor:
+ def __call__(self, val):
+ return val
+
+ cfg.declare('functor', ConfigValue(domain=functor()))
+ self.assertEqual(cfg.get('functor').domain_name(), 'functor')
+
+ class cfunctor:
+ def __call__(self, val):
+ return val
+
+ def domain_name(self):
+ return 'custom functor'
+
+ cfg.declare('cfunctor', ConfigValue(domain=cfunctor()))
+ self.assertEqual(cfg.get('cfunctor').domain_name(), 'custom functor')
+
+ cfg.declare('type', ConfigValue(domain=int))
+ self.assertEqual(cfg.get('type').domain_name(), 'int')
+
+ def test_deferred_initialization(self):
+ class Accumulator(object):
+ def __init__(self):
+ self.data = []
+
+ def __call__(self, val):
+ self.data.append(val)
+ return val
+
+ record = Accumulator()
+
+ cfg = ConfigDict()
+ cfg.declare('a', ConfigValue(5, record))
+ self.assertEqual(record.data, [])
+ self.assertEqual(cfg.a, 5)
+ self.assertEqual(record.data, [5])
+
+ # Test that assignment bypasses the default value
+ cfg.declare('b', ConfigValue(6, record))
+ self.assertEqual(record.data, [5])
+ cfg.b = 10
+ self.assertEqual(record.data, [5, 10])
+ self.assertEqual(cfg.b, 10)
+ self.assertEqual(record.data, [5, 10])
+
+ # But resetting it will trigger the default
+ cfg.get('b').reset()
+ self.assertEqual(record.data, [5, 10, 6])
+ self.assertEqual(cfg.b, 6)
+
+ record.data = []
+ cfg.declare('la', ConfigList(['a', 'b'], ConfigValue(7, record)))
+ self.assertEqual(record.data, [])
+ self.assertEqual(cfg.la.value(), ['a', 'b'])
+ self.assertEqual(record.data, [7, 'a', 'b'])
+
+ # Test that assignment bypasses the default value
+ record.data = []
+ cfg.declare('lb', ConfigList(['a', 'b'], record))
+ self.assertEqual(record.data, [])
+ cfg.lb = [10, 11]
+ self.assertEqual(record.data, [10, 11])
+ self.assertEqual(cfg.lb.value(), [10, 11])
+ self.assertEqual(record.data, [10, 11])
+
+ # But resetting it will trigger the default
+ cfg.get('lb').reset()
+ self.assertEqual(record.data, [10, 11, 'a', 'b'])
+ self.assertEqual(cfg.lb.value(), ['a', 'b'])
+
if __name__ == "__main__":
unittest.main()
diff --git a/pyomo/common/tests/test_dependencies.py b/pyomo/common/tests/test_dependencies.py
index 30822a4f81f..7d3c28a1522 100644
--- a/pyomo/common/tests/test_dependencies.py
+++ b/pyomo/common/tests/test_dependencies.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,6 +10,8 @@
# ___________________________________________________________________________
import inspect
+import sys
+from importlib.machinery import PathFinder
from io import StringIO
import pyomo.common.unittest as unittest
@@ -24,9 +26,11 @@
UnavailableClass,
_DeferredAnd,
_DeferredOr,
+ _DeferredImportCallbackFinder,
check_min_version,
dill,
dill_available,
+ mpi4py_available,
)
import pyomo.common.tests.dep_mod as dep_mod
@@ -45,7 +49,7 @@ def test_import_error(self):
module_obj, module_available = attempt_import(
'__there_is_no_module_named_this__',
'Testing import of a non-existent module',
- defer_check=False,
+ defer_import=False,
)
self.assertFalse(module_available)
with self.assertRaisesRegex(
@@ -85,7 +89,7 @@ def test_pickle(self):
def test_import_success(self):
module_obj, module_available = attempt_import(
- 'ply', 'Testing import of ply', defer_check=False
+ 'ply', 'Testing import of ply', defer_import=False
)
self.assertTrue(module_available)
import ply
@@ -123,7 +127,7 @@ def test_imported_deferred_import(self):
def test_min_version(self):
mod, avail = attempt_import(
- 'pyomo.common.tests.dep_mod', minimum_version='1.0', defer_check=False
+ 'pyomo.common.tests.dep_mod', minimum_version='1.0', defer_import=False
)
self.assertTrue(avail)
self.assertTrue(inspect.ismodule(mod))
@@ -131,7 +135,7 @@ def test_min_version(self):
self.assertFalse(check_min_version(mod, '2.0'))
mod, avail = attempt_import(
- 'pyomo.common.tests.dep_mod', minimum_version='2.0', defer_check=False
+ 'pyomo.common.tests.dep_mod', minimum_version='2.0', defer_import=False
)
self.assertFalse(avail)
self.assertIs(type(mod), ModuleUnavailable)
@@ -146,7 +150,7 @@ def test_min_version(self):
'pyomo.common.tests.dep_mod',
error_message="Failed import",
minimum_version='2.0',
- defer_check=False,
+ defer_import=False,
)
self.assertFalse(avail)
self.assertIs(type(mod), ModuleUnavailable)
@@ -159,10 +163,10 @@ def test_min_version(self):
# Verify check_min_version works with deferred imports
- mod, avail = attempt_import('pyomo.common.tests.dep_mod', defer_check=True)
+ mod, avail = attempt_import('pyomo.common.tests.dep_mod', defer_import=True)
self.assertTrue(check_min_version(mod, '1.0'))
- mod, avail = attempt_import('pyomo.common.tests.dep_mod', defer_check=True)
+ mod, avail = attempt_import('pyomo.common.tests.dep_mod', defer_import=True)
self.assertFalse(check_min_version(mod, '2.0'))
# Verify check_min_version works when called directly
@@ -174,10 +178,10 @@ def test_min_version(self):
self.assertFalse(check_min_version(mod, '1.0'))
def test_and_or(self):
- mod0, avail0 = attempt_import('ply', defer_check=True)
- mod1, avail1 = attempt_import('pyomo.common.tests.dep_mod', defer_check=True)
+ mod0, avail0 = attempt_import('ply', defer_import=True)
+ mod1, avail1 = attempt_import('pyomo.common.tests.dep_mod', defer_import=True)
mod2, avail2 = attempt_import(
- 'pyomo.common.tests.dep_mod', minimum_version='2.0', defer_check=True
+ 'pyomo.common.tests.dep_mod', minimum_version='2.0', defer_import=True
)
_and = avail0 & avail1
@@ -209,7 +213,7 @@ def test_and_or(self):
_and_or = avail0 & avail1 | avail2
self.assertTrue(_and_or)
- # Verify operator prescedence
+ # Verify operator precedence
_or_and = avail0 | avail2 & avail2
self.assertTrue(_or_and)
_or_and = (avail0 | avail2) & avail2
@@ -233,11 +237,11 @@ def test_callbacks(self):
def _record_avail(module, avail):
ans.append(avail)
- mod0, avail0 = attempt_import('ply', defer_check=True, callback=_record_avail)
+ mod0, avail0 = attempt_import('ply', defer_import=True, callback=_record_avail)
mod1, avail1 = attempt_import(
'pyomo.common.tests.dep_mod',
minimum_version='2.0',
- defer_check=True,
+ defer_import=True,
callback=_record_avail,
)
@@ -247,10 +251,74 @@ def _record_avail(module, avail):
self.assertFalse(avail1)
self.assertEqual(ans, [True, False])
+ def test_callback_on_import(self):
+ sys.modules.pop('pyomo.common.tests.mod', None)
+ ans = []
+
+ class ImpFinder(object):
+ # This is an "imp" module-style finder (deprecated in Python
+ # 3.4 and removed in Python 3.12, but Google Collab still
+ # defines finders like this)
+ match = ''
+
+ def find_module(self, fullname, path=None):
+ if fullname != self.match:
+ ans.append('pass')
+ return None
+ ans.append('load')
+ spec = PathFinder().find_spec(fullname, path)
+ return spec.loader
+
+ def load_module(self, name):
+ pass
+
+ def _callback(module, avail):
+ ans.append(len(ans))
+
+ attempt_import('pyomo.common.tests.mod', defer_import=True, callback=_callback)
+ self.assertEqual(ans, [])
+ import pyomo.common.tests.mod as m
+
+ self.assertEqual(ans, [0])
+ self.assertEqual(m.Foo.data, 42)
+
+ sys.modules.pop('pyomo.common.tests.mod', None)
+ del m
+ attempt_import('pyomo.common.tests.mod', defer_import=True, callback=_callback)
+
+ try:
+ # Test deferring to an imp-style finder that does not match
+ # the target module name
+ _finder = ImpFinder()
+ sys.meta_path.insert(
+ sys.meta_path.index(_DeferredImportCallbackFinder) + 1, _finder
+ )
+ import pyomo.common.tests.mod as m
+
+ self.assertEqual(ans, [0, 'pass', 2])
+ self.assertEqual(m.Foo.data, 42)
+
+ sys.modules.pop('pyomo.common.tests.mod', None)
+ del m
+ attempt_import(
+ 'pyomo.common.tests.mod', defer_import=True, callback=_callback
+ )
+
+ # Test deferring to an imp-style finder that DOES match the
+ # target module name
+ _finder.match = 'pyomo.common.tests.mod'
+
+ import pyomo.common.tests.mod as m
+
+ self.assertEqual(ans, [0, 'pass', 2, 'load', 4])
+ self.assertEqual(m.Foo.data, 42)
+ finally:
+ sys.meta_path.remove(_finder)
+
def test_import_exceptions(self):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
only_catch_importerror=True,
)
with self.assertRaisesRegex(ValueError, "cannot import module"):
@@ -260,7 +328,7 @@ def test_import_exceptions(self):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
only_catch_importerror=False,
)
self.assertFalse(avail)
@@ -268,7 +336,7 @@ def test_import_exceptions(self):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
catch_exceptions=(ImportError, ValueError),
)
self.assertFalse(avail)
@@ -280,7 +348,7 @@ def test_import_exceptions(self):
):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
only_catch_importerror=True,
catch_exceptions=(ImportError,),
)
@@ -288,7 +356,7 @@ def test_import_exceptions(self):
def test_generate_warning(self):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
only_catch_importerror=False,
)
@@ -324,7 +392,7 @@ def test_generate_warning(self):
def test_log_warning(self):
mod, avail = attempt_import(
'pyomo.common.tests.dep_mod_except',
- defer_check=True,
+ defer_import=True,
only_catch_importerror=False,
)
log = StringIO()
@@ -366,9 +434,9 @@ def test_importer(self):
def _importer():
attempted_import.append(True)
- return attempt_import('pyomo.common.tests.dep_mod', defer_check=False)[0]
+ return attempt_import('pyomo.common.tests.dep_mod', defer_import=False)[0]
- mod, avail = attempt_import('foo', importer=_importer, defer_check=True)
+ mod, avail = attempt_import('foo', importer=_importer, defer_import=True)
self.assertEqual(attempted_import, [])
self.assertIsInstance(mod, DeferredImportModule)
@@ -401,17 +469,17 @@ def test_deferred_submodules(self):
self.assertTrue(inspect.ismodule(deps.dm))
with self.assertRaisesRegex(
- ValueError, "deferred_submodules is only valid if defer_check==True"
+ ValueError, "deferred_submodules is only valid if defer_import==True"
):
mod, mod_available = attempt_import(
'nonexisting.module',
- defer_check=False,
+ defer_import=False,
deferred_submodules={'submod': None},
)
mod, mod_available = attempt_import(
'nonexisting.module',
- defer_check=True,
+ defer_import=True,
deferred_submodules={'submod.subsubmod': None},
)
self.assertIs(type(mod), DeferredImportModule)
@@ -427,7 +495,7 @@ def test_UnavailableClass(self):
module_obj, module_available = attempt_import(
'__there_is_no_module_named_this__',
'Testing import of a non-existent module',
- defer_check=False,
+ defer_import=False,
)
class A_Class(UnavailableClass(module_obj)):
@@ -450,6 +518,12 @@ class A_Class(UnavailableClass(module_obj)):
):
A_Class.method()
+ @unittest.pytest.mark.mpi
+ def test_mpi4py_available(self):
+ from mpi4py import MPI
+
+ self.assertTrue(bool(mpi4py_available))
+
if __name__ == '__main__':
unittest.main()
diff --git a/pyomo/common/tests/test_deprecated.py b/pyomo/common/tests/test_deprecated.py
index 377e229c775..a44f9058a5e 100644
--- a/pyomo/common/tests/test_deprecated.py
+++ b/pyomo/common/tests/test_deprecated.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,24 +10,29 @@
# ___________________________________________________________________________
#
"""Testing for deprecated function."""
+import logging
import sys
+from importlib import import_module
+from importlib.machinery import ModuleSpec
+from io import StringIO
+
+import pyomo.common
import pyomo.common.unittest as unittest
from pyomo.common import DeveloperError
from pyomo.common.deprecation import (
deprecated,
deprecation_warning,
+ moved_module,
relocated_module_attribute,
+ MovedModuleFinder,
+ MovedModuleLoader,
RenamedClass,
_import_object,
)
from pyomo.common.log import LoggingIntercept
-from io import StringIO
-
-import logging
-
logger = logging.getLogger('local')
@@ -529,7 +534,10 @@ class DeprecatedClassSubclass(DeprecatedClass):
out = StringIO()
with LoggingIntercept(out):
- class DeprecatedClassSubSubclass(DeprecatedClassSubclass):
+ class otherClass:
+ pass
+
+ class DeprecatedClassSubSubclass(DeprecatedClassSubclass, otherClass):
attr = 'DeprecatedClassSubSubclass'
self.assertEqual(out.getvalue(), "")
@@ -657,5 +665,122 @@ class DeprecatedClass(metaclass=RenamedClass):
__renamed__new_class__ = NewClass
+class TestMoved(unittest.TestCase):
+ def test_finder(self):
+ mod_name = 'pyomo.common.deprecation_tester'
+ finder = MovedModuleFinder()
+ self.assertNotIn(mod_name, finder.mapping)
+ self.assertIsNone(finder.find_spec(mod_name, pyomo.common.__path__))
+
+ moved_module(mod_name, __name__, version='1.2.3')
+ try:
+ self.assertIn(mod_name, finder.mapping)
+ spec = finder.find_spec(mod_name, pyomo.common.__path__)
+ self.assertIs(type(spec), ModuleSpec)
+ self.assertEqual(spec.name, mod_name)
+ self.assertIs(type(spec.loader), MovedModuleLoader)
+ self.assertEqual(spec.origin, __file__)
+ finally:
+ del finder.mapping[mod_name]
+
+ def test_declaration(self):
+ try:
+ _old = 'pyomo.common.tests.old_moved'
+ _new = 'pyomo.common.tests.moved'
+ # 1st registration is OK
+ N = len(MovedModuleFinder.mapping)
+ self.assertNotIn(_old, MovedModuleFinder.mapping)
+ moved_module(_old, _new, version='1.2')
+ self.assertIn(_old, MovedModuleFinder.mapping)
+ self.assertEqual(N + 1, len(MovedModuleFinder.mapping))
+ # duplicate registration is OK
+ moved_module(_old, _new, version='1.2')
+ self.assertIn(_old, MovedModuleFinder.mapping)
+ self.assertEqual(N + 1, len(MovedModuleFinder.mapping))
+ _conflict = 'pyomo.something.else'
+ with self.assertRaisesRegex(
+ RuntimeError,
+ "(?s)Duplicate module alias declaration.\n"
+ f"\toriginal: {_old} -> {_new}\n"
+ f"\tconflict: {_old} -> {_conflict}\n",
+ ):
+ moved_module(_old, _conflict, version='1.2')
+ self.assertIn(_old, MovedModuleFinder.mapping)
+ self.assertEqual(N + 1, len(MovedModuleFinder.mapping))
+ finally:
+ del MovedModuleFinder.mapping[_old]
+
+ def test_loader(self):
+ mod_name = 'pyomo.common.deprecation_tester'
+ try:
+ moved_module(mod_name, __name__, version='1.2.3')
+ with LoggingIntercept() as LOG:
+ import pyomo.common.deprecation_tester
+ self.assertRegex(
+ LOG.getvalue().replace('\n', ' ').strip(),
+ "DEPRECATED: The 'pyomo.common.deprecation_tester' module has been "
+ "moved to 'pyomo.common.tests.test_deprecated'. Please update your "
+ r"import. \(deprecated in 1.2.3\) \(called from [^)]+\)",
+ )
+ self.assertIs(pyomo.common.deprecation_tester.TestMoved, TestMoved)
+ finally:
+ del MovedModuleFinder.mapping[mod_name]
+
+ try:
+ moved_module(mod_name, __name__, msg=None, version='1.2.3')
+ with LoggingIntercept() as LOG:
+ import pyomo.common.deprecation_tester
+ self.assertEqual(LOG.getvalue(), "")
+ self.assertIs(pyomo.common.deprecation_tester.TestMoved, TestMoved)
+ finally:
+ del MovedModuleFinder.mapping[mod_name]
+
+ try:
+ moved_module(
+ 'pyomo.common.tests.old_moved',
+ 'pyomo.common.tests.moved',
+ version='1.2',
+ )
+ self.assertNotIn('pyomo.common.tests.moved', sys.modules)
+ self.assertNotIn('pyomo.common.tests.old_moved', sys.modules)
+ with LoggingIntercept() as LOG:
+ import pyomo.common.tests.old_moved
+ self.assertRegex(
+ LOG.getvalue().replace('\n', ' ').strip(),
+ "DEPRECATED: The 'pyomo.common.tests.old_moved' module has been "
+ "moved to 'pyomo.common.tests.moved'. Please update your "
+ r"import. \(deprecated in 1.2\) \(called from [^)]+\)",
+ )
+ self.assertIn('pyomo.common.tests.moved', sys.modules)
+ self.assertIn('pyomo.common.tests.old_moved', sys.modules)
+ self.assertIs(
+ sys.modules['pyomo.common.tests.moved'],
+ sys.modules['pyomo.common.tests.old_moved'],
+ )
+ finally:
+ del MovedModuleFinder.mapping['pyomo.common.tests.old_moved']
+ del sys.modules['pyomo.common.tests.old_moved']
+ del sys.modules['pyomo.common.tests.moved']
+
+ def test_archive_importable(self):
+ import pyomo.environ
+
+ # Check that all modules in the _archive directory are importable.
+ for old_name, info in MovedModuleFinder.mapping.items():
+ if '._archive.' in info.new_name:
+ with LoggingIntercept() as LOG:
+ m = import_module(info.old_name)
+ self.assertIn('DEPRECATED', LOG.getvalue())
+ # We expect every module in _archive to be deprecated
+ # (and to state that in the module docstring):
+ self.assertIn('deprecated', m.__doc__)
+ self.assertEqual(m.__name__, info.new_name)
+ # Remove these modules from sys.modules (some other
+ # modules have tests for deprecation paths that rely on
+ # these modules not having already been imported)
+ del sys.modules[info.old_name]
+ del sys.modules[info.new_name]
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/pyomo/common/tests/test_download.py b/pyomo/common/tests/test_download.py
index 87108be1c59..05287c80cfb 100644
--- a/pyomo/common/tests/test_download.py
+++ b/pyomo/common/tests/test_download.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,19 +9,22 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
+import io
import os
import platform
import re
import shutil
-import tempfile
import subprocess
+import tarfile
+import tempfile
import pyomo.common.unittest as unittest
import pyomo.common.envvar as envvar
from pyomo.common import DeveloperError
-from pyomo.common.fileutils import this_file
+from pyomo.common.fileutils import this_file, Executable
from pyomo.common.download import FileDownloader, distro_available
+from pyomo.common.log import LoggingIntercept
from pyomo.common.tee import capture_output
@@ -170,7 +173,8 @@ def test_get_os_version(self):
self.assertTrue(v.replace('.', '').startswith(dist_ver))
if (
- subprocess.run(
+ Executable('lsb_release').available()
+ and subprocess.run(
['lsb_release'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
@@ -203,7 +207,7 @@ def test_get_os_version(self):
self.assertEqual(_os, 'win')
self.assertEqual(_norm, _os + ''.join(_ver.split('.')[:2]))
else:
- self.assertEqual(ans, '')
+ self.assertEqual(_os, '')
self.assertEqual((_os, _ver), FileDownloader._os_version)
# Exercise the fetch from CACHE
@@ -242,7 +246,7 @@ def test_get_files_requires_set_destination(self):
):
f.get_gzipped_binary_file('bogus')
- def test_get_test_binary_file(self):
+ def test_get_text_binary_file(self):
tmpdir = tempfile.mkdtemp()
try:
f = FileDownloader()
@@ -263,3 +267,66 @@ def test_get_test_binary_file(self):
self.assertEqual(os.path.getsize(target), len(os.linesep))
finally:
shutil.rmtree(tmpdir)
+
+ def test_get_tar_archive(self):
+ tmpdir = tempfile.mkdtemp()
+ try:
+ f = FileDownloader()
+
+ # Mock retrieve_url so network connections are not necessary
+ buf = io.BytesIO()
+ with tarfile.open(mode="w:gz", fileobj=buf) as TAR:
+ info = tarfile.TarInfo('b/lnk')
+ info.size = 0
+ info.type = tarfile.SYMTYPE
+ info.linkname = envvar.PYOMO_CONFIG_DIR
+ TAR.addfile(info)
+ for fname in ('a', 'b/c', 'b/d', '/root', 'b/lnk/test'):
+ info = tarfile.TarInfo(fname)
+ info.size = 0
+ info.type = tarfile.REGTYPE
+ info.mode = 0o644
+ info.mtime = info.uid = info.gid = 0
+ info.uname = info.gname = 'root'
+ TAR.addfile(info)
+ f.retrieve_url = lambda url: buf.getvalue()
+
+ with self.assertRaisesRegex(
+ DeveloperError,
+ r"(?s)target file name has not been initialized "
+ r"with set_destination_filename".replace(' ', r'\s+'),
+ ):
+ f.get_tar_archive(None, 1)
+
+ _tmp = os.path.join(tmpdir, 'a_file')
+ with open(_tmp, 'w'):
+ pass
+ f.set_destination_filename(_tmp)
+ with self.assertRaisesRegex(
+ RuntimeError,
+ r"Target directory \(.*a_file\) exists, but is not a directory",
+ ):
+ f.get_tar_archive(None, 1)
+
+ f.set_destination_filename(tmpdir)
+ with LoggingIntercept() as LOG:
+ f.get_tar_archive(None, 1)
+
+ self.assertEqual(
+ LOG.getvalue().strip(),
+ """
+Skipping file (a) in tar archive due to dirOffset.
+malformed or potentially insecure filename (/root). Skipping file.
+potentially insecure filename (lnk/test) resolves outside target directory. Skipping file.
+""".strip(),
+ )
+ for f in ('c', 'd'):
+ fname = os.path.join(tmpdir, f)
+ self.assertTrue(os.path.exists(fname))
+ self.assertTrue(os.path.isfile(fname))
+ for f in ('lnk',):
+ fname = os.path.join(tmpdir, f)
+ self.assertTrue(os.path.exists(fname))
+ self.assertTrue(os.path.islink(fname))
+ finally:
+ shutil.rmtree(tmpdir)
diff --git a/pyomo/common/tests/test_enums.py b/pyomo/common/tests/test_enums.py
new file mode 100644
index 00000000000..b5264a50825
--- /dev/null
+++ b/pyomo/common/tests/test_enums.py
@@ -0,0 +1,97 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import enum
+
+import pyomo.common.unittest as unittest
+
+from pyomo.common.enums import ExtendedEnumType, ObjectiveSense
+
+
+class ProblemSense(enum.IntEnum, metaclass=ExtendedEnumType):
+ __base_enum__ = ObjectiveSense
+
+ unknown = 0
+
+
+class TestExtendedEnumType(unittest.TestCase):
+ def test_members(self):
+ self.assertEqual(
+ list(ProblemSense),
+ [ProblemSense.unknown, ObjectiveSense.minimize, ObjectiveSense.maximize],
+ )
+
+ def test_isinstance(self):
+ self.assertIsInstance(ProblemSense.unknown, ProblemSense)
+ self.assertIsInstance(ProblemSense.minimize, ProblemSense)
+ self.assertIsInstance(ProblemSense.maximize, ProblemSense)
+
+ self.assertTrue(ProblemSense.__instancecheck__(ProblemSense.unknown))
+ self.assertTrue(ProblemSense.__instancecheck__(ProblemSense.minimize))
+ self.assertTrue(ProblemSense.__instancecheck__(ProblemSense.maximize))
+
+ def test_getattr(self):
+ self.assertIs(ProblemSense.unknown, ProblemSense.unknown)
+ self.assertIs(ProblemSense.minimize, ObjectiveSense.minimize)
+ self.assertIs(ProblemSense.maximize, ObjectiveSense.maximize)
+
+ def test_hasattr(self):
+ self.assertTrue(hasattr(ProblemSense, 'unknown'))
+ self.assertTrue(hasattr(ProblemSense, 'minimize'))
+ self.assertTrue(hasattr(ProblemSense, 'maximize'))
+
+ def test_call(self):
+ self.assertIs(ProblemSense(0), ProblemSense.unknown)
+ self.assertIs(ProblemSense(1), ObjectiveSense.minimize)
+ self.assertIs(ProblemSense(-1), ObjectiveSense.maximize)
+
+ self.assertIs(ProblemSense('unknown'), ProblemSense.unknown)
+ self.assertIs(ProblemSense('minimize'), ObjectiveSense.minimize)
+ self.assertIs(ProblemSense('maximize'), ObjectiveSense.maximize)
+
+ with self.assertRaisesRegex(ValueError, "'foo' is not a valid ProblemSense"):
+ ProblemSense('foo')
+ with self.assertRaisesRegex(ValueError, "2 is not a valid ProblemSense"):
+ ProblemSense(2)
+
+ def test_contains(self):
+ self.assertIn(ProblemSense.unknown, ProblemSense)
+ self.assertIn(ProblemSense.minimize, ProblemSense)
+ self.assertIn(ProblemSense.maximize, ProblemSense)
+
+ self.assertNotIn(ProblemSense.unknown, ObjectiveSense)
+ self.assertIn(ProblemSense.minimize, ObjectiveSense)
+ self.assertIn(ProblemSense.maximize, ObjectiveSense)
+
+
+class TestObjectiveSense(unittest.TestCase):
+ def test_members(self):
+ self.assertEqual(
+ list(ObjectiveSense), [ObjectiveSense.minimize, ObjectiveSense.maximize]
+ )
+
+ def test_hasattr(self):
+ self.assertTrue(hasattr(ProblemSense, 'minimize'))
+ self.assertTrue(hasattr(ProblemSense, 'maximize'))
+
+ def test_call(self):
+ self.assertIs(ObjectiveSense(1), ObjectiveSense.minimize)
+ self.assertIs(ObjectiveSense(-1), ObjectiveSense.maximize)
+
+ self.assertIs(ObjectiveSense('minimize'), ObjectiveSense.minimize)
+ self.assertIs(ObjectiveSense('maximize'), ObjectiveSense.maximize)
+
+ with self.assertRaisesRegex(ValueError, "'foo' is not a valid ObjectiveSense"):
+ ObjectiveSense('foo')
+
+ def test_str(self):
+ self.assertEqual(str(ObjectiveSense.minimize), 'minimize')
+ self.assertEqual(str(ObjectiveSense.maximize), 'maximize')
diff --git a/pyomo/common/tests/test_env.py b/pyomo/common/tests/test_env.py
index 93802fc40bb..98012c4dac3 100644
--- a/pyomo/common/tests/test_env.py
+++ b/pyomo/common/tests/test_env.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_errors.py b/pyomo/common/tests/test_errors.py
index 67a200e84e3..07ac2d85c05 100644
--- a/pyomo/common/tests/test_errors.py
+++ b/pyomo/common/tests/test_errors.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_fileutils.py b/pyomo/common/tests/test_fileutils.py
index 068360b55cb..ddbbda30b7d 100644
--- a/pyomo/common/tests/test_fileutils.py
+++ b/pyomo/common/tests/test_fileutils.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_flags.py b/pyomo/common/tests/test_flags.py
new file mode 100644
index 00000000000..8c49b6c3da6
--- /dev/null
+++ b/pyomo/common/tests/test_flags.py
@@ -0,0 +1,49 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import sys
+
+import pyomo.common.unittest as unittest
+
+from pyomo.common.flags import NOTSET, in_testing_environment, building_documentation
+
+
+class TestFlags(unittest.TestCase):
+
+ def test_NOTSET(self):
+ self.assertTrue(in_testing_environment())
+ self.assertFalse(building_documentation())
+
+ self.assertEqual(str(NOTSET), 'NOTSET')
+ self.assertNotIn('sphinx', sys.modules)
+ self.assertEqual(repr(NOTSET), 'pyomo.common.flags.NOTSET')
+ self.assertIsNone(in_testing_environment.state)
+
+ try:
+ sys.modules['sphinx'] = sys.modules[__name__]
+ self.assertTrue(in_testing_environment())
+ self.assertTrue(building_documentation())
+ self.assertEqual(repr(NOTSET), 'NOTSET')
+
+ in_testing_environment(False)
+ self.assertFalse(in_testing_environment())
+ self.assertTrue(building_documentation())
+ self.assertEqual(repr(NOTSET), 'NOTSET')
+ finally:
+ del sys.modules['sphinx']
+ in_testing_environment(None)
+ self.assertIsNone(in_testing_environment.state)
+
+ def test_singleton(self):
+ # This tests that the type is a "singleton", and that any
+ # attempts to construct an instance will return the class
+ self.assertIs(NOTSET(), NOTSET)
+ self.assertIs(NOTSET(), NOTSET())
diff --git a/pyomo/common/tests/test_formatting.py b/pyomo/common/tests/test_formatting.py
index 29db26676ab..0798a80589c 100644
--- a/pyomo/common/tests/test_formatting.py
+++ b/pyomo/common/tests/test_formatting.py
@@ -2,7 +2,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_gc.py b/pyomo/common/tests/test_gc.py
index 176010b8d0d..a9a0346706c 100644
--- a/pyomo/common/tests/test_gc.py
+++ b/pyomo/common/tests/test_gc.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_log.py b/pyomo/common/tests/test_log.py
index 64691c0015a..43e85af1308 100644
--- a/pyomo/common/tests/test_log.py
+++ b/pyomo/common/tests/test_log.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -511,7 +511,6 @@ def test_verbatim(self):
"\n"
" quote block\n"
)
- self.maxDiff = None
self.assertEqual(self.stream.getvalue(), ans)
@@ -527,6 +526,12 @@ def test_log_stream(self):
ls.write("line 1\nline 2\n")
self.assertEqual(OUT.getvalue(), "INFO: line 1\nINFO: line 2\n")
+ with LI as OUT:
+ # empty writes do not generate log records
+ ls.write("")
+ ls.flush()
+ self.assertEqual(OUT.getvalue(), "")
+
with LI as OUT:
ls.write("line 1\nline 2")
self.assertEqual(OUT.getvalue(), "INFO: line 1\n")
@@ -545,6 +550,18 @@ def test_log_stream(self):
# Exiting the context manager flushes the LogStream
self.assertEqual(OUT.getvalue(), "INFO: line 1\nINFO: line 2\n")
+ def test_loggerAdapter(self):
+ class Adapter(logging.LoggerAdapter):
+ def process(self, msg, kwargs):
+ return '[%s] %s' % (self.extra['foo'], msg), kwargs
+
+ adapter = Adapter(logging.getLogger('pyomo'), {"foo": 42})
+ ls = LogStream(logging.INFO, adapter)
+ LI = LoggingIntercept(level=logging.INFO, formatter=pyomo_formatter)
+ with LI as OUT:
+ ls.write("hello, world\n")
+ self.assertEqual(OUT.getvalue(), "INFO: [42] hello, world\n")
+
class TestPreformatted(unittest.TestCase):
def test_preformatted_api(self):
@@ -559,3 +576,46 @@ def test_preformatted_api(self):
self.assertIs(msg.msg, ref)
self.assertEqual(str(msg), '2')
self.assertEqual(repr(msg), "Preformatted(2)")
+
+
+class TestLoggingIntercept(unittest.TestCase):
+ def test_init(self):
+ li = LoggingIntercept()
+ self.assertEqual(li.module, 'root')
+
+ li = LoggingIntercept(module='pyomo.core')
+ self.assertEqual(li.module, 'pyomo.core')
+
+ li = LoggingIntercept(logger=logger)
+ self.assertEqual(li.module, 'pyomo.common.log.testing')
+
+ with self.assertRaisesRegex(
+ ValueError, "LoggingIntercept: only one of 'module' and 'logger' is allowed"
+ ):
+ li = LoggingIntercept(module='pyomo', logger=logger)
+
+ def test_propagate(self):
+ self.assertEqual(logger.propagate, True)
+ with LoggingIntercept(logger=logger):
+ self.assertEqual(logger.propagate, False)
+ self.assertEqual(logger.propagate, True)
+
+ def test_propagate(self):
+ self.assertEqual(logger.level, 30)
+ try:
+ with LoggingIntercept(logger=logger, level=None):
+ self.assertEqual(logger.level, 30)
+ self.assertEqual(logger.level, 30)
+ with LoggingIntercept(logger=logger, level=40):
+ self.assertEqual(logger.level, 40)
+ self.assertEqual(logger.level, 30)
+
+ logger.setLevel(40)
+ with LoggingIntercept(logger=logger, level=None):
+ self.assertEqual(logger.level, 40)
+ self.assertEqual(logger.level, 40)
+ with LoggingIntercept(logger=logger, level=30):
+ self.assertEqual(logger.level, 30)
+ self.assertEqual(logger.level, 40)
+ finally:
+ logger.setLevel(30)
diff --git a/pyomo/common/tests/test_modeling.py b/pyomo/common/tests/test_modeling.py
index 97bef76c2c0..30d50899c49 100644
--- a/pyomo/common/tests/test_modeling.py
+++ b/pyomo/common/tests/test_modeling.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,12 +9,10 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-import sys
-
import pyomo.common.unittest as unittest
from pyomo.environ import ConcreteModel, Var
-from pyomo.common.modeling import unique_component_name, NOTSET
+from pyomo.common.modeling import unique_component_name
class TestModeling(unittest.TestCase):
@@ -48,8 +46,3 @@ def test_unique_component_name(self):
self.assertEqual(name[:2], 'y_')
self.assertIn(name[2], '0123456789')
self.assertIn(name[3], '0123456789')
-
- def test_NOTSET(self):
- self.assertEqual(str(NOTSET), 'NOTSET')
- assert 'sphinx' not in sys.modules
- self.assertEqual(repr(NOTSET), 'pyomo.common.modeling.NOTSET')
diff --git a/pyomo/common/tests/test_multithread.py b/pyomo/common/tests/test_multithread.py
index fa1a46fa25f..a8a1c67f07d 100644
--- a/pyomo/common/tests/test_multithread.py
+++ b/pyomo/common/tests/test_multithread.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_numeric_types.py b/pyomo/common/tests/test_numeric_types.py
new file mode 100644
index 00000000000..2a751f6569a
--- /dev/null
+++ b/pyomo/common/tests/test_numeric_types.py
@@ -0,0 +1,219 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import pyomo.common.numeric_types as nt
+import pyomo.common.unittest as unittest
+
+from pyomo.common.dependencies import numpy, numpy_available
+from pyomo.core.expr import LinearExpression
+from pyomo.environ import Var
+
+_type_sets = (
+ 'native_types',
+ 'native_numeric_types',
+ 'native_logical_types',
+ 'native_integer_types',
+ 'native_complex_types',
+)
+
+
+class TestNativeTypes(unittest.TestCase):
+ def setUp(self):
+ bool(numpy_available)
+ for s in _type_sets:
+ setattr(self, s, set(getattr(nt, s)))
+ getattr(nt, s).clear()
+
+ def tearDown(self):
+ for s in _type_sets:
+ getattr(nt, s).clear()
+ getattr(nt, s).update(getattr(self, s))
+
+ def test_check_if_native_type(self):
+ self.assertEqual(nt.native_types, set())
+ self.assertEqual(nt.native_logical_types, set())
+ self.assertEqual(nt.native_numeric_types, set())
+ self.assertEqual(nt.native_integer_types, set())
+ self.assertEqual(nt.native_complex_types, set())
+
+ self.assertTrue(nt.check_if_native_type("a"))
+ self.assertIn(str, nt.native_types)
+ self.assertNotIn(str, nt.native_logical_types)
+ self.assertNotIn(str, nt.native_numeric_types)
+ self.assertNotIn(str, nt.native_integer_types)
+ self.assertNotIn(str, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_native_type(1))
+ self.assertIn(int, nt.native_types)
+ self.assertNotIn(int, nt.native_logical_types)
+ self.assertIn(int, nt.native_numeric_types)
+ self.assertIn(int, nt.native_integer_types)
+ self.assertNotIn(int, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_native_type(1.5))
+ self.assertIn(float, nt.native_types)
+ self.assertNotIn(float, nt.native_logical_types)
+ self.assertIn(float, nt.native_numeric_types)
+ self.assertNotIn(float, nt.native_integer_types)
+ self.assertNotIn(float, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_native_type(True))
+ self.assertIn(bool, nt.native_types)
+ self.assertIn(bool, nt.native_logical_types)
+ self.assertNotIn(bool, nt.native_numeric_types)
+ self.assertNotIn(bool, nt.native_integer_types)
+ self.assertNotIn(bool, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_native_type(slice(None, None, None)))
+ self.assertNotIn(slice, nt.native_types)
+ self.assertNotIn(slice, nt.native_logical_types)
+ self.assertNotIn(slice, nt.native_numeric_types)
+ self.assertNotIn(slice, nt.native_integer_types)
+ self.assertNotIn(slice, nt.native_complex_types)
+
+ def test_check_if_logical_type(self):
+ self.assertEqual(nt.native_types, set())
+ self.assertEqual(nt.native_logical_types, set())
+ self.assertEqual(nt.native_numeric_types, set())
+ self.assertEqual(nt.native_integer_types, set())
+ self.assertEqual(nt.native_complex_types, set())
+
+ self.assertFalse(nt.check_if_logical_type("a"))
+ self.assertNotIn(str, nt.native_types)
+ self.assertNotIn(str, nt.native_logical_types)
+ self.assertNotIn(str, nt.native_numeric_types)
+ self.assertNotIn(str, nt.native_integer_types)
+ self.assertNotIn(str, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_logical_type("a"))
+
+ self.assertTrue(nt.check_if_logical_type(True))
+ self.assertIn(bool, nt.native_types)
+ self.assertIn(bool, nt.native_logical_types)
+ self.assertNotIn(bool, nt.native_numeric_types)
+ self.assertNotIn(bool, nt.native_integer_types)
+ self.assertNotIn(bool, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_logical_type(True))
+
+ self.assertFalse(nt.check_if_logical_type(1))
+ self.assertNotIn(int, nt.native_types)
+ self.assertNotIn(int, nt.native_logical_types)
+ self.assertNotIn(int, nt.native_numeric_types)
+ self.assertNotIn(int, nt.native_integer_types)
+ self.assertNotIn(int, nt.native_complex_types)
+
+ if numpy_available:
+ self.assertTrue(nt.check_if_logical_type(numpy.bool_(1)))
+ self.assertIn(numpy.bool_, nt.native_types)
+ self.assertIn(numpy.bool_, nt.native_logical_types)
+ self.assertNotIn(numpy.bool_, nt.native_numeric_types)
+ self.assertNotIn(numpy.bool_, nt.native_integer_types)
+ self.assertNotIn(numpy.bool_, nt.native_complex_types)
+
+ def test_check_if_numeric_type(self):
+ self.assertEqual(nt.native_types, set())
+ self.assertEqual(nt.native_logical_types, set())
+ self.assertEqual(nt.native_numeric_types, set())
+ self.assertEqual(nt.native_integer_types, set())
+ self.assertEqual(nt.native_complex_types, set())
+
+ self.assertFalse(nt.check_if_numeric_type("a"))
+ self.assertFalse(nt.check_if_numeric_type("a"))
+ self.assertNotIn(str, nt.native_types)
+ self.assertNotIn(str, nt.native_logical_types)
+ self.assertNotIn(str, nt.native_numeric_types)
+ self.assertNotIn(str, nt.native_integer_types)
+ self.assertNotIn(str, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_numeric_type(True))
+ self.assertFalse(nt.check_if_numeric_type(True))
+ self.assertNotIn(bool, nt.native_types)
+ self.assertNotIn(bool, nt.native_logical_types)
+ self.assertNotIn(bool, nt.native_numeric_types)
+ self.assertNotIn(bool, nt.native_integer_types)
+ self.assertNotIn(bool, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_numeric_type(1))
+ self.assertTrue(nt.check_if_numeric_type(1))
+ self.assertIn(int, nt.native_types)
+ self.assertNotIn(int, nt.native_logical_types)
+ self.assertIn(int, nt.native_numeric_types)
+ self.assertIn(int, nt.native_integer_types)
+ self.assertNotIn(int, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_numeric_type(1.5))
+ self.assertTrue(nt.check_if_numeric_type(1.5))
+ self.assertIn(float, nt.native_types)
+ self.assertNotIn(float, nt.native_logical_types)
+ self.assertIn(float, nt.native_numeric_types)
+ self.assertNotIn(float, nt.native_integer_types)
+ self.assertNotIn(float, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_numeric_type(1j))
+ self.assertIn(complex, nt.native_types)
+ self.assertNotIn(complex, nt.native_logical_types)
+ self.assertNotIn(complex, nt.native_numeric_types)
+ self.assertNotIn(complex, nt.native_integer_types)
+ self.assertIn(complex, nt.native_complex_types)
+
+ v = Var()
+ v.construct()
+ self.assertFalse(nt.check_if_numeric_type(v))
+ self.assertNotIn(type(v), nt.native_types)
+ self.assertNotIn(type(v), nt.native_logical_types)
+ self.assertNotIn(type(v), nt.native_numeric_types)
+ self.assertNotIn(type(v), nt.native_integer_types)
+ self.assertNotIn(type(v), nt.native_complex_types)
+
+ e = LinearExpression([1])
+ self.assertFalse(nt.check_if_numeric_type(e))
+ self.assertNotIn(type(e), nt.native_types)
+ self.assertNotIn(type(e), nt.native_logical_types)
+ self.assertNotIn(type(e), nt.native_numeric_types)
+ self.assertNotIn(type(e), nt.native_integer_types)
+ self.assertNotIn(type(e), nt.native_complex_types)
+
+ if numpy_available:
+ self.assertFalse(nt.check_if_numeric_type(numpy.bool_(1)))
+ self.assertNotIn(numpy.bool_, nt.native_types)
+ self.assertNotIn(numpy.bool_, nt.native_logical_types)
+ self.assertNotIn(numpy.bool_, nt.native_numeric_types)
+ self.assertNotIn(numpy.bool_, nt.native_integer_types)
+ self.assertNotIn(numpy.bool_, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_numeric_type(numpy.array([1])))
+ self.assertNotIn(numpy.ndarray, nt.native_types)
+ self.assertNotIn(numpy.ndarray, nt.native_logical_types)
+ self.assertNotIn(numpy.ndarray, nt.native_numeric_types)
+ self.assertNotIn(numpy.ndarray, nt.native_integer_types)
+ self.assertNotIn(numpy.ndarray, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_numeric_type(numpy.float64(1)))
+ self.assertIn(numpy.float64, nt.native_types)
+ self.assertNotIn(numpy.float64, nt.native_logical_types)
+ self.assertIn(numpy.float64, nt.native_numeric_types)
+ self.assertNotIn(numpy.float64, nt.native_integer_types)
+ self.assertNotIn(numpy.float64, nt.native_complex_types)
+
+ self.assertTrue(nt.check_if_numeric_type(numpy.int64(1)))
+ self.assertIn(numpy.int64, nt.native_types)
+ self.assertNotIn(numpy.int64, nt.native_logical_types)
+ self.assertIn(numpy.int64, nt.native_numeric_types)
+ self.assertIn(numpy.int64, nt.native_integer_types)
+ self.assertNotIn(numpy.int64, nt.native_complex_types)
+
+ self.assertFalse(nt.check_if_numeric_type(numpy.complex128(1)))
+ self.assertIn(numpy.complex128, nt.native_types)
+ self.assertNotIn(numpy.complex128, nt.native_logical_types)
+ self.assertNotIn(numpy.complex128, nt.native_numeric_types)
+ self.assertNotIn(numpy.complex128, nt.native_integer_types)
+ self.assertIn(numpy.complex128, nt.native_complex_types)
diff --git a/pyomo/common/tests/test_orderedset.py b/pyomo/common/tests/test_orderedset.py
index 8f944e66bd7..b1aacbd049b 100644
--- a/pyomo/common/tests/test_orderedset.py
+++ b/pyomo/common/tests/test_orderedset.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_plugin.py b/pyomo/common/tests/test_plugin.py
index 54431334d5b..76044e50610 100644
--- a/pyomo/common/tests/test_plugin.py
+++ b/pyomo/common/tests/test_plugin.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_sorting.py b/pyomo/common/tests/test_sorting.py
index 7fbefda6a19..5bd3c3399d8 100644
--- a/pyomo/common/tests/test_sorting.py
+++ b/pyomo/common/tests/test_sorting.py
@@ -2,7 +2,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_tee.py b/pyomo/common/tests/test_tee.py
index a5c6ee894b2..2316a7dbc3d 100644
--- a/pyomo/common/tests/test_tee.py
+++ b/pyomo/common/tests/test_tee.py
@@ -2,7 +2,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -10,19 +10,79 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
+import gc
+import itertools
+import logging
import os
+import platform
import time
import sys
from io import StringIO, BytesIO
-from pyomo.common.log import LoggingIntercept
+from pyomo.common.log import LoggingIntercept, LogStream
import pyomo.common.unittest as unittest
from pyomo.common.tempfiles import TempfileManager
import pyomo.common.tee as tee
+class timestamper:
+ """A 'TextIO'-like object that records the time when data was written to
+ the stream."""
+
+ def __init__(self):
+ self.buf = []
+ self.error = ""
+
+ def write(self, data):
+ for line in data.splitlines():
+ line = line.strip()
+ if not line:
+ continue
+ self.buf.append((time.time(), float(line)))
+
+ def writelines(self, data):
+ for line in data:
+ self.write(line.strip())
+
+ def flush(self):
+ pass
+
+ def check(self, *bases):
+ """Map the recorded times to {0, 1} based on the range of times
+ recorded: anything in the first half of the range is mapped to
+ 0, and anything in the second half is mapped to 1. This
+ "discretizes" the times so that we can reliably compare to
+ baselines.
+
+ """
+
+ n = list(itertools.chain(*self.buf))
+ mid = (min(n) + max(n)) / 2.0
+ result = [tuple(0 if i < mid else 1 for i in _) for _ in self.buf]
+ if result not in bases:
+ base = ' or '.join(str(_) for _ in bases)
+ self.error = f"result {result} != baseline {base}\nRaw timing: {self.buf}"
+ return False
+ return True
+
+
class TestTeeStream(unittest.TestCase):
+ def setUp(self):
+ self.reenable_gc = gc.isenabled()
+ gc.disable()
+ gc.collect()
+ # Set a short switch interval so that the threading tests behave
+ # as expected
+ self.switchinterval = sys.getswitchinterval()
+ sys.setswitchinterval(tee._poll_interval / 100)
+
+ def tearDown(self):
+ sys.setswitchinterval(self.switchinterval)
+ if self.reenable_gc:
+ gc.enable()
+ gc.collect()
+
def test_stdout(self):
a = StringIO()
b = StringIO()
@@ -39,6 +99,28 @@ def test_err_and_out_are_different(self):
self.assertIs(err, t.STDERR)
self.assertIsNot(out, err)
+ def test_signal_flush(self):
+ a = StringIO()
+ with tee.TeeStream(a) as t:
+ out = t.STDOUT
+ self.assertIs(type(out), tee._SignalFlush)
+ out.write("out1\n")
+ out.writelines(["out2\n", "out3\n"])
+ self.assertEqual(a.getvalue(), "out1\nout2\nout3\n")
+ with tee.TeeStream(a) as t:
+ err = t.STDERR
+ self.assertIs(type(err), tee._AutoFlush)
+ err.write("err1\n")
+ err.writelines(["err2\n", "err3\n"])
+ self.assertEqual(a.getvalue(), "out1\nout2\nout3\nerr1\nerr2\nerr3\n")
+ # Note: 'is not writable' appears to work for all platforms
+ # except PyPy, where the exception is "readonly attribute
+ # 'name'"
+ with self.assertRaisesRegex(
+ AttributeError, '.*(is not writable)|(readonly attribute)'
+ ):
+ tee.TeeStream().STDOUT.name = 'foo'
+
@unittest.skipIf(
not tee._peek_available,
"Requires the _mergedReader, but _peek_available==False",
@@ -56,7 +138,8 @@ def test_merge_out_and_err(self):
# This is a slightly nondeterministic (on Windows), so a
# flush() and short pause should help
t.STDOUT.write("Hello\nWorld")
- t.STDOUT.flush()
+ # NOTE: do not flush: we will test flush in the next test
+ # t.STDOUT.flush()
time.sleep(tee._poll_interval * 100)
t.STDERR.write("interrupting\ncow")
t.STDERR.flush()
@@ -75,6 +158,38 @@ def test_merge_out_and_err(self):
self.assertIn(a.getvalue(), acceptable_results)
self.assertEqual(b.getvalue(), a.getvalue())
+ def test_merge_out_and_err_flush(self):
+ # Test that the STDERR/STDOUT streams are merged correctly
+ # (i.e., STDOUT is line buffered and STDERR is not). This merge
+ # logic is only applicable when using the merged reader (i.e.,
+ # _peek_available is True)
+ a = StringIO()
+ b = StringIO()
+ # make sure this doesn't accidentally become a very long wait
+ assert tee._poll_interval <= 0.1
+ with tee.TeeStream(a, b) as t:
+ # This is a slightly nondeterministic (on Windows), so a
+ # flush() and short pause should help
+ t.STDOUT.write("Hello\nWorld")
+ t.STDOUT.flush()
+ time.sleep(tee._poll_interval * 100)
+ t.STDERR.write("interrupting\ncow")
+ t.STDERR.flush()
+ # For determinism, it is important that the STDERR message
+ # appears in the output stream before we start shutting down
+ # the TeeStream (which will dump the OUT and ERR in an
+ # arbitrary order)
+ start_time = time.time()
+ while 'cow' not in a.getvalue() and time.time() - start_time < 1:
+ time.sleep(tee._poll_interval)
+ acceptable_results = {
+ "Hello\nWorldinterrupting\ncow", # expected
+ "interrupting\ncowHello\nWorld", # Windows occasionally puts
+ # all error before stdout
+ }
+ self.assertIn(a.getvalue(), acceptable_results)
+ self.assertEqual(b.getvalue(), a.getvalue())
+
def test_merged_out_and_err_without_peek(self):
a = StringIO()
b = StringIO()
@@ -113,9 +228,6 @@ def test_decoder_and_buffer_errors(self):
os.write(t.STDOUT.fileno(), bytes_ref[:-1])
self.assertEqual(
log.getvalue(),
- "Stream handle closed with a partial line in the output buffer "
- "that was not emitted to the output stream(s):\n"
- "\t'Hello, '\n"
"Stream handle closed with un-decoded characters in the decoder "
"buffer that was not emitted to the output stream(s):\n"
"\tb'\\xc2'\n",
@@ -127,12 +239,84 @@ def test_decoder_and_buffer_errors(self):
with tee.TeeStream(out) as t:
out.close()
t.STDOUT.write("hi\n")
+ _id = hex(id(out))
+ self.assertRegex(
+ log.getvalue(),
+ f"Error writing to output stream <_?io.StringIO @ {_id}>:"
+ r"\n.*\nOutput stream closed before all output was written to it.\n"
+ r"The following was left in the output buffer:\n 'hi\\n'\n$",
+ )
+
+ # TeeStream expects stream-like objects
+ out = logging.getLogger()
+ log = StringIO()
+ with LoggingIntercept(log):
+ with tee.TeeStream(out) as t:
+ t.STDOUT.write("hi\n")
+ _id = hex(id(out))
+ self.assertRegex(
+ log.getvalue(),
+ f"Error writing to output stream :"
+ r"\n.*\nIs this a writeable TextIOBase object\?\n"
+ r"The following was left in the output buffer:\n 'hi\\n'\n$",
+ )
+
+ # Catch partial writes
+ class fake_stream:
+ def write(self, data):
+ return 1
+
+ out = fake_stream()
+ log = StringIO()
+ with LoggingIntercept(log):
+ with tee.TeeStream(out) as t:
+ t.STDOUT.write("hi\n")
+ _id = hex(id(out))
self.assertRegex(
log.getvalue(),
- r"^Output stream \(<.*?>\) closed before all output was written "
- r"to it. The following was left in the output buffer:\n\t'hi\\n'\n$",
+ f"Incomplete write to output stream <.*fake_stream @ {_id}>."
+ r"\nThe following was left in the output buffer:\n 'i\\n'\n$",
)
+ def test_context_mismatch(self):
+ with self.assertRaisesRegex(
+ RuntimeError, "TeeStream: exiting a context that was not entered"
+ ):
+ with tee.TeeStream() as t:
+ t.__exit__(None, None, None)
+
+ def test_handle_prematurely_closed(self):
+ # Close the TextIO object
+ with LoggingIntercept() as LOG:
+ with tee.TeeStream() as t:
+ t.STDOUT.close()
+ self.assertEqual(LOG.getvalue(), "")
+
+ # Close the underlying file descriptor
+ with LoggingIntercept() as LOG:
+ with tee.TeeStream() as t:
+ os.close(t.STDOUT.fileno())
+ self.assertEqual(LOG.getvalue(), "")
+
+
+class TestCapture(unittest.TestCase):
+ def setUp(self):
+ self.streams = sys.stdout, sys.stderr
+ self.reenable_gc = gc.isenabled()
+ gc.disable()
+ gc.collect()
+ # Set a short switch interval so that the threading tests behave
+ # as expected
+ self.switchinterval = sys.getswitchinterval()
+ sys.setswitchinterval(tee._poll_interval / 100)
+
+ def tearDown(self):
+ sys.stdout, sys.stderr = self.streams
+ sys.setswitchinterval(self.switchinterval)
+ if self.reenable_gc:
+ gc.enable()
+ gc.collect()
+
def test_capture_output(self):
out = StringIO()
with tee.capture_output(out) as OUT:
@@ -161,47 +345,534 @@ def test_capture_output_logfile_string(self):
result = f.read()
self.assertEqual('HELLO WORLD\n', result)
+ # Check that an exception when entering the context will cleanly
+ # unroll the context stack
+ logfile = os.path.join('path', 'to', 'nonexisting', 'file.txt')
+ T = tee.capture_output(logfile)
+ with self.assertRaises(FileNotFoundError):
+ T.__enter__()
+ self.assertEqual(T.context_stack, [])
+
+ def test_capture_to_logger(self):
+ logger = logging.getLogger('_pyomo_no_logger')
+ lstream = LogStream(logging.WARNING, logger)
+ orig = logger.propagate, logger.handlers
+ try:
+ logger.propagate = False
+ logger.handlers = []
+ with LoggingIntercept(module='_pyomo_no_logger') as LOG:
+ with tee.capture_output(lstream, capture_fd=False):
+ sys.stderr.write("hi!\n")
+ sys.stderr.flush()
+ self.assertEqual(LOG.getvalue(), "hi!\n")
+
+ # test that we handle the lastResort logger correctly
+ _lastResort = logging.lastResort
+ with tee.capture_output() as OUT:
+ with tee.capture_output(lstream, capture_fd=False):
+ self.assertIsNot(_lastResort, logging.lastResort)
+ sys.stderr.write("hi?\n")
+ self.assertEqual(OUT.getvalue(), "hi?\n")
+
+ # test that we allow redirect-to-logger out
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=False):
+ sys.stderr.write("hi.\n")
+ self.assertEqual(OUT.getvalue(), "hi.\n")
+ logger.handlers.clear()
+
+ # test a sub-logger
+ lstream = LogStream(
+ logging.WARNING, logging.getLogger('_pyomo_no_logger.foo')
+ )
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=False):
+ sys.stderr.write("hi,\n")
+ self.assertEqual(OUT.getvalue(), "hi,\n")
+ finally:
+ logger.propagate, logger.handlers = orig
+
+ def test_capture_fd_to_logger(self):
+ logger = logging.getLogger('_pyomo_no_logger')
+ lstream = LogStream(logging.WARNING, logger)
+ orig = logger.propagate, logger.handlers
+ try:
+ logger.propagate = False
+ logger.handlers = []
+ with LoggingIntercept(module='_pyomo_no_logger') as LOG:
+ with tee.capture_output(lstream, capture_fd=True):
+ sys.stderr.write("hi!\n")
+ sys.stderr.flush()
+ self.assertEqual(LOG.getvalue(), "hi!\n")
+
+ # test that we handle the lastResort logger correctly
+ _lastResort = logging.lastResort
+ with tee.capture_output() as OUT:
+ with tee.capture_output(lstream, capture_fd=True):
+ self.assertIsNot(_lastResort, logging.lastResort)
+ sys.stderr.write("hi?\n")
+ self.assertEqual(OUT.getvalue(), "hi?\n")
+
+ # test that we allow redirect-to-logger out
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=True):
+ sys.stderr.write("hi.\n")
+ self.assertEqual(OUT.getvalue(), "hi.\n")
+ logger.handlers.clear()
+
+ # test a sub-logger
+ lstream = LogStream(
+ logging.WARNING, logging.getLogger('_pyomo_no_logger.foo')
+ )
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=True):
+ sys.stderr.write("hi,\n")
+ self.assertEqual(OUT.getvalue(), "hi,\n")
+ finally:
+ logger.propagate, logger.handlers = orig
+
+ def test_capture_to_logger_adapter(self):
+ class Adapter(logging.LoggerAdapter):
+ def process(self, msg, kwargs):
+ return '[%s] %s' % (self.extra['foo'], msg), kwargs
+
+ logger = logging.getLogger('_pyomo_no_logger')
+ adapter = Adapter(logger, {"foo": 42})
+ lstream = LogStream(logging.WARNING, adapter)
+ orig = logger.propagate, logger.handlers
+ try:
+ logger.propagate = False
+ logger.handlers = []
+ with LoggingIntercept(module='_pyomo_no_logger') as LOG:
+ with tee.capture_output(lstream, capture_fd=False):
+ sys.stderr.write("hi!\n")
+ sys.stderr.flush()
+ self.assertEqual(LOG.getvalue(), "[42] hi!\n")
+
+ # test that we handle the lastResort logger correctly
+ _lastResort = logging.lastResort
+ with tee.capture_output() as OUT:
+ with tee.capture_output(lstream, capture_fd=False):
+ self.assertIsNot(_lastResort, logging.lastResort)
+ sys.stderr.write("hi?\n")
+ self.assertEqual(OUT.getvalue(), "[42] hi?\n")
+
+ # test that we allow redirect-to-logger out
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=False):
+ sys.stderr.write("hi.\n")
+ self.assertEqual(OUT.getvalue(), "[42] hi.\n")
+ logger.handlers.clear()
+ finally:
+ logger.propagate, logger.handlers = orig
+
+ def test_capture_fd_to_logger_adapter(self):
+ class Adapter(logging.LoggerAdapter):
+ def process(self, msg, kwargs):
+ return '[%s] %s' % (self.extra['foo'], msg), kwargs
+
+ logger = logging.getLogger('_pyomo_no_logger')
+ adapter = Adapter(logger, {"foo": 42})
+ lstream = LogStream(logging.WARNING, adapter)
+ orig = logger.propagate, logger.handlers
+ try:
+ logger.propagate = False
+ logger.handlers = []
+ with LoggingIntercept(module='_pyomo_no_logger') as LOG:
+ with tee.capture_output(lstream, capture_fd=True):
+ sys.stderr.write("hi!\n")
+ sys.stderr.flush()
+ self.assertEqual(LOG.getvalue(), "[42] hi!\n")
+
+ # test that we handle the lastResort logger correctly
+ _lastResort = logging.lastResort
+ with tee.capture_output() as OUT:
+ with tee.capture_output(lstream, capture_fd=True):
+ self.assertIsNot(_lastResort, logging.lastResort)
+ sys.stderr.write("hi?\n")
+ self.assertEqual(OUT.getvalue(), "[42] hi?\n")
+
+ # test that we allow redirect-to-logger out
+ with tee.capture_output() as OUT:
+ logger.addHandler(logging.NullHandler())
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ with tee.capture_output(lstream, capture_fd=True):
+ sys.stderr.write("hi.\n")
+ self.assertEqual(OUT.getvalue(), "[42] hi.\n")
+ logger.handlers.clear()
+ finally:
+ logger.propagate, logger.handlers = orig
+
+ def test_no_fileno_stdout(self):
+ T = tee.capture_output()
+ with T:
+ self.assertEqual(len(T.context_stack), 2)
+ T = tee.capture_output(capture_fd=True)
+ # out & err point to something other than fd 1 and 2
+ sys.stdout = os.fdopen(os.dup(1), closefd=True)
+ sys.stderr = os.fdopen(os.dup(2), closefd=True)
+ with sys.stdout, sys.stderr:
+ with T:
+ self.assertEqual(len(T.context_stack), 8)
+ # out & err point to fd 1 and 2
+ sys.stdout = os.fdopen(1, closefd=False)
+ sys.stderr = os.fdopen(2, closefd=False)
+ with sys.stdout, sys.stderr:
+ with T:
+ self.assertEqual(len(T.context_stack), 6)
+ # out & err have no fileno
+ sys.stdout = StringIO()
+ sys.stderr = StringIO()
+ with sys.stdout, sys.stderr:
+ with T:
+ self.assertEqual(len(T.context_stack), 6)
+
def test_capture_output_stack_error(self):
OUT1 = StringIO()
OUT2 = StringIO()
old = (sys.stdout, sys.stderr)
+ old_fd = os.dup(1), os.dup(2)
try:
a = tee.capture_output(OUT1)
a.setup()
b = tee.capture_output(OUT2)
b.setup()
with self.assertRaisesRegex(
- RuntimeError, 'Captured output does not match sys.stdout'
+ RuntimeError, 'Captured output .* does not match sys.stdout'
):
a.reset()
- b.tee = None
finally:
+ # Clear b so that it doesn't call __exit__ and corrupt stdout/stderr
+ b.tee = None
+ os.dup2(old_fd[0], 1)
+ os.dup2(old_fd[1], 2)
sys.stdout, sys.stderr = old
+ logging.getLogger('pyomo.common.tee').handlers.clear()
+
+ def test_capture_output_invalid_ostream(self):
+ # Test that capture_output does not suppress errors from the tee
+ # module
+ _id = hex(id(15))
+ with tee.capture_output(capture_fd=True) as OUT:
+ with tee.capture_output(15):
+ sys.stderr.write("hi\n")
+ self.assertEqual(
+ OUT.getvalue(),
+ f"Error writing to output stream :\n"
+ " AttributeError: 'int' object has no attribute 'write'\n"
+ "Is this a writeable TextIOBase object?\n"
+ "The following was left in the output buffer:\n 'hi\\n'\n",
+ )
+
+ with tee.capture_output(capture_fd=True) as OUT:
+ with tee.capture_output(15, capture_fd=True):
+ print("hi")
+ self.assertEqual(
+ OUT.getvalue(),
+ f"Error writing to output stream :\n"
+ " AttributeError: 'int' object has no attribute 'write'\n"
+ "Is this a writeable TextIOBase object?\n"
+ "The following was left in the output buffer:\n 'hi\\n'\n",
+ )
+
+ def test_exit_on_del(self):
+ # This is a weird "feature", but because things like the pyomo
+ # script will create and "enter" a capture_output object without
+ # using a context manager, it is possible that the object can be
+ # deleted without calling __exit__. Check that the context
+ # stack is correctly unwound
+ T = tee.capture_output()
+ T.__enter__()
+ stack = T.context_stack
+ self.assertGreater(len(stack), 0)
+ del T
+ # This is a bit tricky: for cpython, T should be immediately
+ # deallocated (including calling __del__) through reference
+ # counting. pypy is trickier: because it lacks
+ # reference-counting, it must rely on the GC. We have seen
+ # cases on GHA where a single call to gc.collect() was sometimes
+ # insufficient to ensure that T was collected (but unable to
+ # reproduce it locally). We will try up to 4 times (1 more than
+ # the number of generations in the GC)
+ remaining_attempts = 4
+ while len(stack) and remaining_attempts:
+ gc.collect()
+ time.sleep(((4 - remaining_attempts) / 4.0) ** 2)
+ remaining_attempts -= 1
+ try:
+ self.assertEqual(len(stack), 0)
+ except:
+ # We still want to unwind the context managers if the test fails:
+ while stack:
+ try:
+ stack.pop().__exit__(None, None, None)
+ except:
+ pass
+ raise
def test_deadlock(self):
class MockStream(object):
def write(self, data):
- time.sleep(0.2)
+ # This test will kill the write before this sleep is
+ # done, so a long sleep won't impact suite run time.
+ time.sleep(1)
+
+ def flush(self):
+ pass
_save = tee._poll_timeout, tee._poll_timeout_deadlock
tee._poll_timeout = tee._poll_interval * 2**5 # 0.0032
tee._poll_timeout_deadlock = tee._poll_interval * 2**7 # 0.0128
-
try:
with LoggingIntercept() as LOG, self.assertRaisesRegex(
RuntimeError, 'deadlock'
):
with tee.TeeStream(MockStream()) as t:
- err = t.STDERR
- err.write('*')
+ t.STDERR.write('*')
self.assertEqual(
'Significant delay observed waiting to join reader '
- 'threads, possible output stream deadlock\n',
+ 'threads, possible output stream deadlock\n'
+ 'TeeStream: deadlock observed joining reader threads\n',
LOG.getvalue(),
)
finally:
tee._poll_timeout, tee._poll_timeout_deadlock = _save
+ _save = tee._poll_timeout, tee._poll_timeout_deadlock
+ tee._poll_timeout = tee._poll_interval * 2**5 # 0.0032
+ tee._poll_timeout_deadlock = tee._poll_interval * 2**7 # 0.0128
+ try:
+ with LoggingIntercept() as LOG, self.assertRaisesRegex(
+ ValueError, 'testing'
+ ):
+ with tee.TeeStream(MockStream()) as t:
+ t.STDERR.write('*')
+ raise ValueError('testing')
+ self.assertEqual("", LOG.getvalue())
+ finally:
+ tee._poll_timeout, tee._poll_timeout_deadlock = _save
+
+
+class BufferTester(object):
+ def setUp(self):
+ sys.stdout.flush()
+ sys.stderr.flush()
+ self.reenable_gc = gc.isenabled()
+ gc.disable()
+ gc.collect()
+ # Set a short switch interval so that the threading tests behave
+ # as expected
+ self.switchinterval = sys.getswitchinterval()
+ sys.setswitchinterval(tee._poll_interval)
+ self.dt = 0.1
+
+ def tearDown(self):
+ sys.setswitchinterval(self.switchinterval)
+ if self.reenable_gc:
+ gc.enable()
+ gc.collect()
+
+ def test_buffered_stdout(self):
+ # Test 1: short messages to STDOUT are buffered
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}\n")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stdout.write(f"{time.time()}\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}\n")
+ baseline = [
+ [(0, 0), (1, 0), (1, 0), (1, 1)],
+ # TODO: [JDS] The stdout channel appears to sometimes be no
+ # longer buffered. I am not exactly sure why (my guess is
+ # because the underlying pipe is not buffered), but as it is
+ # generally not a problem to not buffer, we will put off
+ # "fixing" it.
+ [(0, 0), (0, 0), (0, 0), (1, 1)],
+ ]
+ if not ts.check(*baseline):
+ self.fail(ts.error)
+
+ def test_buffered_stdout_flush(self, retry=True):
+ # Test 2: short messages to STDOUT that are flushed are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}\n")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stdout.write(f"{time.time()}\n")
+ sys.stdout.flush()
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}\n")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ # FIXME: We don't know why, but this test will
+ # intermittently fail. For the moment, we will just wait a
+ # little and give it a second chance with a longer delay.
+ if retry:
+ time.sleep(self.dt)
+ self.dt *= 2.5
+ self.test_buffered_stdout_flush(False)
+ elif platform.python_implementation().lower().startswith('pypy'):
+ # TODO: For some reason, some part of the flush logic is
+ # not reliable under pypy.
+ pass
+ else:
+ self.fail(ts.error)
+
+ def test_buffered_stdout_long_message(self):
+ # Test 3: long messages to STDOUT fill the buffer and are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stdout.write(f"{time.time()}" + ' ' * 4096 + "\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stdout_embed_TeeStream(self):
+ # Test 4: short messages captured directly to TeeStream are not
+ # buffered.
+ #
+ # TODO: [JDS] I am not exactly sure why this is not buffered (my
+ # guess is because the underlying pipe is not buffered), but as
+ # it is generally not a problem to not buffer, we will put off
+ # "fixing" it.
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stdout.write(f"{time.time()}\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stdout_flush_embed_TeeStream(self):
+ # Test 5: short messages captured directly to TeeStream that are
+ # flushed are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stdout.write(f"{time.time()}\n")
+ sys.stdout.flush()
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stdout_long_message_embed_TeeStream(self):
+ # Test 6: long messages captured directly to TeeStream fill the
+ # buffer and are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stdout.write(f"{time.time()}" + ' ' * 4096 + "\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr(self):
+ # Test 1: short messages to STDERR are buffered, unless we are
+ # capturing the underlying file descriptor, in which case they
+ # are buffered.
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stderr.write(f"{time.time()}\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr_flush(self):
+ # Test 2: short messages to STDERR that are flushed are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stderr.write(f"{time.time()}\n")
+ sys.stderr.flush()
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr_long_message(self):
+ # Test 3: long messages to STDERR fill the buffer and are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.TeeStream(ts, ts) as t, tee.capture_output(t.STDOUT, capture_fd=fd):
+ sys.stderr.write(f"{time.time()}" + ' ' * 4096 + "\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr_embed_TeeStream(self):
+ # Test 4: short messages captured directly to TeeStream are not
+ # buffered, unless we are capturing the underlying file
+ # descriptor, in which case they are buffered.
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stderr.write(f"{time.time()}\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr_flush_embed_TeeStream(self):
+ # Test 5: short messages captured directly to TeeStream that are
+ # flushed are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stderr.write(f"{time.time()}\n")
+ sys.stderr.flush()
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+ def test_buffered_stderr_long_message_embed_TeeStream(self):
+ # Test 6: long messages captured directly to TeeStream fill the
+ # buffer and are flushed
+ fd = self.capture_fd
+ ts = timestamper()
+ ts.write(f"{time.time()}")
+ with tee.capture_output(tee.TeeStream(ts, ts), capture_fd=fd):
+ sys.stderr.write(f"{time.time()}" + ' ' * 4096 + "\n")
+ time.sleep(self.dt)
+ ts.write(f"{time.time()}")
+ if not ts.check([(0, 0), (0, 0), (0, 0), (1, 1)]):
+ self.fail(ts.error)
+
+
+class TestBuffering_noCapture(BufferTester, unittest.TestCase):
+ capture_fd = False
+
+
+class TestBuffering_capture(BufferTester, unittest.TestCase):
+ capture_fd = True
+
class TestFileDescriptor(unittest.TestCase):
def setUp(self):
@@ -249,7 +920,7 @@ def test_redirect_no_synchronize_stdout(self):
with os.fdopen(r, 'r') as FILE:
os.close(w)
os.close(1)
- self.assertEqual(FILE.read(), "to_stdout_1\nto_stdout_2\nto_fd1_2\n")
+ self.assertEqual(FILE.read(), "to_stdout_2\nto_fd1_2\n")
# Pytest's default capture method causes failures for the following
# two tests. This re-implementation of the capfd fixture allows
@@ -340,6 +1011,38 @@ def test_capture_output_fd(self):
os.close(w)
self.assertEqual(FILE.read(), "to_stdout_2\nto_fd1_2\n")
+ def test_nested_capture_output(self):
+ OUT2 = StringIO()
+ r, w = os.pipe()
+ os.dup2(w, 1)
+ sys.stdout = stdout0 = os.fdopen(1, 'w', closefd=False)
+ with tee.capture_output((sys.stdout, StringIO()), capture_fd=True) as (_, OUT1):
+ stdout1 = sys.stdout
+ self.assertIsNot(stdout0, stdout1)
+ with tee.capture_output((sys.stdout, OUT2), capture_fd=True):
+ stdout2 = sys.stdout
+ self.assertIsNot(stdout1, stdout2)
+ sys.stdout.write("to_stdout_1\n")
+ sys.stdout.flush()
+ with os.fdopen(1, 'w', closefd=False) as F:
+ F.write("to_fd1_1\n")
+ F.flush()
+
+ sys.stdout.write("to_stdout_2\n")
+ sys.stdout.flush()
+ with os.fdopen(1, 'w', closefd=False) as F:
+ F.write("to_fd1_2\n")
+ F.flush()
+
+ self.assertEqual(OUT1.getvalue(), "to_stdout_1\nto_fd1_1\n")
+ self.assertEqual(OUT2.getvalue(), "to_stdout_1\nto_fd1_1\n")
+ with os.fdopen(r, 'r') as FILE:
+ os.close(1)
+ os.close(w)
+ self.assertEqual(
+ FILE.read(), "to_stdout_1\nto_fd1_1\nto_stdout_2\nto_fd1_2\n"
+ )
+
if __name__ == '__main__':
unittest.main()
diff --git a/pyomo/common/tests/test_tempfile.py b/pyomo/common/tests/test_tempfile.py
index c49aa8c6771..85aa2fca3c4 100644
--- a/pyomo/common/tests/test_tempfile.py
+++ b/pyomo/common/tests/test_tempfile.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_timing.py b/pyomo/common/tests/test_timing.py
index 0a4224c5476..c75fc3fafd9 100644
--- a/pyomo/common/tests/test_timing.py
+++ b/pyomo/common/tests/test_timing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -35,7 +35,7 @@
Any,
TransformationFactory,
)
-from pyomo.core.base.var import _VarData
+from pyomo.core.base.var import VarData
class _pseudo_component(Var):
@@ -47,8 +47,13 @@ class TestTiming(unittest.TestCase):
def setUp(self):
self.reenable_gc = gc.isenabled()
gc.disable()
+ # Set a long switch interval to discourage context switches
+ # during these tests
+ self.switchinterval = sys.getswitchinterval()
+ sys.setswitchinterval(10)
def tearDown(self):
+ sys.setswitchinterval(self.switchinterval)
if self.reenable_gc:
gc.enable()
gc.collect()
@@ -62,7 +67,7 @@ def test_raw_construction_timer(self):
)
v = Var()
v.construct()
- a = ConstructionTimer(_VarData(v))
+ a = ConstructionTimer(VarData(v))
self.assertRegex(
str(a),
r"ConstructionTimer object for Var ScalarVar\[NOTSET\]; "
@@ -107,7 +112,6 @@ def test_report_timing(self):
m.y = Var(Any, dense=False)
xfrm.apply_to(m)
result = out.getvalue().strip()
- self.maxDiff = None
for l, r in zip(result.splitlines(), ref.splitlines()):
self.assertRegex(str(l.strip()), str(r.strip()))
finally:
@@ -122,7 +126,6 @@ def test_report_timing(self):
m.y = Var(Any, dense=False)
xfrm.apply_to(m)
result = os.getvalue().strip()
- self.maxDiff = None
for l, r in zip(result.splitlines(), ref.splitlines()):
self.assertRegex(str(l.strip()), str(r.strip()))
finally:
@@ -135,7 +138,6 @@ def test_report_timing(self):
m.y = Var(Any, dense=False)
xfrm.apply_to(m)
result = os.getvalue().strip()
- self.maxDiff = None
for l, r in zip(result.splitlines(), ref.splitlines()):
self.assertRegex(str(l.strip()), str(r.strip()))
self.assertEqual(buf.getvalue().strip(), "")
@@ -172,7 +174,6 @@ def test_report_timing_context_manager(self):
xfrm.apply_to(m)
self.assertEqual(OUT.getvalue(), "")
result = OS.getvalue().strip()
- self.maxDiff = None
for l, r in zip_longest(result.splitlines(), ref.splitlines()):
self.assertRegex(str(l.strip()), str(r.strip()))
# Active reporting is False: the previous log should not have changed
@@ -184,7 +185,7 @@ def test_report_timing_context_manager(self):
def test_TicTocTimer_tictoc(self):
SLEEP = 0.1
- RES = 0.02 # resolution (seconds): 1/5 the sleep
+ RES = 0.01 # resolution (seconds): 1/10 the sleep
# Note: pypy on GHA occasionally has timing
# differences of >0.04s
@@ -194,6 +195,11 @@ def test_TicTocTimer_tictoc(self):
# if sys.platform == 'darwin':
# RES *= 2
+ # Note: the above RES heuristics were determined before the
+ # current handling of "now" within the tic/toc timer. They are
+ # probably overly conservative now, but tightening them doesn't
+ # really improve the quality of the tests.
+
abs_time = time.perf_counter()
timer = TicTocTimer()
@@ -273,7 +279,12 @@ def test_TicTocTimer_tictoc(self):
def test_TicTocTimer_context_manager(self):
SLEEP = 0.1
- RES = 0.05 # resolution (seconds): 1/2 the sleep
+ RES = 0.01 # resolution (seconds): 1/10 the sleep
+
+ # Note: the above RES heuristic was determined before the
+ # current handling of "now" within the tic/toc timer. It is
+ # probably overly conservative now, but tightening them doesn't
+ # really improve the quality of the tests.
abs_time = time.perf_counter()
with TicTocTimer() as timer:
diff --git a/pyomo/common/tests/test_typing.py b/pyomo/common/tests/test_typing.py
index e65effe7f29..6f03e6308e3 100644
--- a/pyomo/common/tests/test_typing.py
+++ b/pyomo/common/tests/test_typing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/common/tests/test_unittest.py b/pyomo/common/tests/test_unittest.py
index 9344853b737..0ba42a50e06 100644
--- a/pyomo/common/tests/test_unittest.py
+++ b/pyomo/common/tests/test_unittest.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -13,7 +13,6 @@
import multiprocessing
import os
import time
-from io import StringIO
import pyomo.common.unittest as unittest
from pyomo.common.log import LoggingIntercept
@@ -190,7 +189,7 @@ def test_timeout(self):
@unittest.timeout(0.01)
def test_timeout_timeout(self):
time.sleep(1)
- self.assertEqual(0, 1)
+ self.assertEqual(0, 0)
@unittest.timeout(10)
def test_timeout_skip(self):
@@ -218,8 +217,7 @@ def test_bound_function(self):
if multiprocessing.get_start_method() == 'fork':
self.bound_function()
return
- LOG = StringIO()
- with LoggingIntercept(LOG):
+ with LoggingIntercept() as LOG:
with self.assertRaises((TypeError, EOFError, AttributeError)):
self.bound_function()
self.assertIn("platform that does not support 'fork'", LOG.getvalue())
@@ -234,7 +232,7 @@ def test_bound_function_require_fork(self):
self.bound_function_require_fork()
return
with self.assertRaisesRegex(
- unittest.SkipTest, "timeout requires unavailable fork interface"
+ unittest.SkipTest, r"timeout\(\) requires unavailable fork interface"
):
self.bound_function_require_fork()
diff --git a/pyomo/common/timing.py b/pyomo/common/timing.py
index d502b38d12d..b08b2bd07dc 100644
--- a/pyomo/common/timing.py
+++ b/pyomo/common/timing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -347,6 +347,11 @@ class was constructed). Note: timing logged using `level`
level (int): an optional logging output level.
"""
+ # Note: important to do this first so that we don't add a random
+ # amount of time for I/O operations or extracting the stack.
+ # This helps ensure that the timing tests are less fragile.
+ now = default_timer()
+
if msg is _NotSpecified:
msg = 'File "%s", line %s in %s' % traceback.extract_stack(limit=2)[0][:3]
if args and msg is not None and '%' not in msg:
@@ -365,11 +370,10 @@ class was constructed). Note: timing logged using `level`
if args:
logger, *args = args
- now = default_timer()
if self._start_count or self._lastTime is None:
ans = self._cumul
if self._lastTime:
- ans += default_timer() - self._lastTime
+ ans += now - self._lastTime
if msg is not None:
fmt = "[%8.2f|%4d] %s"
data = (ans, self._start_count, msg)
diff --git a/pyomo/common/unittest.py b/pyomo/common/unittest.py
index 9a21b35faa8..a332e38deee 100644
--- a/pyomo/common/unittest.py
+++ b/pyomo/common/unittest.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -32,7 +32,6 @@
# specifically later
from unittest import *
import unittest as _unittest
-import pytest as pytest
from pyomo.common.collections import Mapping, Sequence
from pyomo.common.dependencies import attempt_import, check_min_version
@@ -43,6 +42,11 @@
from unittest import mock
+# We defer this import so that we don't add a hard dependence on pytest.
+# Note that importing test modules may cause this import to be resolved
+# (and then enforce a strict dependence on pytest)
+pytest, pytest_available = attempt_import('pytest')
+
def _defaultFormatter(msg, default):
return msg or default
@@ -111,8 +115,10 @@ def assertStructuredAlmostEqual(
values)
The relative error is computed for numerical values as
- `abs(first - second) / max(abs(first), abs(second))`,
- only when first != second (thereby avoiding divide-by-zero errors).
+
+ `abs(first - second) / max(abs(first), abs(second))`
+
+ only when `first != second` (thereby avoiding divide-by-zero errors).
Items (entries other than Sequence / Mapping containers, matching
strings, and items that satisfy `first is second`) are passed to the
@@ -123,37 +129,47 @@ def assertStructuredAlmostEqual(
Parameters
----------
- first:
+ first :
the first value to compare
- second:
+
+ second :
the second value to compare
- places: int
+
+ places : int
`first` and `second` are considered equivalent if their
difference is between `places` decimal places; equivalent to
`abstol = 10**-places` (included for compatibility with
assertAlmostEqual)
- msg: str
+
+ msg : str
the message to raise on failure
- delta: float
+
+ delta : float
alias for `abstol`
- abstol: float
+
+ abstol : float
the absolute tolerance. `first` and `second` are considered
equivalent if their absolute difference is less than `abstol`
- reltol: float
+
+ reltol : float
the relative tolerance. `first` and `second` are considered
equivalent if their absolute difference divided by the
largest of `first` and `second` is less than `reltol`
- allow_second_superset: bool
+
+ allow_second_superset : bool
If True, then extra entries in containers found on second
will not trigger a failure.
- item_callback: function
+
+ item_callback : function
items (other than Sequence / Mapping containers, matching
strings, and items satisfying `is`) are passed to this callback
to generate the (nominally floating point) value to use for
comparison.
- exception: Exception
+
+ exception : Exception
exception to raise when `first` is not 'almost equal' to `second`.
- formatter: function
+
+ formatter : function
callback for generating the final failure message (for
compatibility with unittest)
@@ -292,11 +308,11 @@ def _assertStructuredAlmostEqual(
raise exception(msg)
-def _runner(q, qualname):
+def _runner(pipe, qualname):
"Utility wrapper for running functions, used by timeout()"
resultType = _RunnerResult.call
- if q in _runner.data:
- fcn, args, kwargs = _runner.data[q]
+ if pipe in _runner.data:
+ fcn, args, kwargs = _runner.data[pipe]
elif isinstance(qualname, str):
# Use unittest to instantiate the TestCase and run it
resultType = _RunnerResult.unittest
@@ -312,11 +328,10 @@ def fcn():
else:
qualname, fcn, args, kwargs = qualname
_runner.data[qualname] = None
- OUT = StringIO()
try:
- with capture_output(OUT):
+ with capture_output() as OUT:
result = fcn(*args, **kwargs)
- q.put((resultType, result, OUT.getvalue()))
+ pipe.send((resultType, result, OUT.getvalue()))
except:
import traceback
@@ -325,7 +340,7 @@ def fcn():
e = etype(
"%s\nOriginal traceback:\n%s" % (e, ''.join(traceback.format_tb(tb)))
)
- q.put((_RunnerResult.exception, e, OUT.getvalue()))
+ pipe.send((_RunnerResult.exception, e, OUT.getvalue()))
finally:
_runner.data.pop(qualname)
@@ -349,7 +364,7 @@ def timeout(seconds, require_fork=False, timeout_raises=TimeoutError):
using multiprocessing to execute the function in a forked process.
If the wrapped function raises an exception, then the exception will
be re-raised in this process. If the function times out, a
- :python:`TimeoutError` will be raised.
+ :class:`TimeoutError` will be raised.
Note that as this method uses multiprocessing, the wrapped function
should NOT spawn any subprocesses. The timeout is implemented using
@@ -371,21 +386,27 @@ def timeout(seconds, require_fork=False, timeout_raises=TimeoutError):
Examples
--------
- >>> import pyomo.common.unittest as unittest
- >>> @unittest.timeout(1)
- ... def test_function():
- ... return 42
- >>> test_function()
- 42
-
- >>> @unittest.timeout(0.01)
- ... def test_function():
- ... while 1:
- ... pass
- >>> test_function()
- Traceback (most recent call last):
- ...
- TimeoutError: test timed out after 0.01 seconds
+ .. doctest::
+ :skipif: multiprocessing.get_start_method() != 'fork'
+
+ >>> import pyomo.common.unittest as unittest
+ >>> @unittest.timeout(1)
+ ... def test_function():
+ ... return 42
+ >>> test_function()
+ 42
+
+ .. doctest::
+ :skipif: multiprocessing.get_start_method() != 'fork'
+
+ >>> @unittest.timeout(0.01)
+ ... def test_function():
+ ... while 1:
+ ... pass
+ >>> test_function()
+ Traceback (most recent call last):
+ ...
+ TimeoutError: test timed out after 0.01 seconds
"""
import functools
@@ -396,18 +417,24 @@ def timeout_decorator(fcn):
@functools.wraps(fcn)
def test_timer(*args, **kwargs):
qualname = '%s.%s' % (fcn.__module__, fcn.__qualname__)
+ # If qualname is in the data dict, then we are in the child
+ # process and are being asked to run the wrapped function.
if qualname in _runner.data:
return fcn(*args, **kwargs)
+ # Parent process: spawn a subprocess to execute the wrapped
+ # function and monitor for timeout
if require_fork and multiprocessing.get_start_method() != 'fork':
- raise _unittest.SkipTest("timeout requires unavailable fork interface")
+ raise _unittest.SkipTest(
+ "timeout() requires unavailable fork interface"
+ )
- q = multiprocessing.Queue()
+ pipe_recv, pipe_send = multiprocessing.Pipe(False)
if multiprocessing.get_start_method() == 'fork':
# Option 1: leverage fork if possible. This minimizes
# the reliance on serialization and ensures that the
# wrapped function operates in the same environment.
- _runner.data[q] = (fcn, args, kwargs)
- runner_args = (q, qualname)
+ _runner.data[pipe_send] = (fcn, args, kwargs)
+ runner_arg = qualname
elif (
args
and fcn.__name__.startswith('test')
@@ -417,36 +444,41 @@ def test_timer(*args, **kwargs):
# unittest in the child process with this function as
# the sole target. This ensures that things like setUp
# and tearDown are correctly called.
- runner_args = (q, qualname)
+ runner_arg = qualname
else:
# Option 3: attempt to serialize the function and all
# arguments and send them to the (spawned) child
# process. The wrapped function cannot count on any
# environment configuration that it does not set up
# itself.
- runner_args = (q, (qualname, test_timer, args, kwargs))
- test_proc = multiprocessing.Process(target=_runner, args=runner_args)
+ runner_arg = (qualname, test_timer, args, kwargs)
+ test_proc = multiprocessing.Process(
+ target=_runner, args=(pipe_send, runner_arg)
+ )
+ # Set daemon: if the parent process is killed, the child
+ # process should be killed and collected.
test_proc.daemon = True
try:
test_proc.start()
except:
- if type(runner_args[1]) is tuple:
+ if type(runner_arg) is tuple:
logging.getLogger(__name__).error(
- "Exception raised spawning timeout subprocess "
+ "Exception raised spawning timeout() subprocess "
"on a platform that does not support 'fork'. "
"It is likely that either the wrapped function or "
"one of its arguments is not serializable"
)
raise
try:
- resultType, result, stdout = q.get(True, seconds)
- except queue.Empty:
- test_proc.terminate()
- raise timeout_raises(
- "test timed out after %s seconds" % (seconds,)
- ) from None
+ if pipe_recv.poll(seconds):
+ resultType, result, stdout = pipe_recv.recv()
+ else:
+ test_proc.terminate()
+ raise timeout_raises(
+ "test timed out after %s seconds" % (seconds,)
+ ) from None
finally:
- _runner.data.pop(q, None)
+ _runner.data.pop(pipe_send, None)
sys.stdout.write(stdout)
test_proc.join()
if resultType == _RunnerResult.call:
@@ -489,14 +521,35 @@ class TestCase(_unittest.TestCase):
This class derives from unittest.TestCase and provides the following
additional functionality:
- - additional assertions:
- * :py:meth:`assertStructuredAlmostEqual`
- unittest.TestCase documentation
- -------------------------------
+ * additional assertions:
+ - :py:meth:`~TestCase.assertStructuredAlmostEqual`
+ - :py:meth:`assertExpressionsEqual`
+ - :py:meth:`assertExpressionsStructurallyEqual`
+
+ * updated assertions:
+ - :py:meth:`assertRaisesRegex`
+
+ :py:class:`unittest.TestCase` documentation
+ -------------------------------------------
"""
- __doc__ += _unittest.TestCase.__doc__
+ # Note that the current unittest.TestCase documentation generates
+ # sphinx warnings. We will clean up that documentation to suppress
+ # the warnings.
+ __doc__ += (
+ re.sub(
+ r'^( +)(\* +[^:]+:) *',
+ r'\n\1\2\n\1 ',
+ _unittest.TestCase.__doc__.rstrip(),
+ flags=re.M,
+ )
+ + "\n\n"
+ )
+
+ # By default, we always want to spend the time to create the full
+ # diff of the test reault and the baseline
+ maxDiff = None
def assertStructuredAlmostEqual(
self,
@@ -510,6 +563,8 @@ def assertStructuredAlmostEqual(
allow_second_superset=False,
item_callback=_floatOrCall,
):
+ # Note: __doc__ copied from assertStructuredAlmostEqual below
+ #
assertStructuredAlmostEqual(
first=first,
second=second,
@@ -533,18 +588,28 @@ def assertRaisesRegex(self, expected_exception, expected_regex, *args, **kwargs)
normalizes all consecutive whitespace in the exception message
to a single space before checking the regular expression.
- Args:
- expected_exception: Exception class expected to be raised.
- expected_regex: Regex (re.Pattern object or string) expected
- to be found in error message.
- args: Function to be called and extra positional args.
- kwargs: Extra kwargs.
- msg: Optional message used in case of failure. Can only be used
- when assertRaisesRegex is used as a context manager.
- normalize_whitespace: Optional bool that, if True, collapses
- consecutive whitespace (including newlines) into a
- single space before checking against the regular
- expression
+ Parameters
+ ----------
+ expected_exception : Exception
+ Exception class expected to be raised.
+
+ expected_regex : `re.Pattern` or str
+ Regular expression expected to be found in error message.
+
+ *args :
+ Function to be called and extra positional args.
+
+ **kwargs :
+ Extra keyword args.
+
+ msg : str
+ Optional message used in case of failure. Can only be used
+ when assertRaisesRegex is used as a context manager.
+
+ normalize_whitespace : bool, default=False
+ If True, collapses consecutive whitespace (including
+ newlines) into a single space before checking against the
+ regular expression
"""
normalize_whitespace = kwargs.pop('normalize_whitespace', False)
@@ -556,6 +621,29 @@ def assertRaisesRegex(self, expected_exception, expected_regex, *args, **kwargs)
return context.handle('assertRaisesRegex', args, kwargs)
def assertExpressionsEqual(self, a, b, include_named_exprs=True, places=None):
+ """Assert that two Pyomo expressions are equal.
+
+ This converts the expressions `a` and `b` into prefix notation
+ and then compares the resulting lists. All nodes in the tree
+ are compared using py:meth:`assertEqual` (or
+ py:meth:`assertAlmostEqual`)
+
+ Parameters
+ ----------
+ a: ExpressionBase or native type
+
+ b: ExpressionBase or native type
+
+ include_named_exprs : bool
+ If True (the default), the comparison expands all named
+ expressions when generating the prefix notation
+
+ places : float
+ Number of decimal places required for equality of floating
+ point numbers in the expression. If None (the default), the
+ expressions must be exactly equal.
+
+ """
from pyomo.core.expr.compare import assertExpressionsEqual
return assertExpressionsEqual(self, a, b, include_named_exprs, places)
@@ -563,6 +651,30 @@ def assertExpressionsEqual(self, a, b, include_named_exprs=True, places=None):
def assertExpressionsStructurallyEqual(
self, a, b, include_named_exprs=True, places=None
):
+ """Assert that two Pyomo expressions are structurally equal.
+
+ This converts the expressions `a` and `b` into prefix notation
+ and then compares the resulting lists. Operators and
+ (non-native type) leaf nodes in the prefix representation are
+ converted to strings before comparing (so that things like
+ variables can be compared across clones or pickles)
+
+ Parameters
+ ----------
+ a: ExpressionBase or native type
+
+ b: ExpressionBase or native type
+
+ include_named_exprs: bool
+ If True (the default), the comparison expands all named
+ expressions when generating the prefix notation
+
+ places: float
+ Number of decimal places required for equality of floating
+ point numbers in the expression. If None (the default), the
+ expressions must be exactly equal.
+
+ """
from pyomo.core.expr.compare import assertExpressionsStructurallyEqual
return assertExpressionsStructurallyEqual(
@@ -570,6 +682,11 @@ def assertExpressionsStructurallyEqual(
)
+TestCase.assertStructuredAlmostEqual.__doc__ = re.sub(
+ 'exception :.*', '', assertStructuredAlmostEqual.__doc__, flags=re.S
+)
+
+
class BaselineTestDriver(object):
"""Generic driver for performing baseline tests in bulk
@@ -631,7 +748,7 @@ def initialize_dependencies(self):
cls.package_modules = {}
packages_used = set(sum(list(cls.package_dependencies.values()), []))
for package_ in packages_used:
- pack, pack_avail = attempt_import(package_, defer_check=False)
+ pack, pack_avail = attempt_import(package_, defer_import=False)
cls.package_available[package_] = pack_avail
cls.package_modules[package_] = pack
@@ -769,16 +886,18 @@ def filter_fcn(self, line):
# next 6 patterns ignore entries in pstats reports:
'function calls',
'List reduced',
- '.py:',
+ '.py:', # timing/profiling output
' {built-in method',
' {method',
' {pyomo.core.expr.numvalue.as_numeric}',
+ ' {gurobipy.',
):
if field in line:
return True
return False
def filter_file_contents(self, lines, abstol=None):
+ _numpy_scalar_re = re.compile(r'np.(int|float)\d+\(([^\)]+)\)')
filtered = []
deprecated = None
for line in lines:
@@ -803,6 +922,15 @@ def filter_file_contents(self, lines, abstol=None):
item_list = []
items = line.strip().split()
for i in items:
+ # Split up lists, dicts, and sets
+ while i and i[0] in '[{':
+ item_list.append(i[0])
+ i = i[1:]
+ tail = []
+ while i and i[-1] in ',:]}':
+ tail.append(i[-1])
+ i = i[:-1]
+
# A few substitutions to get tests passing on pypy3
if ".inf" in i:
i = i.replace(".inf", "inf")
@@ -810,9 +938,19 @@ def filter_file_contents(self, lines, abstol=None):
i = i.replace("null", "None")
try:
- item_list.append(float(i))
+ # Numpy 2.x changed the repr for scalars. Convert
+ # the new scalar reprs back to the original (which
+ # were indistinguishable from python floats/ints)
+ np_match = _numpy_scalar_re.match(i)
+ if np_match:
+ item_list.append(float(np_match.group(2)))
+ else:
+ item_list.append(float(i))
except:
item_list.append(i)
+ if tail:
+ tail.reverse()
+ item_list.extend(tail)
# We can get printed results objects where the baseline is
# exactly 0 (and omitted) and the test is slightly non-zero.
@@ -820,12 +958,13 @@ def filter_file_contents(self, lines, abstol=None):
# results objects and remote them if they are within
# tolerance of 0
if (
- len(item_list) == 2
- and item_list[0] == 'Value:'
- and type(item_list[1]) is float
- and abs(item_list[1]) < (abstol or 0)
- and len(filtered[-1]) == 1
- and filtered[-1][0][-1] == ':'
+ len(item_list) == 3
+ and item_list[0] == 'Value'
+ and item_list[1] == ':'
+ and type(item_list[2]) is float
+ and abs(item_list[2]) < (abstol or 0)
+ and len(filtered[-1]) == 2
+ and filtered[-1][1] == ':'
):
filtered.pop()
else:
@@ -833,7 +972,7 @@ def filter_file_contents(self, lines, abstol=None):
return filtered
- def compare_baseline(self, test_output, baseline, abstol=1e-6, reltol=None):
+ def compare_baseline(self, test_output, baseline, abstol=1e-6, reltol=1e-8):
# Filter files independently and then compare filtered contents
out_filtered = self.filter_file_contents(
test_output.strip().split('\n'), abstol
diff --git a/pyomo/contrib/__init__.py b/pyomo/contrib/__init__.py
index a4a626013c4..e8ba473eab1 100644
--- a/pyomo/contrib/__init__.py
+++ b/pyomo/contrib/__init__.py
@@ -1,10 +1,25 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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.
# ___________________________________________________________________________
+
+#
+# declare deprecation paths for removed modules and attributes
+#
+from pyomo.common.deprecation import moved_module
+
+moved_module(
+ "pyomo.contrib.simplemodel",
+ "pyomocontrib_simplemodel",
+ msg="The use of pyomo.contrib.simplemodel is deprecated. "
+ "This capability is now supported in the pyomocontrib_simplemodel "
+ "package, which is included in the pyomo_community distribution.",
+ version='5.6.9',
+)
+del moved_module
diff --git a/pyomo/contrib/alternative_solutions/README.md b/pyomo/contrib/alternative_solutions/README.md
new file mode 100644
index 00000000000..b6e387aceee
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/README.md
@@ -0,0 +1,8 @@
+# alternative_solutions
+
+pyomo.contrib.alternative_solutions is a collection of functions that
+that generate a set of alternative (near-)optimal solutions
+(AOS). These functions rely on a pyomo solver to search for solutions,
+and they iteratively adapt the search process to find a variety of
+alternative solutions.
+
diff --git a/pyomo/contrib/alternative_solutions/__init__.py b/pyomo/contrib/alternative_solutions/__init__.py
new file mode 100644
index 00000000000..ead886ae0f8
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/__init__.py
@@ -0,0 +1,20 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.contrib.alternative_solutions.aos_utils import logcontext
+from pyomo.contrib.alternative_solutions.solution import Solution
+from pyomo.contrib.alternative_solutions.solnpool import gurobi_generate_solutions
+from pyomo.contrib.alternative_solutions.balas import enumerate_binary_solutions
+from pyomo.contrib.alternative_solutions.obbt import (
+ obbt_analysis,
+ obbt_analysis_bounds_and_solutions,
+)
+from pyomo.contrib.alternative_solutions.lp_enum import enumerate_linear_solutions
diff --git a/pyomo/contrib/alternative_solutions/aos_utils.py b/pyomo/contrib/alternative_solutions/aos_utils.py
new file mode 100644
index 00000000000..c2efbf934b3
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/aos_utils.py
@@ -0,0 +1,304 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+from contextlib import contextmanager
+
+from pyomo.common.dependencies import numpy as numpy, numpy_available
+
+if numpy_available:
+ import numpy.random
+ from numpy.linalg import norm
+
+import pyomo.environ as pyo
+from pyomo.common.modeling import unique_component_name
+from pyomo.common.collections import ComponentSet
+import pyomo.util.vars_from_expressions as vfe
+
+
+@contextmanager
+def logcontext(level):
+ """
+ This context manager is used to dynamically set the specified logging level
+ and then execute a block of code using that logging level. When the context is
+ deleted, the logging level is reset to the original value.
+
+ Examples
+ --------
+ >>> with logcontext(logging.INFO):
+ ... logging.debug("This will not be printed")
+ ... logging.info("This will be printed")
+
+ """
+ logger = logging.getLogger()
+ current_level = logger.getEffectiveLevel()
+ logger.setLevel(level)
+ try:
+ yield
+ finally:
+ logger.setLevel(current_level)
+
+
+def get_active_objective(model):
+ """
+ Finds and returns the active objective function for a model. Currently
+ assume that there is exactly one active objective.
+ """
+
+ active_objs = list(model.component_data_objects(pyo.Objective, active=True))
+ assert (
+ len(active_objs) == 1
+ ), "Model has {} active objective functions, exactly one is required.".format(
+ len(active_objs)
+ )
+
+ return active_objs[0]
+
+
+def _add_aos_block(model, name="_aos_block"):
+ """Adds an alternative optimal solution block with a unique name."""
+ aos_block = pyo.Block()
+ model.add_component(unique_component_name(model, name), aos_block)
+ return aos_block
+
+
+def _add_objective_constraint(
+ aos_block, objective, objective_value, rel_opt_gap, abs_opt_gap
+):
+ """
+ Adds a relative and/or absolute objective function constraint to the
+ specified block.
+ """
+
+ assert (
+ rel_opt_gap is None or rel_opt_gap >= 0.0
+ ), "rel_opt_gap must be None or >= 0.0"
+ assert (
+ abs_opt_gap is None or abs_opt_gap >= 0.0
+ ), "abs_opt_gap must be None or >= 0.0"
+
+ objective_constraints = []
+
+ objective_is_min = objective.is_minimizing()
+ objective_expr = objective.expr
+
+ objective_sense = -1
+ if objective_is_min:
+ objective_sense = 1
+
+ if rel_opt_gap is not None:
+ objective_cutoff = objective_value + objective_sense * rel_opt_gap * abs(
+ objective_value
+ )
+
+ if objective_is_min:
+ aos_block.optimality_tol_rel = pyo.Constraint(
+ expr=objective_expr <= objective_cutoff
+ )
+ else:
+ aos_block.optimality_tol_rel = pyo.Constraint(
+ expr=objective_expr >= objective_cutoff
+ )
+ objective_constraints.append(aos_block.optimality_tol_rel)
+
+ if abs_opt_gap is not None:
+ objective_cutoff = objective_value + objective_sense * abs_opt_gap
+
+ if objective_is_min:
+ aos_block.optimality_tol_abs = pyo.Constraint(
+ expr=objective_expr <= objective_cutoff
+ )
+ else:
+ aos_block.optimality_tol_abs = pyo.Constraint(
+ expr=objective_expr >= objective_cutoff
+ )
+ objective_constraints.append(aos_block.optimality_tol_abs)
+
+ return objective_constraints
+
+
+if numpy_available:
+ rng = numpy.random.default_rng(9283749387)
+else:
+ rng = None
+
+
+def _set_numpy_rng(seed):
+ global rng
+ rng = numpy.random.default_rng(seed)
+
+
+def _get_random_direction(num_dimensions, iterations=1000, min_norm=1e-4):
+ """
+ Get a unit vector of dimension num_dimensions by sampling from and
+ normalizing a standard multivariate Gaussian distribution.
+ """
+ for idx in range(iterations):
+ samples = rng.normal(size=num_dimensions)
+ samples_norm = norm(samples)
+ if samples_norm > min_norm:
+ return samples / samples_norm
+ raise Exception( # pragma: no cover
+ (
+ "Generated {} sequential Gaussian draws with a norm of "
+ "less than {}.".format(iterations, min_norm)
+ )
+ )
+
+
+def _filter_model_variables(
+ variable_set,
+ var_generator,
+ include_continuous=True,
+ include_binary=True,
+ include_integer=True,
+ include_fixed=False,
+):
+ """
+ Filters variables from a variable generator and adds them to a set.
+ """
+ for var in var_generator:
+ if var in variable_set or (var.is_fixed() and not include_fixed):
+ continue
+ if (
+ (var.is_continuous() and include_continuous)
+ or (var.is_binary() and include_binary)
+ or (var.is_integer() and include_integer)
+ ):
+ variable_set.add(var)
+
+
+def get_model_variables(
+ model,
+ components=None,
+ include_continuous=True,
+ include_binary=True,
+ include_integer=True,
+ include_fixed=False,
+):
+ """Gathers and returns all variables or a subset of variables from a
+ Pyomo model.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model.
+ components: None or a collection of Pyomo components
+ The components from which variables should be collected. None
+ indicates that all variables will be included. Alternatively, a
+ collection of Pyomo Blocks, Constraints, or Variables (indexed or
+ non-indexed) from which variables will be gathered can be provided.
+ If a Block is provided, all variables associated with constraints
+ in that that block and its sub-blocks will be returned. To exclude
+ sub-blocks, a tuple element with the format (Block, False) can be
+ used.
+ include_continuous : boolean
+ Boolean indicating that continuous variables should be included.
+ include_binary : boolean
+ Boolean indicating that binary variables should be included.
+ include_integer : boolean
+ Boolean indicating that integer variables should be included.
+ include_fixed : boolean
+ Boolean indicating that fixed variables should be included.
+
+ Returns
+ -------
+ variable_set
+ A Pyomo ComponentSet containing _GeneralVarData variables.
+
+ """
+
+ component_list = (pyo.Objective, pyo.Constraint)
+ variable_set = ComponentSet()
+ if components == None:
+ var_generator = vfe.get_vars_from_components(
+ model, component_list, include_fixed=include_fixed
+ )
+ _filter_model_variables(
+ variable_set,
+ var_generator,
+ include_continuous,
+ include_binary,
+ include_integer,
+ include_fixed,
+ )
+ else:
+ for comp in components:
+ if hasattr(comp, "ctype") and comp.ctype == pyo.Block:
+ blocks = comp.values() if comp.is_indexed() else (comp,)
+ for item in blocks:
+ variables = vfe.get_vars_from_components(
+ item, component_list, include_fixed=include_fixed
+ )
+ _filter_model_variables(
+ variable_set,
+ variables,
+ include_continuous,
+ include_binary,
+ include_integer,
+ include_fixed,
+ )
+ elif (
+ isinstance(comp, tuple)
+ and hasattr(comp[0], "ctype")
+ and comp[0].ctype == pyo.Block
+ ):
+ block = comp[0]
+ descend_into = pyo.Block if comp[1] else False
+ blocks = block.values() if block.is_indexed() else (block,)
+ for item in blocks:
+ variables = vfe.get_vars_from_components(
+ item,
+ component_list,
+ include_fixed=include_fixed,
+ descend_into=descend_into,
+ )
+ _filter_model_variables(
+ variable_set,
+ variables,
+ include_continuous,
+ include_binary,
+ include_integer,
+ include_fixed,
+ )
+ elif hasattr(comp, "ctype") and comp.ctype in component_list:
+ constraints = comp.values() if comp.is_indexed() else (comp,)
+ for item in constraints:
+ variables = pyo.expr.identify_variables(
+ item.expr, include_fixed=include_fixed
+ )
+ _filter_model_variables(
+ variable_set,
+ variables,
+ include_continuous,
+ include_binary,
+ include_integer,
+ include_fixed,
+ )
+ elif hasattr(comp, "ctype") and comp.ctype == pyo.Var:
+ variables = comp.values() if comp.is_indexed() else (comp,)
+ _filter_model_variables(
+ variable_set,
+ variables,
+ include_continuous,
+ include_binary,
+ include_integer,
+ include_fixed,
+ )
+ else: # pragma: no cover
+ logger.info(
+ ("No variables added for unrecognized component {}.").format(comp)
+ )
+
+ return variable_set
diff --git a/pyomo/contrib/alternative_solutions/balas.py b/pyomo/contrib/alternative_solutions/balas.py
new file mode 100644
index 00000000000..e0de7a8f392
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/balas.py
@@ -0,0 +1,260 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+import pyomo.environ as pyo
+from pyomo.common.collections import ComponentSet
+from pyomo.contrib.alternative_solutions import Solution
+import pyomo.contrib.alternative_solutions.aos_utils as aos_utils
+
+
+def enumerate_binary_solutions(
+ model,
+ *,
+ num_solutions=10,
+ variables=None,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ search_mode="optimal",
+ solver="gurobi",
+ solver_options={},
+ tee=False,
+ seed=None,
+):
+ """
+ Finds alternative optimal solutions for a binary problem using no-good
+ cuts.
+
+ This function implements a no-good cuts technique inheriting from
+ Balas's work on Canonical Cuts [BJ72]_.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model
+ num_solutions : int
+ The maximum number of solutions to generate.
+ variables: None or a collection of Pyomo _GeneralVarData variables
+ The variables for which bounds will be generated. None indicates
+ that all variables will be included. Alternatively, a collection of
+ _GenereralVarData variables can be provided.
+ rel_opt_gap : float or None
+ The relative optimality gap for the original objective for which
+ variable bounds will be found. None indicates that a relative gap
+ constraint will not be added to the model.
+ abs_opt_gap : float or None
+ The absolute optimality gap for the original objective for which
+ variable bounds will be found. None indicates that an absolute gap
+ constraint will not be added to the model.
+ search_mode : 'optimal', 'random', or 'hamming'
+ Indicates the mode that is used to generate alternative solutions.
+ The optimal mode finds the next best solution. The random mode
+ finds an alternative solution in the direction of a random ray. The
+ hamming mode iteratively finds solution that maximize the hamming
+ distance from previously discovered solutions.
+ solver : string
+ The solver to be used.
+ solver_options : dict
+ Solver option-value pairs to be passed to the solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+ seed : int
+ Optional integer seed for the numpy random number generator
+
+ Returns
+ -------
+ solutions
+ A list of Solution objects.
+ [Solution]
+
+ """
+ logger.info("STARTING NO-GOOD CUT ANALYSIS")
+
+ assert search_mode in [
+ "optimal",
+ "random",
+ "hamming",
+ ], 'search mode must be "optimal", "random", or "hamming".'
+
+ if seed is not None:
+ aos_utils._set_numpy_rng(seed)
+
+ all_variables = aos_utils.get_model_variables(model, include_fixed=True)
+ if variables == None:
+ binary_variables = [
+ var for var in all_variables if var.is_binary() and not var.is_fixed()
+ ]
+ logger.debug(
+ "Analysis using %d binary variables: %s"
+ % (len(binary_variables), " ".join(var.name for var in binary_variables))
+ )
+ else:
+ binary_variables = ComponentSet()
+ non_binary_variables = []
+ for var in variables:
+ if var.is_binary():
+ binary_variables.add(var)
+ else: # pragma: no cover
+ non_binary_variables.append(var.name)
+ if len(non_binary_variables) > 0:
+ logger.warn(
+ (
+ "Warning: The following non-binary variables were included"
+ "in the variable list and will be ignored:"
+ )
+ )
+ logger.warn(", ".join(non_binary_variables))
+
+ orig_objective = aos_utils.get_active_objective(model)
+
+ if len(binary_variables) == 0:
+ logger.warn("No binary variables found!")
+
+ #
+ # Setup solver
+ #
+ opt = pyo.SolverFactory(solver)
+ opt.available()
+ for parameter, value in solver_options.items():
+ opt.options[parameter] = value
+ #
+ # Appsi-specific configurations
+ #
+ use_appsi = False
+ if "appsi" in solver:
+ use_appsi = True
+ opt.update_config.update_constraints = False
+ opt.update_config.check_for_new_or_removed_constraints = True
+ opt.update_config.check_for_new_or_removed_vars = False
+ opt.update_config.check_for_new_or_removed_params = False
+ opt.update_config.update_vars = False
+ opt.update_config.update_params = False
+ opt.update_config.update_named_expressions = False
+ opt.update_config.treat_fixed_vars_as_params = False
+
+ if search_mode == "hamming":
+ opt.update_config.check_for_new_objective = True
+ opt.update_config.update_objective = True
+ elif search_mode == "random":
+ opt.update_config.check_for_new_objective = True
+ opt.update_config.update_objective = False
+ else:
+ opt.update_config.check_for_new_objective = False
+ opt.update_config.update_objective = False
+
+ #
+ # Initial solve of the model
+ #
+ logger.info("Performing initial solve of model.")
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ status = results.solver.status
+ if not pyo.check_optimal_termination(results):
+ condition = results.solver.termination_condition
+ raise Exception(
+ (
+ "No-good cut analysis cannot be applied, "
+ "SolverStatus = {}, "
+ "TerminationCondition = {}"
+ ).format(status.value, condition.value)
+ )
+
+ model.solutions.load_from(results)
+ orig_objective_value = pyo.value(orig_objective)
+ logger.info("Found optimal solution, value = {}.".format(orig_objective_value))
+ solutions = [Solution(model, all_variables, objective=orig_objective)]
+ #
+ # Return just this solution if there are no binary variables
+ #
+ if len(binary_variables) == 0:
+ return solutions
+
+ aos_block = aos_utils._add_aos_block(model, name="_balas")
+ logger.info("Added block {} to the model.".format(aos_block))
+ aos_block.no_good_cuts = pyo.ConstraintList()
+ aos_utils._add_objective_constraint(
+ aos_block, orig_objective, orig_objective_value, rel_opt_gap, abs_opt_gap
+ )
+
+ if search_mode in ["random", "hamming"]:
+ orig_objective.deactivate()
+
+ solution_number = 2
+ while solution_number <= num_solutions:
+
+ expr = 0
+ for var in binary_variables:
+ if var.value > 0.5:
+ expr += 1 - var
+ else:
+ expr += var
+
+ aos_block.no_good_cuts.add(expr=expr >= 1)
+
+ if search_mode == "hamming":
+ if hasattr(aos_block, "hamming_objective"):
+ aos_block.hamming_objective.expr += expr
+ if use_appsi and opt.update_config.check_for_new_objective:
+ opt.update_config.check_for_new_objective = False
+ else:
+ aos_block.hamming_objective = pyo.Objective(
+ expr=expr, sense=pyo.maximize
+ )
+
+ elif search_mode == "random":
+ if hasattr(aos_block, "random_objective"):
+ aos_block.del_component("random_objective")
+ vector = aos_utils._get_random_direction(len(binary_variables))
+ idx = 0
+ expr = 0
+ for var in binary_variables:
+ expr += vector[idx] * var
+ idx += 1
+ aos_block.random_objective = pyo.Objective(expr=expr, sense=pyo.maximize)
+
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ status = results.solver.status
+ condition = results.solver.termination_condition
+ if pyo.check_optimal_termination(results):
+ model.solutions.load_from(results)
+ orig_obj_value = pyo.value(orig_objective)
+ logger.info(
+ "Iteration {}: objective = {}".format(solution_number, orig_obj_value)
+ )
+ solutions.append(Solution(model, all_variables, objective=orig_objective))
+ solution_number += 1
+ elif (
+ condition == pyo.TerminationCondition.infeasibleOrUnbounded
+ or condition == pyo.TerminationCondition.infeasible
+ ):
+ logger.info(
+ "Iteration {}: Infeasible, no additional binary solutions.".format(
+ solution_number
+ )
+ )
+ break
+ else: # pragma: no cover
+ logger.info(
+ (
+ "Iteration {}: Unexpected condition, SolverStatus = {}, "
+ "TerminationCondition = {}"
+ ).format(solution_number, status.value, condition.value)
+ )
+ break
+
+ aos_block.deactivate()
+ orig_objective.activate()
+
+ logger.info("COMPLETED NO-GOOD CUT ANALYSIS")
+
+ return solutions
diff --git a/pyomo/contrib/alternative_solutions/lp_enum.py b/pyomo/contrib/alternative_solutions/lp_enum.py
new file mode 100644
index 00000000000..b943314a708
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/lp_enum.py
@@ -0,0 +1,330 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+import pyomo.environ as pyo
+from pyomo.contrib.alternative_solutions import (
+ aos_utils,
+ shifted_lp,
+ solution,
+ solnpool,
+)
+from pyomo.contrib import appsi
+
+
+def enumerate_linear_solutions(
+ model,
+ *,
+ num_solutions=10,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ zero_threshold=1e-5,
+ search_mode="optimal",
+ solver="gurobi",
+ solver_options={},
+ tee=False,
+ seed=None,
+):
+ """
+ Finds alternative optimal solutions a (mixed-integer) linear program.
+
+ This function implements the technique described here:
+
+ S. Lee, C. Phalakornkule, M.M. Domach, and I.E. Grossmann,
+ "Recursive MILP model for finding all the alternative optima in LP
+ models for metabolic networks", Computers and Chemical Engineering,
+ 24 (2000) 711-716.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model
+ num_solutions : int
+ The maximum number of solutions to generate.
+ rel_opt_gap : float or None
+ The relative optimality gap for the original objective for which
+ variable bounds will be found. None indicates that a relative gap
+ constraint will not be added to the model.
+ abs_opt_gap : float or None
+ The absolute optimality gap for the original objective for which
+ variable bounds will be found. None indicates that an absolute gap
+ constraint will not be added to the model.
+ zero_threshold: float
+ The threshold for which a continuous variables' value is considered
+ to be equal to zero.
+ search_mode : 'optimal', 'random', or 'norm'
+ Indicates the mode that is used to generate alternative solutions.
+ The optimal mode finds the next best solution. The random mode
+ finds an alternative solution in the direction of a random ray. The
+ norm mode iteratively finds solution that maximize the L2 distance
+ from previously discovered solutions.
+ solver : string
+ The solver to be used.
+ solver_options : dict
+ Solver option-value pairs to be passed to the solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+ seed : int
+ Optional integer seed for the numpy random number generator
+
+ Returns
+ -------
+ solutions
+ A list of Solution objects.
+ [Solution]
+ """
+ logger.info("STARTING LP ENUMERATION ANALYSIS")
+
+ assert search_mode in [
+ "optimal",
+ "random",
+ "norm",
+ ], 'search mode must be "optimal", "random", or "norm".'
+ # TODO: Implement the random and norm objectives. I think it is sufficient
+ # to only consider the cb.var_lower variables in the objective for these two
+ # cases. The cb.var_upper variables are directly linked to these to diversity
+ # in one implies diversity in the other. Diversity in the cb.basic_slack
+ # variables doesn't really matter since we only really care about diversity
+ # in the original problem and not in the slack space (I think)
+
+ all_variables = aos_utils.get_model_variables(model)
+ # else:
+ # binary_variables = ComponentSet()
+ # non_binary_variables = []
+ # for var in variables:
+ # if var.is_binary():
+ # binary_variables.append(var)
+ # else:
+ # non_binary_variables.append(var.name)
+ # if len(non_binary_variables) > 0:
+ # logger.warn(('Warning: The following non-binary variables were included'
+ # 'in the variable list and will be ignored:'))
+ # logger.warn(", ".join(non_binary_variables))
+ # all_variables = aos_utils.get_model_variables(model, None,
+ # include_fixed=True)
+
+ # TODO: Relax this if possible - Should allow for the mixed-binary case
+ for var in all_variables:
+ assert var.is_continuous(), "Model must be an LP"
+
+ use_appsi = False
+ if "appsi" in solver:
+ use_appsi = True
+ opt = appsi.solvers.Gurobi()
+ opt.config.load_solution = False
+ opt.config.stream_solver = tee
+ opt.update_config.check_for_new_or_removed_constraints = True
+ opt.update_config.update_constraints = False
+ opt.update_config.check_for_new_or_removed_vars = True
+ opt.update_config.check_for_new_or_removed_params = False
+ opt.update_config.update_vars = False
+ opt.update_config.update_params = False
+ opt.update_config.update_named_expressions = False
+ opt.update_config.treat_fixed_vars_as_params = False
+
+ if search_mode == "norm":
+ opt.update_config.check_for_new_objective = True
+ opt.update_config.update_objective = True
+ elif search_mode == "random":
+ opt.update_config.check_for_new_objective = True
+ opt.update_config.update_objective = False
+ else:
+ opt.update_config.check_for_new_objective = False
+ opt.update_config.update_objective = False
+ for parameter, value in solver_options.items():
+ opt.gurobi_options[parameter] = value
+ else:
+ opt = pyo.SolverFactory(solver)
+ opt.available()
+ for parameter, value in solver_options.items():
+ opt.options[parameter] = value
+ if solver == "gurobi":
+ # Disable gurobi heuristics, which can return
+ # solutions not at a vertex
+ opt.options["Heuristics"] = 0.0
+
+ logger.info("Performing initial solve of model.")
+
+ if use_appsi:
+ results = opt.solve(model)
+ condition = results.termination_condition
+ optimal_tc = appsi.base.TerminationCondition.optimal
+ else:
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ condition = results.solver.termination_condition
+ optimal_tc = pyo.TerminationCondition.optimal
+ if condition != optimal_tc:
+ raise Exception(
+ (
+ "Model could not be solved. LP enumeration analysis "
+ "cannot be applied, "
+ "TerminationCondition = {}"
+ ).format(condition.value)
+ )
+ if use_appsi:
+ results.solution_loader.load_vars(solution_number=0)
+ else:
+ model.solutions.load_from(results)
+
+ orig_objective = aos_utils.get_active_objective(model)
+ orig_objective_value = pyo.value(orig_objective)
+ logger.info("Found optimal solution, value = {}.".format(orig_objective_value))
+
+ aos_block = aos_utils._add_aos_block(model, name="_lp_enum")
+ aos_utils._add_objective_constraint(
+ aos_block, orig_objective, orig_objective_value, rel_opt_gap, abs_opt_gap
+ )
+ logger.info("Added block {} to the model.".format(aos_block))
+
+ canon_block = shifted_lp.get_shifted_linear_model(model)
+ cb = canon_block
+
+ # Set K
+ cb.iteration = pyo.Set(pyo.PositiveIntegers)
+
+ # w variables
+ cb.basic_lower = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+ cb.basic_upper = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+ cb.basic_slack = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+
+ # w upper bounds constraints (Eqn (3))
+ cb.bound_lower = pyo.Constraint(pyo.Any)
+ cb.bound_upper = pyo.Constraint(pyo.Any)
+ cb.bound_slack = pyo.Constraint(pyo.Any)
+
+ # non-zero basic variable no-good cut set
+ cb.cut_set = pyo.Constraint(pyo.PositiveIntegers)
+
+ # [ (continuous, binary, constraint) ]
+ variable_groups = [
+ (cb.var_lower, cb.basic_lower, cb.bound_lower),
+ (cb.var_upper, cb.basic_upper, cb.bound_upper),
+ (cb.slack_vars, cb.basic_slack, cb.bound_slack),
+ ]
+
+ solution_number = 1
+ solutions = []
+ while solution_number <= num_solutions:
+ logger.info("Solving Iteration {}: ".format(solution_number), end="")
+
+ if logger.isEnabledFor(logging.DEBUG):
+ model.pprint()
+ if use_appsi:
+ results = opt.solve(model)
+ condition = results.termination_condition
+ else:
+ results = opt.solve(cb, tee=tee, load_solutions=False)
+ condition = results.solver.termination_condition
+
+ if condition == optimal_tc:
+ if use_appsi:
+ results.solution_loader.load_vars(solution_number=0)
+ else:
+ model.solutions.load_from(results)
+
+ for var, index in cb.var_map.items():
+ var.set_value(var.lb + cb.var_lower[index].value)
+ sol = solution.Solution(model, all_variables, objective=orig_objective)
+ solutions.append(sol)
+ orig_objective_value = sol.objective[1]
+
+ if logger.isEnabledFor(logging.INFO):
+ logger.info("Solved, objective = {}".format(orig_objective_value))
+ for var, index in cb.var_map.items():
+ logger.info(
+ "{} = {}".format(var.name, var.lb + cb.var_lower[index].value)
+ )
+ if logger.isEnabledFor(logging.DEBUG):
+ model.display()
+
+ if hasattr(cb, "force_out"):
+ cb.del_component("force_out")
+ if hasattr(cb, "link_in_out"):
+ cb.del_component("link_in_out")
+ if hasattr(cb, "basic_last_lower"):
+ cb.del_component("basic_last_lower")
+ if hasattr(cb, "basic_last_upper"):
+ cb.del_component("basic_last_upper")
+ if hasattr(cb, "basic_last_slack"):
+ cb.del_component("basic_last_slack")
+
+ cb.link_in_out = pyo.Constraint(pyo.Any)
+ # y variables
+ cb.basic_last_lower = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+ cb.basic_last_upper = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+ cb.basic_last_slack = pyo.Var(pyo.Any, domain=pyo.Binary, dense=False)
+ basic_last_list = [
+ cb.basic_last_lower,
+ cb.basic_last_upper,
+ cb.basic_last_slack,
+ ]
+
+ # Number of variables with non-zero values
+ num_non_zero = 0
+ # This expression is used to ensure that at least one of the non-zero basic
+ # variables in the previous solution is selected.
+ force_out_expr = -1
+ # This expression is used to ensure that at most (# non-zero basic variables)-1
+ # binary choice variables can be selected.
+ non_zero_basic_expr = 1
+ for idx in range(len(variable_groups)):
+ continuous_var, binary_var, constraint = variable_groups[idx]
+ for var in continuous_var:
+ if continuous_var[var].value > zero_threshold:
+ num_non_zero += 1
+
+ # Eqn (3): if binary choice variable is not selected, then
+ # continuous variable is zero.
+ constraint[var] = (
+ continuous_var[var]
+ <= continuous_var[var].ub * binary_var[var]
+ )
+ non_zero_basic_expr += binary_var[var]
+ basic_var = basic_last_list[idx][var]
+ force_out_expr += basic_var
+ # Eqn (4): if binary choice variable is selected, then
+ # basic variable is zero
+ cb.link_in_out[var] = basic_var + binary_var[var] <= 1
+ # Eqn (1): at least one of the non-zero basic variables in the
+ # previous solution is selected
+ cb.force_out = pyo.Constraint(expr=force_out_expr >= 0)
+ # Eqn (2): At most (# non-zero basic variables)-1 binary choice
+ # variables can be selected
+ cb.cut_set[solution_number] = non_zero_basic_expr <= num_non_zero
+
+ solution_number += 1
+ elif (
+ condition == pyo.TerminationCondition.infeasibleOrUnbounded
+ or condition == pyo.TerminationCondition.infeasible
+ ):
+ logger.info("Infeasible, all alternative solutions have been found.")
+ break
+ else:
+ logger.info(
+ (
+ "Unexpected solver condition. Stopping LP enumeration. "
+ "SolverStatus = {}, TerminationCondition = {}"
+ ).format(results.solver.status.value, condition.value)
+ )
+ break
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.debug("")
+ logger.debug("=" * 80)
+ logger.debug("")
+
+ model.del_component("aos_block")
+
+ logger.info("COMPLETED LP ENUMERATION ANALYSIS")
+
+ return solutions
diff --git a/pyomo/contrib/alternative_solutions/lp_enum_solnpool.py b/pyomo/contrib/alternative_solutions/lp_enum_solnpool.py
new file mode 100644
index 00000000000..680599eda8b
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/lp_enum_solnpool.py
@@ -0,0 +1,235 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+from pyomo.common.dependencies import attempt_import
+
+gurobipy, gurobi_available = attempt_import("gurobipy")
+
+import pyomo.environ as pyo
+import pyomo.common.errors
+from pyomo.contrib.alternative_solutions import aos_utils, shifted_lp, solution
+from pyomo.contrib import appsi
+
+
+class NoGoodCutGenerator:
+ def __init__(
+ self,
+ model,
+ variable_groups,
+ zero_threshold,
+ orig_model,
+ all_variables,
+ orig_objective,
+ num_solutions,
+ ):
+ self.model = model
+ self.zero_threshold = zero_threshold
+ self.variable_groups = variable_groups
+ self.variables = aos_utils.get_model_variables(model)
+ self.orig_model = orig_model
+ self.all_variables = all_variables
+ self.orig_objective = orig_objective
+ self.solutions = []
+ self.num_solutions = num_solutions
+
+ def cut_generator_callback(self, cb_m, cb_opt, cb_where):
+ if cb_where == gurobipy.GRB.Callback.MIPSOL:
+ cb_opt.cbGetSolution(vars=self.variables)
+ logger.info("***FOUND SOLUTION***")
+
+ for var, index in self.model.var_map.items():
+ var.set_value(var.lb + self.model.var_lower[index].value)
+ sol = solution.Solution(
+ self.orig_model, self.all_variables, objective=self.orig_objective
+ )
+ self.solutions.append(sol)
+
+ if len(self.solutions) >= self.num_solutions:
+ cb_opt._solver_model.terminate()
+ num_non_zero = 0
+ non_zero_basic_expr = 1
+ for idx in range(len(self.variable_groups)):
+ continuous_var, binary_var = self.variable_groups[idx]
+ for var in continuous_var:
+ if continuous_var[var].value > self.zero_threshold:
+ num_non_zero += 1
+ non_zero_basic_expr += binary_var[var]
+ # TODO: JLG - If we want to add the mixed binary case, I think we
+ # need to do it here. Essentially we would want to continue to
+ # build up the num_non_zero as follows
+ # for binary in binary_vars:
+ # if binary.value > 0.5:
+ # num_non_zero += 1 - binary
+ # else:
+ # num_non_zero += binary
+ new_con = self.model.cl.add(non_zero_basic_expr <= num_non_zero)
+ cb_opt.cbLazy(new_con)
+
+
+def enumerate_linear_solutions_soln_pool(
+ model,
+ num_solutions=10,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ zero_threshold=1e-5,
+ solver_options={},
+ tee=False,
+):
+ """
+ Finds alternative optimal solutions for a (mixed-binary) linear program
+ using Gurobi's solution pool feature.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model
+ num_solutions : int
+ The maximum number of solutions to generate.
+ variables: None or a collection of Pyomo _GeneralVarData variables
+ The variables for which bounds will be generated. None indicates
+ that all variables will be included. Alternatively, a collection of
+ _GenereralVarData variables can be provided.
+ rel_opt_gap : float or None
+ The relative optimality gap for the original objective for which
+ variable bounds will be found. None indicates that a relative gap
+ constraint will not be added to the model.
+ abs_opt_gap : float or None
+ The absolute optimality gap for the original objective for which
+ variable bounds will be found. None indicates that an absolute gap
+ constraint will not be added to the model.
+ zero_threshold: float
+ The threshold for which a continuous variables' value is considered
+ to be equal to zero.
+ solver_options : dict
+ Solver option-value pairs to be passed to the solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+
+ Returns
+ -------
+ solutions
+ A list of Solution objects.
+ [Solution]
+ """
+ logger.info("STARTING LP ENUMERATION ANALYSIS USING GUROBI SOLUTION POOL")
+ #
+ # Setup gurobi
+ #
+ if not gurobi_available:
+ raise pyomo.common.errors.ApplicationError(f"Solver (gurobi) not available")
+
+ all_variables = aos_utils.get_model_variables(model)
+ for var in all_variables:
+ if var.is_integer():
+ raise pyomo.common.errors.ApplicationError(
+ f"The enumerate_linear_solutions_soln_pool() function cannot be used with models that contain discrete variables"
+ )
+
+ opt = pyo.SolverFactory("gurobi")
+ if not opt.available(exception_flag=False):
+ raise ValueError(solver + " is not available")
+ for parameter, value in solver_options.items():
+ opt.options[parameter] = value
+
+ logger.info("Performing initial solve of model.")
+ results = opt.solve(model, tee=tee)
+ status = results.solver.status
+ condition = results.solver.termination_condition
+ if condition != pyo.TerminationCondition.optimal:
+ raise Exception(
+ (
+ "Model could not be solve. LP enumeration analysis "
+ "cannot be applied, SolverStatus = {}, "
+ "TerminationCondition = {}"
+ ).format(status.value, condition.value)
+ )
+
+ orig_objective = aos_utils.get_active_objective(model)
+ orig_objective_value = pyo.value(orig_objective)
+ logger.info("Found optimal solution, value = {}.".format(orig_objective_value))
+
+ aos_block = aos_utils._add_aos_block(model, name="_lp_enum")
+ logger.info("Added block {} to the model.".format(aos_block))
+ aos_utils._add_objective_constraint(
+ aos_block, orig_objective, orig_objective_value, rel_opt_gap, abs_opt_gap
+ )
+
+ canonical_block = shifted_lp.get_shifted_linear_model(model)
+ cb = canonical_block
+ lower_index = list(cb.var_lower.keys())
+ upper_index = list(cb.var_upper.keys())
+
+ # w variables
+ cb.basic_lower = pyo.Var(lower_index, domain=pyo.Binary)
+ cb.basic_upper = pyo.Var(upper_index, domain=pyo.Binary)
+ cb.basic_slack = pyo.Var(cb.slack_index, domain=pyo.Binary)
+
+ # w upper bounds constraints
+ def bound_lower_rule(m, var_index):
+ return (
+ m.var_lower[var_index]
+ <= m.var_lower[var_index].ub * m.basic_lower[var_index]
+ )
+
+ cb.bound_lower = pyo.Constraint(lower_index, rule=bound_lower_rule)
+
+ def bound_upper_rule(m, var_index):
+ return (
+ m.var_upper[var_index]
+ <= m.var_upper[var_index].ub * m.basic_upper[var_index]
+ )
+
+ cb.bound_upper = pyo.Constraint(upper_index, rule=bound_upper_rule)
+
+ def bound_slack_rule(m, var_index):
+ return (
+ m.slack_vars[var_index]
+ <= m.slack_vars[var_index].ub * m.basic_slack[var_index]
+ )
+
+ cb.bound_slack = pyo.Constraint(cb.slack_index, rule=bound_slack_rule)
+
+ cb.cl = pyo.ConstraintList()
+
+ # TODO: If we go the mixed binary route we also want to list the binary variables
+ variable_groups = [
+ (cb.var_lower, cb.basic_lower),
+ (cb.var_upper, cb.basic_upper),
+ (cb.slack_vars, cb.basic_slack),
+ ]
+ cut_generator = NoGoodCutGenerator(
+ cb,
+ variable_groups,
+ zero_threshold,
+ model,
+ all_variables,
+ orig_objective,
+ num_solutions,
+ )
+
+ opt = appsi.solvers.Gurobi()
+ for parameter, value in solver_options.items():
+ opt.gurobi_options[parameter] = value
+ opt.config.stream_solver = True
+ opt.config.load_solution = False
+ opt.gurobi_options["LazyConstraints"] = 1
+ opt.set_instance(cb)
+ opt.set_callback(cut_generator.cut_generator_callback)
+ opt.solve(cb)
+
+ aos_block.deactivate()
+ logger.info("COMPLETED LP ENUMERATION ANALYSIS")
+
+ return cut_generator.solutions
diff --git a/pyomo/contrib/alternative_solutions/obbt.py b/pyomo/contrib/alternative_solutions/obbt.py
new file mode 100644
index 00000000000..3a546347619
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/obbt.py
@@ -0,0 +1,355 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+import pyomo.environ as pyo
+from pyomo.contrib.alternative_solutions import aos_utils
+from pyomo.contrib.alternative_solutions import Solution
+from pyomo.contrib import appsi
+
+
+def obbt_analysis(
+ model,
+ *,
+ variables=None,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ refine_discrete_bounds=False,
+ warmstart=True,
+ solver="gurobi",
+ solver_options={},
+ tee=False,
+):
+ """
+ Calculates the bounds on each variable by solving a series of min and max
+ optimization problems where each variable is used as the objective function
+ This can be applied to any class of problem supported by the selected
+ solver.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model.
+ variables: None or a collection of Pyomo _GeneralVarData variables
+ The variables for which bounds will be generated. None indicates
+ that all variables will be included. Alternatively, a collection of
+ _GenereralVarData variables can be provided.
+ rel_opt_gap : float or None
+ The relative optimality gap for the original objective for which
+ variable bounds will be found. None indicates that a relative gap
+ constraint will not be added to the model.
+ abs_opt_gap : float or None
+ The absolute optimality gap for the original objective for which
+ variable bounds will be found. None indicates that an absolute gap
+ constraint will not be added to the model.
+ refine_discrete_bounds : boolean
+ Boolean indicating that new constraints should be added to the
+ model at each iteration to tighten the bounds for discrete
+ variables.
+ warmstart : boolean
+ Boolean indicating that the solver should be warmstarted from the
+ best previously discovered solution.
+ solver : string
+ The solver to be used.
+ solver_options : dict
+ Solver option-value pairs to be passed to the solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+
+ Returns
+ -------
+ variable_ranges
+ A Pyomo ComponentMap containing the bounds for each variable.
+ {variable: (lower_bound, upper_bound)}. An exception is raised when
+ the solver encountered an issue.
+ """
+ bounds, solns = obbt_analysis_bounds_and_solutions(
+ model,
+ variables=variables,
+ rel_opt_gap=rel_opt_gap,
+ abs_opt_gap=abs_opt_gap,
+ refine_discrete_bounds=refine_discrete_bounds,
+ warmstart=warmstart,
+ solver=solver,
+ solver_options=solver_options,
+ tee=tee,
+ )
+ return bounds
+
+
+def obbt_analysis_bounds_and_solutions(
+ model,
+ *,
+ variables=None,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ refine_discrete_bounds=False,
+ warmstart=True,
+ solver="gurobi",
+ solver_options={},
+ tee=False,
+):
+ """
+ Calculates the bounds on each variable by solving a series of min and max
+ optimization problems where each variable is used as the objective function
+ This can be applied to any class of problem supported by the selected
+ solver.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model.
+ variables: None or a collection of Pyomo _GeneralVarData variables
+ The variables for which bounds will be generated. None indicates
+ that all variables will be included. Alternatively, a collection of
+ _GenereralVarData variables can be provided.
+ rel_opt_gap : float or None
+ The relative optimality gap for the original objective for which
+ variable bounds will be found. None indicates that a relative gap
+ constraint will not be added to the model.
+ abs_opt_gap : float or None
+ The absolute optimality gap for the original objective for which
+ variable bounds will be found. None indicates that an absolute gap
+ constraint will not be added to the model.
+ refine_discrete_bounds : boolean
+ Boolean indicating that new constraints should be added to the
+ model at each iteration to tighten the bounds for discrete
+ variables.
+ warmstart : boolean
+ Boolean indicating that the solver should be warmstarted from the
+ best previously discovered solution.
+ solver : string
+ The solver to be used.
+ solver_options : dict
+ Solver option-value pairs to be passed to the solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+
+ Returns
+ -------
+ variable_ranges
+ A Pyomo ComponentMap containing the bounds for each variable.
+ {variable: (lower_bound, upper_bound)}. An exception is raised when
+ the solver encountered an issue.
+ solutions
+ [Solution]
+ """
+
+ # TODO - parallelization
+
+ logger.info("STARTING OBBT ANALYSIS")
+
+ if warmstart:
+ assert (
+ variables == None
+ ), "Cannot restrict variable list when warmstart is specified"
+ all_variables = aos_utils.get_model_variables(model, include_fixed=False)
+ if variables == None:
+ variable_list = all_variables
+ else:
+ variable_list = list(variables)
+ if warmstart:
+ solutions = pyo.ComponentMap()
+ for var in all_variables:
+ solutions[var] = []
+
+ num_vars = len(variable_list)
+ logger.info(
+ "Analyzing {} variables ({} total solves).".format(num_vars, 2 * num_vars)
+ )
+ orig_objective = aos_utils.get_active_objective(model)
+
+ use_appsi = False
+ if "appsi" in solver:
+ opt = appsi.solvers.Gurobi()
+ for parameter, value in solver_options.items():
+ opt.gurobi_options[parameter] = value
+ opt.config.stream_solver = tee
+ opt.config.load_solution = False
+ results = opt.solve(model)
+ condition = results.termination_condition
+ optimal_tc = appsi.base.TerminationCondition.optimal
+ infeas_or_unbdd_tc = appsi.base.TerminationCondition.infeasibleOrUnbounded
+ unbdd_tc = appsi.base.TerminationCondition.unbounded
+ use_appsi = True
+ else:
+ opt = pyo.SolverFactory(solver)
+ opt.available()
+ for parameter, value in solver_options.items():
+ opt.options[parameter] = value
+ try:
+ results = opt.solve(
+ model, warmstart=warmstart, tee=tee, load_solutions=False
+ )
+ except ValueError:
+ # An exception occurs if the solver does not recognize the warmstart option
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ condition = results.solver.termination_condition
+ optimal_tc = pyo.TerminationCondition.optimal
+ infeas_or_unbdd_tc = pyo.TerminationCondition.infeasibleOrUnbounded
+ unbdd_tc = pyo.TerminationCondition.unbounded
+ logger.info("Performing initial solve of model.")
+
+ if condition != optimal_tc:
+ raise RuntimeError(
+ ("OBBT cannot be applied, " "TerminationCondition = {}").format(
+ condition.value
+ )
+ )
+ if use_appsi:
+ results.solution_loader.load_vars(solution_number=0)
+ else:
+ model.solutions.load_from(results)
+ if warmstart:
+ _add_solution(solutions)
+ orig_objective_value = pyo.value(orig_objective)
+ logger.info("Found optimal solution, value = {}.".format(orig_objective_value))
+ aos_block = aos_utils._add_aos_block(model, name="_obbt")
+ # placeholder for objective
+ aos_block.var_objective = pyo.Objective(expr=0)
+ logger.info("Added block {} to the model.".format(aos_block))
+ obj_constraints = aos_utils._add_objective_constraint(
+ aos_block, orig_objective, orig_objective_value, rel_opt_gap, abs_opt_gap
+ )
+ if refine_discrete_bounds:
+ aos_block.bound_constraints = pyo.ConstraintList()
+ new_constraint = False
+ if len(obj_constraints) > 0:
+ new_constraint = True
+ orig_objective.deactivate()
+
+ if use_appsi:
+ opt.update_config.check_for_new_or_removed_constraints = new_constraint
+ opt.update_config.check_for_new_or_removed_vars = False
+ opt.update_config.check_for_new_or_removed_params = False
+ opt.update_config.check_for_new_objective = True
+ opt.update_config.update_constraints = False
+ opt.update_config.update_vars = False
+ opt.update_config.update_params = False
+ opt.update_config.update_named_expressions = False
+ opt.update_config.update_objective = True
+ opt.update_config.treat_fixed_vars_as_params = False
+
+ variable_bounds = pyo.ComponentMap()
+ solns = [Solution(model, all_variables, objective=orig_objective)]
+
+ senses = [(pyo.minimize, "LB"), (pyo.maximize, "UB")]
+
+ iteration = 1
+ total_iterations = len(senses) * num_vars
+ for idx in range(len(senses)):
+ sense = senses[idx][0]
+ bound_dir = senses[idx][1]
+
+ for var in variable_list:
+ if idx == 0:
+ variable_bounds[var] = [None, None]
+
+ aos_block.var_objective.expr = var
+ aos_block.var_objective.sense = sense
+
+ if warmstart:
+ _update_values(var, bound_dir, solutions)
+
+ if use_appsi:
+ opt.update_config.check_for_new_or_removed_constraints = new_constraint
+ if use_appsi:
+ opt.config.stream_solver = tee
+ results = opt.solve(model)
+ condition = results.termination_condition
+ else:
+ try:
+ results = opt.solve(
+ model, warmstart=warmstart, tee=tee, load_solutions=False
+ )
+ except ValueError:
+ # An exception occurs if the solver does not recognize the warmstart option
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ condition = results.solver.termination_condition
+ new_constraint = False
+
+ if condition == optimal_tc:
+ if use_appsi:
+ results.solution_loader.load_vars(solution_number=0)
+ else:
+ model.solutions.load_from(results)
+ solns.append(Solution(model, all_variables, objective=orig_objective))
+
+ if warmstart:
+ _add_solution(solutions)
+ obj_val = pyo.value(var)
+ variable_bounds[var][idx] = obj_val
+
+ if refine_discrete_bounds and not var.is_continuous():
+ if sense == pyo.minimize and var.lb < obj_val:
+ aos_block.bound_constraints.add(var >= obj_val)
+ new_constraint = True
+
+ if sense == pyo.maximize and var.ub > obj_val:
+ aos_block.bound_constraints.add(var <= obj_val)
+ new_constraint = True
+
+ # An infeasibleOrUnbounded status code will imply the problem is
+ # unbounded since feasibility has been established previously
+ elif condition == infeas_or_unbdd_tc or condition == unbdd_tc:
+ if sense == pyo.minimize:
+ variable_bounds[var][idx] = float("-inf")
+ else:
+ variable_bounds[var][idx] = float("inf")
+ else: # pragma: no cover
+ logger.warn(
+ (
+ "Unexpected condition for the variable {} {} problem."
+ "TerminationCondition = {}"
+ ).format(var.name, bound_dir, condition.value)
+ )
+
+ var_value = variable_bounds[var][idx]
+ logger.info(
+ "Iteration {}/{}: {}_{} = {}".format(
+ iteration, total_iterations, var.name, bound_dir, var_value
+ )
+ )
+
+ if idx == 1:
+ variable_bounds[var] = tuple(variable_bounds[var])
+
+ iteration += 1
+
+ aos_block.deactivate()
+ orig_objective.activate()
+
+ logger.info("COMPLETED OBBT ANALYSIS")
+
+ return variable_bounds, solns
+
+
+def _add_solution(solutions):
+ """Add the current variable values to the solution list."""
+ for var in solutions:
+ solutions[var].append(pyo.value(var))
+
+
+def _update_values(var, bound_dir, solutions):
+ """
+ Set the values of all variables to the best solution seen previously for
+ the current objective function.
+ """
+ if bound_dir == "LB":
+ value = min(solutions[var])
+ else:
+ value = max(solutions[var])
+ idx = solutions[var].index(value)
+ for variable in solutions:
+ variable.set_value(solutions[variable][idx])
diff --git a/pyomo/contrib/alternative_solutions/shifted_lp.py b/pyomo/contrib/alternative_solutions/shifted_lp.py
new file mode 100644
index 00000000000..aff59a1aa99
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/shifted_lp.py
@@ -0,0 +1,229 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import pyomo.environ as pyo
+from pyomo.common.collections import ComponentMap
+from pyomo.gdp.util import clone_without_expression_components
+from pyomo.contrib.fbbt.fbbt import compute_bounds_on_expr
+from pyomo.contrib.alternative_solutions import aos_utils
+
+
+def _get_unique_name(collection, name):
+ """Create a unique name for an item that will be added to a collection."""
+ if name not in collection:
+ return name
+ else:
+ i = 1
+ while "{}_{}".format(name, i) not in collection:
+ i += 1
+ return "{}_{}".format(name, i)
+
+
+def _set_slack_ub(expression, slack_var):
+ """
+ Use FBBT to compute an upper bound for a slack variable on an equality
+ expression."""
+ slack_lb, slack_ub = compute_bounds_on_expr(expression)
+ assert slack_ub >= 0
+ slack_var.setub(slack_ub)
+
+
+def get_shifted_linear_model(model, block=None):
+ """
+ Converts an (MI)LP with bounded (discrete and) continuous variables
+ (l <= x <= u) into a standard form where where all continuous variables
+ are non-negative reals and all constraints are equalities. For a pure LP of
+ the form,
+
+ .. math::
+
+ min/max cx
+ s.t.
+ A_1 * x = b_1
+ A_2 * x <= b_2
+ l <= x <= u
+
+ a problem of the form,
+
+ .. math::
+
+ min/max c'z
+ s.t.
+ Bz = q
+ z >= 0
+
+ will be created and added to the returned block. z consists of var_lower
+ and var_upper variables that are substituted into the original x variables,
+ and slack_vars that are used to convert the original inequalities to
+ equalities. Bounds are provided on all variables in z. For MILPs, only the
+ continuous part of the problem is converted.
+
+ See Lee, Sangbum., C. Phalakornkule, M. Domach, I. Grossmann, Recursive
+ MILP model for finding all the alternate optima in LP models for metabolic
+ networks, Computers & Chemical Engineering, Volume 24, Issues 2–7, 2000,
+ page 712 for additional details.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model
+ block : Block
+ The Pyomo block that the new model should be added to.
+
+ Returns
+ -------
+ block
+ The block that holds the reformulated model.
+ """
+
+ # Gather all variables and confirm the model is bounded
+ all_vars = aos_utils.get_model_variables(model)
+ new_vars = {}
+ all_vars_new = {}
+ var_map = ComponentMap()
+ var_range = {}
+ for var in all_vars:
+ assert var.lb is not None, (
+ "Variable {} does not have a "
+ "lower bound. All variables must be "
+ "bounded.".format(var.name)
+ )
+ assert var.ub is not None, (
+ "Variable {} does not have an "
+ "upper bound. All variables must be "
+ "bounded.".format(var.name)
+ )
+ if var.is_continuous():
+ var_name = _get_unique_name(new_vars.keys(), var.name)
+ new_vars[var_name] = var
+ all_vars_new[var_name] = var
+ var_map[var] = var_name
+ var_range[var_name] = (0, var.ub - var.lb)
+ else:
+ all_vars_new[var.name] = var
+
+ if block is None:
+ block = model
+ shifted_lp = aos_utils._add_aos_block(block, name="_shifted_lp")
+
+ # Replace original variables with shifted lower and upper variables
+ shifted_lp.var_lower = pyo.Var(
+ new_vars.keys(), domain=pyo.NonNegativeReals, bounds=var_range
+ )
+ shifted_lp.var_upper = pyo.Var(
+ new_vars.keys(), domain=pyo.NonNegativeReals, bounds=var_range
+ )
+
+ # Link the shifted lower and upper variables
+ def link_vars_rule(m, var_index):
+ return (
+ m.var_lower[var_index] + m.var_upper[var_index] == m.var_upper[var_index].ub
+ )
+
+ shifted_lp.link_vars = pyo.Constraint(new_vars.keys(), rule=link_vars_rule)
+
+ # Map the lower and upper variables to the original variables and their
+ # lower bounds. This will be used to substitute x with var_lower + x.lb.
+ var_lower_map = {id(var): shifted_lp.var_lower[i] for i, var in new_vars.items()}
+ var_lower_bounds = {id(var): var.lb for var in new_vars.values()}
+ var_zeros = {id(var): 0 for var in all_vars_new.values()}
+
+ # Substitute the new s variables into the objective function
+ # The c_fix_zeros calculation is used to find any constant terms that exist
+ # in the objective expression to avoid double counting
+ active_objective = aos_utils.get_active_objective(model)
+ c_var_lower = clone_without_expression_components(
+ active_objective.expr, substitute=var_lower_map
+ )
+ c_fix_lower = clone_without_expression_components(
+ active_objective.expr, substitute=var_lower_bounds
+ )
+ c_fix_zeros = clone_without_expression_components(
+ active_objective.expr, substitute=var_zeros
+ )
+ shifted_lp.objective = pyo.Objective(
+ expr=c_var_lower - c_fix_zeros + c_fix_lower,
+ name=active_objective.name + "_shifted",
+ sense=active_objective.sense,
+ )
+
+ # Identify all of the shifted constraints and associated slack variables
+ # that will need to be created
+ new_constraints = {}
+ constraint_map = ComponentMap()
+ constraint_type = {}
+ slacks = []
+ for constraint in model.component_data_objects(pyo.Constraint, active=True):
+ if constraint.parent_block() == shifted_lp:
+ continue
+ if constraint.equality:
+ constraint_name = constraint.name + "_equal"
+ constraint_name = _get_unique_name(new_constraints.keys(), constraint.name)
+ new_constraints[constraint_name] = constraint
+ constraint_map[constraint] = constraint_name
+ constraint_type[constraint_name] = 0
+ else:
+ if constraint.lb is not None:
+ constraint_name = constraint.name + "_lower"
+ constraint_name = _get_unique_name(
+ new_constraints.keys(), constraint.name
+ )
+ new_constraints[constraint_name] = constraint
+ constraint_map[constraint] = constraint_name
+ constraint_type[constraint_name] = -1
+ slacks.append(constraint_name)
+ if constraint.ub is not None:
+ constraint_name = constraint.name + "_upper"
+ constraint_name = _get_unique_name(
+ new_constraints.keys(), constraint.name
+ )
+ new_constraints[constraint_name] = constraint
+ constraint_map[constraint] = constraint_name
+ constraint_type[constraint_name] = 1
+ slacks.append(constraint_name)
+ shifted_lp.constraint_index = pyo.Set(initialize=new_constraints.keys())
+ shifted_lp.slack_index = pyo.Set(initialize=slacks)
+ shifted_lp.slack_vars = pyo.Var(shifted_lp.slack_index, domain=pyo.NonNegativeReals)
+ shifted_lp.constraints = pyo.Constraint(shifted_lp.constraint_index)
+
+ for constraint_name, constraint in new_constraints.items():
+ # The c_fix_zeros calculation is used to find any constant terms that
+ # exist in the constraint expression to avoid double counting
+ a_sub_var_lower = clone_without_expression_components(
+ constraint.body, substitute=var_lower_map
+ )
+ a_sub_fix_lower = clone_without_expression_components(
+ constraint.body, substitute=var_lower_bounds
+ )
+ a_sub_fix_zeros = clone_without_expression_components(
+ constraint.body, substitute=var_zeros
+ )
+ b_lower = constraint.lb
+ b_upper = constraint.ub
+ con_type = constraint_type[constraint_name]
+ if con_type == 0:
+ expr = a_sub_var_lower - a_sub_fix_zeros + a_sub_fix_lower - b_lower == 0
+ elif con_type == -1:
+ expr_rhs = a_sub_var_lower - a_sub_fix_zeros + a_sub_fix_lower - b_lower
+ expr = shifted_lp.slack_vars[constraint_name] == expr_rhs
+ _set_slack_ub(expr_rhs, shifted_lp.slack_vars[constraint_name])
+ elif con_type == 1:
+ expr_rhs = b_upper - a_sub_var_lower + a_sub_fix_zeros - a_sub_fix_lower
+ expr = shifted_lp.slack_vars[constraint_name] == expr_rhs
+ _set_slack_ub(expr_rhs, shifted_lp.slack_vars[constraint_name])
+ shifted_lp.constraints[constraint_name] = expr
+
+ shifted_lp.var_map = var_map
+ shifted_lp.new_vars = new_vars
+ shifted_lp.constraint_map = constraint_map
+ shifted_lp.new_constraints = new_constraints
+
+ return shifted_lp
diff --git a/pyomo/contrib/alternative_solutions/solnpool.py b/pyomo/contrib/alternative_solutions/solnpool.py
new file mode 100644
index 00000000000..5c75a6261c3
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/solnpool.py
@@ -0,0 +1,108 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+from pyomo.common.dependencies import attempt_import
+from pyomo.common.errors import ApplicationError
+
+from pyomo.contrib import appsi
+import pyomo.contrib.alternative_solutions.aos_utils as aos_utils
+from pyomo.contrib.alternative_solutions import Solution
+
+
+def gurobi_generate_solutions(
+ model,
+ *,
+ num_solutions=10,
+ rel_opt_gap=None,
+ abs_opt_gap=None,
+ solver_options={},
+ tee=False,
+):
+ """
+ Finds alternative optimal solutions for discrete variables using Gurobi's
+ built-in Solution Pool capability. See the Gurobi Solution Pool
+ documentation for additional details.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model.
+ num_solutions : int
+ The maximum number of solutions to generate. This parameter maps to
+ the PoolSolutions parameter in Gurobi.
+ rel_opt_gap : non-negative float or None
+ The relative optimality gap for allowable alternative solutions.
+ None implies that there is no limit on the relative optimality gap
+ (i.e. that any feasible solution can be considered by Gurobi).
+ This parameter maps to the PoolGap parameter in Gurobi.
+ abs_opt_gap : non-negative float or None
+ The absolute optimality gap for allowable alternative solutions.
+ None implies that there is no limit on the absolute optimality gap
+ (i.e. that any feasible solution can be considered by Gurobi).
+ This parameter maps to the PoolGapAbs parameter in Gurobi.
+ solver_options : dict
+ Solver option-value pairs to be passed to the Gurobi solver.
+ tee : boolean
+ Boolean indicating that the solver output should be displayed.
+
+ Returns
+ -------
+ solutions
+ A list of Solution objects. [Solution]
+ """
+ #
+ # Setup gurobi
+ #
+ opt = appsi.solvers.Gurobi()
+ if not opt.available():
+ raise ApplicationError("Solver (gurobi) not available")
+
+ opt.config.stream_solver = tee
+ opt.config.load_solution = False
+ opt.gurobi_options["PoolSolutions"] = num_solutions
+ opt.gurobi_options["PoolSearchMode"] = 2
+ if rel_opt_gap is not None:
+ opt.gurobi_options["PoolGap"] = rel_opt_gap
+ if abs_opt_gap is not None:
+ opt.gurobi_options["PoolGapAbs"] = abs_opt_gap
+ for parameter, value in solver_options.items():
+ opt.gurobi_options[parameter] = value
+ #
+ # Run gurobi
+ #
+ results = opt.solve(model)
+ condition = results.termination_condition
+ if not (condition == appsi.base.TerminationCondition.optimal):
+ raise ApplicationError(
+ "Model cannot be solved, " "TerminationCondition = {}"
+ ).format(condition.value)
+ #
+ # Collect solutions
+ #
+ solution_count = opt.get_model_attr("SolCount")
+ variables = aos_utils.get_model_variables(model, include_fixed=True)
+ solutions = []
+ for i in range(solution_count):
+ #
+ # Load the i-th solution into the model
+ #
+ results.solution_loader.load_vars(solution_number=i)
+ #
+ # Pull the solution from the model into a Solution object,
+ # and append to our list of solutions
+ #
+ solutions.append(Solution(model, variables))
+
+ return solutions
diff --git a/pyomo/contrib/alternative_solutions/solution.py b/pyomo/contrib/alternative_solutions/solution.py
new file mode 100644
index 00000000000..7022e7741ce
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/solution.py
@@ -0,0 +1,158 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import json
+import pyomo.environ as pyo
+from pyomo.common.collections import ComponentMap, ComponentSet
+from pyomo.contrib.alternative_solutions import aos_utils
+
+
+class Solution:
+ """
+ A class to store solutions from a Pyomo model.
+
+ Attributes
+ ----------
+ variables : ComponentMap
+ A map between Pyomo variables and their values for a solution.
+ fixed_vars : ComponentSet
+ The set of Pyomo variables that are fixed in a solution.
+ objective : ComponentMap
+ A map between Pyomo objectives and their values for a solution.
+
+ Methods
+ -------
+ pprint():
+ Prints a solution.
+ get_variable_name_values(self, ignore_fixed_vars=False):
+ Get a dictionary of variable name-variable value pairs.
+ get_fixed_variable_names(self):
+ Get a list of fixed-variable names.
+ get_objective_name_values(self):
+ Get a dictionary of objective name-objective value pairs.
+ """
+
+ def __init__(self, model, variable_list, include_fixed=True, objective=None):
+ """
+ Constructs a Pyomo Solution object.
+
+ Parameters
+ ----------
+ model : ConcreteModel
+ A concrete Pyomo model.
+ variable_list: A collection of Pyomo _GenereralVarData variables
+ The variables for which the solution will be stored.
+ include_fixed : boolean
+ Boolean indicating that fixed variables should be added to the
+ solution.
+ objective: None or Objective
+ The objective functions for which the value will be saved. None
+ indicates that the active objective should be used, but a
+ different objective can be stored as well.
+ """
+
+ self.variables = ComponentMap()
+ self.fixed_vars = ComponentSet()
+ for var in variable_list:
+ is_fixed = var.is_fixed()
+ if is_fixed:
+ self.fixed_vars.add(var)
+ if include_fixed or not is_fixed:
+ self.variables[var] = pyo.value(var)
+
+ if objective is None:
+ objective = aos_utils.get_active_objective(model)
+ self.objective = (objective, pyo.value(objective))
+
+ @property
+ def objective_value(self):
+ """
+ Returns
+ -------
+ The value of the objective.
+ """
+ return self.objective[1]
+
+ def pprint(self, round_discrete=True, sort_keys=True, indent=4):
+ """
+ Print the solution variables and objective values.
+
+ Parameters
+ ----------
+ rounded_discrete : boolean
+ If True, then round discrete variable values before printing.
+ """
+ print(
+ self.to_string(
+ round_discrete=round_discrete, sort_keys=sort_keys, indent=indent
+ )
+ ) # pragma: no cover
+
+ def to_string(self, round_discrete=True, sort_keys=True, indent=4):
+ return json.dumps(
+ self.to_dict(round_discrete=round_discrete),
+ sort_keys=sort_keys,
+ indent=indent,
+ )
+
+ def to_dict(self, round_discrete=True):
+ ans = {}
+ ans["objective"] = str(self.objective[0])
+ ans["objective_value"] = self.objective[1]
+ soln = {}
+ for variable, value in self.variables.items():
+ val = self._round_variable_value(variable, value, round_discrete)
+ soln[variable.name] = val
+ ans["solution"] = soln
+ ans["fixed_variables"] = [str(v) for v in self.fixed_vars]
+ return ans
+
+ def __str__(self):
+ return self.to_string()
+
+ __repn__ = __str__
+
+ def get_variable_name_values(self, include_fixed=True, round_discrete=True):
+ """
+ Get a dictionary of variable name-variable value pairs.
+
+ Parameters
+ ----------
+ include_fixed : boolean
+ If True, then include fixed variables in the dictionary.
+ round_discrete : boolean
+ If True, then round discrete variable values in the dictionary.
+
+ Returns
+ -------
+ Dictionary mapping variable names to variable values.
+ """
+ return {
+ var.name: self._round_variable_value(var, val, round_discrete)
+ for var, val in self.variables.items()
+ if include_fixed or not var in self.fixed_vars
+ }
+
+ def get_fixed_variable_names(self):
+ """
+ Get a list of fixed-variable names.
+
+ Returns
+ -------
+ A list of the variable names that are fixed.
+ """
+ return [var.name for var in self.fixed_vars]
+
+ def _round_variable_value(self, variable, value, round_discrete=True):
+ """
+ Returns a rounded value unless the variable is discrete or rounded_discrete is False.
+ """
+ return value if not round_discrete or variable.is_continuous() else round(value)
diff --git a/doc/OnlineDocs/modeling_extensions/__init__.py b/pyomo/contrib/alternative_solutions/tests/__init__.py
similarity index 95%
rename from doc/OnlineDocs/modeling_extensions/__init__.py
rename to pyomo/contrib/alternative_solutions/tests/__init__.py
index a4a626013c4..6eb9ea8b81d 100644
--- a/doc/OnlineDocs/modeling_extensions/__init__.py
+++ b/pyomo/contrib/alternative_solutions/tests/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/alternative_solutions/tests/test_aos_utils.py b/pyomo/contrib/alternative_solutions/tests/test_aos_utils.py
new file mode 100644
index 00000000000..481e79f68ca
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_aos_utils.py
@@ -0,0 +1,300 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 import unittest
+
+from pyomo.common.dependencies import numpy as numpy, numpy_available
+
+import pyomo.environ as pyo
+import pyomo.common.unittest as unittest
+from pyomo.common.collections import ComponentSet
+
+import pyomo.contrib.alternative_solutions.aos_utils as au
+
+
+class TestAOSUtilsUnit(unittest.TestCase):
+
+ def get_multiple_objective_model(self):
+ """Create a simple model with three objectives."""
+ m = pyo.ConcreteModel()
+ m.b1 = pyo.Block()
+ m.b2 = pyo.Block()
+ m.x = pyo.Var()
+ m.y = pyo.Var()
+ m.b1.o = pyo.Objective(expr=m.x)
+ m.b2.o = pyo.Objective([0, 1])
+ m.b2.o[0] = pyo.Objective(expr=m.y)
+ m.b2.o[1] = pyo.Objective(expr=m.x + m.y)
+ return m
+
+ def test_multiple_objectives(self):
+ """Check that an error is thrown with multiple objectives."""
+ m = self.get_multiple_objective_model()
+ assert_text = (
+ "Model has 3 active objective functions, exactly one " "is required."
+ )
+ with self.assertRaisesRegex(AssertionError, assert_text):
+ au.get_active_objective(m)
+
+ def test_no_objectives(self):
+ """Check that an error is thrown with no objectives."""
+ m = self.get_multiple_objective_model()
+ m.b1.o.deactivate()
+ m.b2.o.deactivate()
+ assert_text = (
+ "Model has 0 active objective functions, exactly one " "is required."
+ )
+ with self.assertRaisesRegex(AssertionError, assert_text):
+ au.get_active_objective(m)
+
+ def test_one_objective(self):
+ """
+ Check that the active objective is returned, when there is just one
+ objective.
+ """
+ m = self.get_multiple_objective_model()
+ m.b1.o.deactivate()
+ m.b2.o[0].deactivate()
+ self.assertEqual(m.b2.o[1], au.get_active_objective(m))
+
+ def test_aos_block(self):
+ """Ensure that an alternative solution block is added."""
+ m = self.get_multiple_objective_model()
+ block_name = "test_block"
+ b = au._add_aos_block(m, block_name)
+ self.assertEqual(b.name, block_name)
+ self.assertEqual(b.ctype, pyo.Block)
+
+ def get_simple_model(self, sense=pyo.minimize):
+ """Create a simple 2d linear program with an objective."""
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var()
+ m.y = pyo.Var()
+ m.o = pyo.Objective(expr=m.x + m.y, sense=sense)
+ return m
+
+ def test_no_obj_constraint(self):
+ """Ensure that no objective constraints are added."""
+ m = self.get_simple_model()
+ cons = au._add_objective_constraint(m, m.o, 2, None, None)
+ self.assertEqual(cons, [])
+ self.assertEqual(m.find_component("optimality_tol_rel"), None)
+ self.assertEqual(m.find_component("optimality_tol_abs"), None)
+
+ def test_min_rel_obj_constraint(self):
+ """Ensure that the correct relative objective constraint is added."""
+ m = self.get_simple_model()
+ cons = au._add_objective_constraint(m, m.o, 2, 0.1, None)
+ self.assertEqual(len(cons), 1)
+ self.assertEqual(m.find_component("optimality_tol_rel"), cons[0])
+ self.assertEqual(m.find_component("optimality_tol_abs"), None)
+ self.assertEqual(2.2, cons[0].upper)
+ self.assertEqual(None, cons[0].lower)
+
+ def test_min_abs_obj_constraint(self):
+ """Ensure that the correct absolute objective constraint is added."""
+ m = self.get_simple_model()
+ cons = au._add_objective_constraint(m, m.o, 2, None, 1)
+ self.assertEqual(len(cons), 1)
+ self.assertEqual(m.find_component("optimality_tol_rel"), None)
+ self.assertEqual(m.find_component("optimality_tol_abs"), cons[0])
+ self.assertEqual(3, cons[0].upper)
+ self.assertEqual(None, cons[0].lower)
+
+ def test_min_both_obj_constraint(self):
+ m = self.get_simple_model()
+ cons = au._add_objective_constraint(m, m.o, -10, 0.3, 5)
+ self.assertEqual(len(cons), 2)
+ self.assertEqual(m.find_component("optimality_tol_rel"), cons[0])
+ self.assertEqual(m.find_component("optimality_tol_abs"), cons[1])
+ self.assertEqual(-7, cons[0].upper)
+ self.assertEqual(None, cons[0].lower)
+ self.assertEqual(-5, cons[1].upper)
+ self.assertEqual(None, cons[1].lower)
+
+ def test_max_both_obj_constraint(self):
+ """
+ Ensure that the correct relative and absolute objective constraints are
+ added.
+ """
+ m = self.get_simple_model(sense=pyo.maximize)
+ cons = au._add_objective_constraint(m, m.o, -1, 0.3, 1)
+ self.assertEqual(len(cons), 2)
+ self.assertEqual(m.find_component("optimality_tol_rel"), cons[0])
+ self.assertEqual(m.find_component("optimality_tol_abs"), cons[1])
+ self.assertEqual(None, cons[0].upper)
+ self.assertEqual(-1.3, cons[0].lower)
+ self.assertEqual(None, cons[1].upper)
+ self.assertEqual(-2, cons[1].lower)
+
+ def test_max_both_obj_constraint2(self):
+ """
+ Ensure that the correct relative and absolute objective constraints are
+ added.
+ """
+ m = self.get_simple_model(sense=pyo.maximize)
+ cons = au._add_objective_constraint(m, m.o, 20, 0.5, 11)
+ self.assertEqual(len(cons), 2)
+ self.assertEqual(m.find_component("optimality_tol_rel"), cons[0])
+ self.assertEqual(m.find_component("optimality_tol_abs"), cons[1])
+ self.assertEqual(None, cons[0].upper)
+ self.assertEqual(10, cons[0].lower)
+ self.assertEqual(None, cons[1].upper)
+ self.assertEqual(9, cons[1].lower)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_random_direction(self):
+ """
+ Ensure that _get_random_direction returns a normal vector.
+ """
+ from numpy.linalg import norm
+
+ vector = au._get_random_direction(10)
+ self.assertAlmostEqual(1.0, norm(vector))
+
+ def get_var_model(self):
+ """
+ Create a model with multiple variables that are nested over several
+ layers of blocks.
+ """
+
+ indices = [0, 1, 2, 3]
+
+ m = pyo.ConcreteModel()
+
+ m.b1 = pyo.Block()
+ m.b2 = pyo.Block()
+ m.b1.sb1 = pyo.Block()
+ m.b2.sb2 = pyo.Block()
+
+ m.x = pyo.Var(domain=pyo.Reals)
+ m.b1.y = pyo.Var(domain=pyo.Binary)
+ m.b2.z = pyo.Var(domain=pyo.Integers)
+
+ m.x_f = pyo.Var(domain=pyo.Reals)
+ m.b1.y_f = pyo.Var(domain=pyo.Binary)
+ m.b2.z_f = pyo.Var(domain=pyo.Integers)
+ m.x_f.fix(0)
+ m.b1.y_f.fix(0)
+ m.b2.z_f.fix(0)
+
+ m.b1.sb1.x_l = pyo.Var(indices, domain=pyo.Reals)
+ m.b1.sb1.y_l = pyo.Var(indices, domain=pyo.Binary)
+ m.b2.sb2.z_l = pyo.Var(indices, domain=pyo.Integers)
+
+ m.b1.sb1.x_l[3].fix(0)
+ m.b1.sb1.y_l[3].fix(0)
+ m.b2.sb2.z_l[3].fix(0)
+
+ vars_minus_x = (
+ [m.b1.y, m.b2.z, m.x_f, m.b1.y_f, m.b2.z_f]
+ + [m.b1.sb1.x_l[i] for i in indices]
+ + [m.b1.sb1.y_l[i] for i in indices]
+ + [m.b2.sb2.z_l[i] for i in indices]
+ )
+
+ m.con = pyo.Constraint(expr=sum(v for v in vars_minus_x) <= 1)
+ m.b1.con = pyo.Constraint(expr=m.b1.y <= 1)
+ m.b1.sb1.con = pyo.Constraint(expr=m.b1.sb1.y_l[0] <= 1)
+ m.obj = pyo.Objective(expr=m.x)
+
+ m.all_vars = ComponentSet([m.x] + vars_minus_x)
+ m.unfixed_vars = ComponentSet([var for var in m.all_vars if not var.is_fixed()])
+
+ return m
+
+ def test_get_all_variables_unfixed(self):
+ """Check that all unfixed variables are gathered."""
+ m = self.get_var_model()
+ var = au.get_model_variables(m)
+ self.assertEqual(var, m.unfixed_vars)
+
+ def test_get_all_variables(self):
+ """Check that all fixed and unfixed variables are gathered."""
+ m = self.get_var_model()
+ var = au.get_model_variables(m, include_fixed=True)
+ self.assertEqual(var, m.all_vars)
+
+ def test_get_all_continuous(self):
+ """Check that all continuous variables are gathered."""
+ m = self.get_var_model()
+ var = au.get_model_variables(
+ m, include_continuous=True, include_binary=False, include_integer=False
+ )
+ continuous_vars = ComponentSet(
+ var for var in m.unfixed_vars if var.is_continuous()
+ )
+ self.assertEqual(var, continuous_vars)
+
+ def test_get_all_binary(self):
+ """Check that all binary variables are gathered."""
+ m = self.get_var_model()
+ var = au.get_model_variables(
+ m, include_continuous=False, include_binary=True, include_integer=False
+ )
+ binary_vars = ComponentSet(var for var in m.unfixed_vars if var.is_binary())
+ self.assertEqual(var, binary_vars)
+
+ def test_get_all_integer(self):
+ """Check that all integer variables are gathered."""
+ m = self.get_var_model()
+ var = au.get_model_variables(
+ m, include_continuous=False, include_binary=False, include_integer=True
+ )
+ continuous_vars = ComponentSet(
+ var for var in m.unfixed_vars if var.is_integer()
+ )
+ self.assertEqual(var, continuous_vars)
+
+ def test_get_specific_vars(self):
+ """Check that all variables from a list are gathered."""
+ m = self.get_var_model()
+ components = [m.x, m.b1.sb1.y_l[0], m.b2.sb2.z_l]
+ var = au.get_model_variables(m, components=components)
+ specific_vars = ComponentSet(
+ [m.x, m.b1.sb1.y_l[0], m.b2.sb2.z_l[0], m.b2.sb2.z_l[1], m.b2.sb2.z_l[2]]
+ )
+ self.assertEqual(var, specific_vars)
+
+ def test_get_block_vars1(self):
+ """
+ Check that all variables from block are gathered (without
+ descending into subblocks).
+ """
+ m = self.get_var_model()
+ components = [m.b2.sb2.z_l, (m.b1, False)]
+ var = au.get_model_variables(m, components=components)
+ specific_vars = ComponentSet(
+ [m.b1.y, m.b2.sb2.z_l[0], m.b2.sb2.z_l[1], m.b2.sb2.z_l[2]]
+ )
+ self.assertEqual(var, specific_vars)
+
+ def test_get_block_vars2(self):
+ """
+ Check that all variables from block are gathered (without
+ descending into subblocks).
+ """
+ m = self.get_var_model()
+ components = [m.b1]
+ var = au.get_model_variables(m, components=components)
+ specific_vars = ComponentSet([m.b1.y, m.b1.sb1.y_l[0]])
+ self.assertEqual(var, specific_vars)
+
+ def test_get_constraint_vars(self):
+ """Check that all variables constraints and objectives are gathered."""
+ m = self.get_var_model()
+ components = [m.con, m.obj]
+ var = au.get_model_variables(m, components=components)
+ self.assertEqual(var, m.unfixed_vars)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/alternative_solutions/tests/test_balas.py b/pyomo/contrib/alternative_solutions/tests/test_balas.py
new file mode 100644
index 00000000000..984cde09a79
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_balas.py
@@ -0,0 +1,154 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 collections import Counter
+
+from pyomo.common.dependencies import numpy as numpy, numpy_available
+
+if numpy_available:
+ from numpy.testing import assert_array_almost_equal
+
+from pyomo.common import unittest
+import pyomo.opt
+
+from pyomo.contrib.alternative_solutions import enumerate_binary_solutions
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+
+solvers = list(pyomo.opt.check_available_solvers("glpk", "gurobi", "appsi_gurobi"))
+pytestmark = unittest.pytest.mark.parametrize("mip_solver", solvers)
+
+
+@unittest.pytest.mark.default
+class TestBalasUnit:
+
+ def test_bad_solver(self, mip_solver):
+ """
+ Confirm that an exception is thrown with a bad solver name.
+ """
+ m = tc.get_triangle_ip()
+ try:
+ enumerate_binary_solutions(m, solver="unknown_solver")
+ except pyomo.common.errors.ApplicationError as e:
+ pass
+
+ def test_ip_feasibility(self, mip_solver):
+ """
+ Enumerate solutions for an ip: triangle_ip.
+
+ Check that there is just one solution when the # of binary variables is 0.
+ """
+ m = tc.get_triangle_ip()
+ results = enumerate_binary_solutions(m, num_solutions=100, solver=mip_solver)
+ assert len(results) == 1
+ assert results[0].objective_value == unittest.pytest.approx(5)
+
+ @unittest.skipIf(True, "Ignoring fragile test for solver timeout.")
+ def test_no_time(self, mip_solver):
+ """
+ Enumerate solutions for an ip: triangle_ip.
+
+ Check that something sensible happens when the solver times out.
+ """
+ m = tc.get_triangle_ip()
+ with unittest.pytest.raises(Exception):
+ results = enumerate_binary_solutions(
+ m, num_solutions=100, solver=mip_solver, solver_options={"TimeLimit": 0}
+ )
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_knapsack_all(self, mip_solver):
+ """
+ Enumerate solutions for a binary problem: knapsack
+
+ """
+ m = tc.get_aos_test_knapsack(
+ 1, weights=[3, 4, 6, 5], values=[2, 3, 1, 4], capacity=8
+ )
+ results = enumerate_binary_solutions(m, num_solutions=100, solver=mip_solver)
+ objectives = list(
+ sorted((round(result.objective[1], 2) for result in results), reverse=True)
+ )
+ assert_array_almost_equal(objectives, m.ranked_solution_values)
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ assert_array_almost_equal(unique_solns_by_obj, m.num_ranked_solns)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_knapsack_x0_x1(self, mip_solver):
+ """
+ Enumerate solutions for a binary problem: knapsack
+
+ Check that we only see 4 solutions that enumerate alternatives of x[1] and x[1]
+ """
+ m = tc.get_aos_test_knapsack(
+ 1, weights=[3, 4, 6, 5], values=[2, 3, 1, 4], capacity=8
+ )
+ results = enumerate_binary_solutions(
+ m, num_solutions=100, solver=mip_solver, variables=[m.x[0], m.x[1]]
+ )
+ objectives = list(
+ sorted((round(result.objective[1], 2) for result in results), reverse=True)
+ )
+ assert_array_almost_equal(objectives, [6, 5, 4, 3])
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ assert_array_almost_equal(unique_solns_by_obj, [1, 1, 1, 1])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_knapsack_optimal_3(self, mip_solver):
+ """
+ Enumerate solutions for a binary problem: knapsack
+
+ """
+ m = tc.get_aos_test_knapsack(
+ 1, weights=[3, 4, 6, 5], values=[2, 3, 1, 4], capacity=8
+ )
+ results = enumerate_binary_solutions(m, num_solutions=3, solver=mip_solver)
+ objectives = list(
+ sorted((round(result.objective[1], 2) for result in results), reverse=True)
+ )
+ assert_array_almost_equal(objectives, m.ranked_solution_values[:3])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_knapsack_hamming_3(self, mip_solver):
+ """
+ Enumerate solutions for a binary problem: knapsack
+
+ """
+ m = tc.get_aos_test_knapsack(
+ 1, weights=[3, 4, 6, 5], values=[2, 3, 1, 4], capacity=8
+ )
+ results = enumerate_binary_solutions(
+ m, num_solutions=3, solver=mip_solver, search_mode="hamming"
+ )
+ objectives = list(
+ sorted((round(result.objective[1], 2) for result in results), reverse=True)
+ )
+ assert_array_almost_equal(objectives, [6, 3, 1])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_knapsack_random_3(self, mip_solver):
+ """
+ Enumerate solutions for a binary problem: knapsack
+
+ """
+ m = tc.get_aos_test_knapsack(
+ 1, weights=[3, 4, 6, 5], values=[2, 3, 1, 4], capacity=8
+ )
+ results = enumerate_binary_solutions(
+ m, num_solutions=3, solver=mip_solver, search_mode="random", seed=1118798374
+ )
+ objectives = list(
+ sorted((round(result.objective[1], 2) for result in results), reverse=True)
+ )
+ assert_array_almost_equal(objectives, [6, 5, 4])
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/alternative_solutions/tests/test_case.xlsx b/pyomo/contrib/alternative_solutions/tests/test_case.xlsx
new file mode 100644
index 00000000000..4fa4ee1045a
Binary files /dev/null and b/pyomo/contrib/alternative_solutions/tests/test_case.xlsx differ
diff --git a/pyomo/contrib/alternative_solutions/tests/test_cases.py b/pyomo/contrib/alternative_solutions/tests/test_cases.py
new file mode 100644
index 00000000000..5a5f2479af8
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_cases.py
@@ -0,0 +1,438 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 itertools import product
+from math import ceil, floor
+from collections import Counter
+
+from pyomo.common.dependencies import numpy as np
+
+import pyomo.environ as pyo
+
+"""
+This script has collection of test cases that can be used to enumerate solutions.
+That is, simple problems where the alternative solutions can be found manually.
+"""
+
+
+def _is_satisfied(constraint, feasibility_tol=1e-6):
+ value = pyo.value(constraint.body)
+ if constraint.has_lb() and value < constraint.lb - feasibility_tol:
+ return False
+ if constraint.has_ub() and value > constraint.ub + feasibility_tol:
+ return False
+ return True
+
+
+def get_2d_diamond_problem(discrete_x=False, discrete_y=False):
+ """
+ Simple 2d problem where the feasible is diamond-shaped.
+ """
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.Integers if discrete_x else pyo.Reals, bounds=(-10, 10))
+ m.y = pyo.Var(within=pyo.Integers if discrete_y else pyo.Reals, bounds=(-10, 10))
+
+ m.o = pyo.Objective(expr=m.x + m.y, sense=pyo.maximize)
+
+ m.c1 = pyo.Constraint(expr=-4 / 5 * m.x - 4 <= m.y)
+ m.c2 = pyo.Constraint(expr=5 / 9 * m.x - 5 <= m.y)
+ m.c3 = pyo.Constraint(expr=2 / 9 * m.x + 2 >= m.y)
+ m.c4 = pyo.Constraint(expr=-1 / 2 * m.x + 3 >= m.y)
+
+ # Continuous exteme points and bounds
+ m.extreme_points = {
+ (0.737704918, -4.590163934),
+ (-5.869565217, 0.695652174),
+ (1.384615385, 2.307692308),
+ (7.578947368, -0.789473684),
+ }
+
+ m.continuous_bounds = pyo.ComponentMap()
+ m.continuous_bounds[m.x] = (-5.869565217, 7.578947368)
+ m.continuous_bounds[m.y] = (-4.590163934, 2.307692308)
+
+ # Continuous exteme points and bounds for the case where an objective
+ # constraint is added within a 100% relative gap of optimality or an
+ # absolute gap of 6.789473684
+
+ m.extreme_points_cut = {
+ (45 / 14, -45 / 14),
+ (-18 / 11, 18 / 11),
+ (1.384615385, 2.307692308),
+ (7.578947368, -0.789473684),
+ }
+
+ m.continuous_bounds_cut = pyo.ComponentMap()
+ m.continuous_bounds_cut[m.x] = (-18 / 11, 7.578947368)
+ m.continuous_bounds_cut[m.y] = (-45 / 14, 2.307692308)
+
+ # Discrete feasible solutions and bounds
+ feasible_sols = []
+ x_lower_bound = None
+ x_upper_bound = None
+ y_lower_bound = None
+ y_upper_bound = None
+
+ x_lower = ceil(m.continuous_bounds[m.x][0])
+ x_upper = floor(m.continuous_bounds[m.x][1])
+ y_lower = ceil(m.continuous_bounds[m.y][0])
+ y_upper = floor(m.continuous_bounds[m.y][1])
+ cons = [m.c1, m.c2, m.c3, m.c4]
+ for x_value in range(x_lower, x_upper + 1):
+ for y_value in range(y_lower, y_upper + 1):
+ m.x.set_value(x_value)
+ m.y.set_value(y_value)
+ is_feasible = True
+ for con in cons:
+ if not _is_satisfied(con):
+ is_feasible = False
+ break
+ if is_feasible:
+ if x_lower_bound is None or x_value < x_lower_bound:
+ x_lower_bound = x_value
+ if x_upper_bound is None or x_value > x_upper_bound:
+ x_upper_bound = x_value
+ if y_lower_bound is None or y_value < y_lower_bound:
+ y_lower_bound = y_value
+ if y_upper_bound is None or y_value > y_upper_bound:
+ y_upper_bound = y_value
+ feasible_sols.append(((x_value, y_value), x_value + y_value))
+ m.discrete_feasible = sorted(feasible_sols, key=lambda sol: sol[1], reverse=True)
+ m.discrete_bounds = pyo.ComponentMap()
+ m.discrete_bounds[m.x] = (x_lower_bound, x_upper_bound)
+ m.discrete_bounds[m.y] = (y_lower_bound, y_upper_bound)
+
+ return m
+
+
+def get_3d_polyhedron_problem():
+ """
+ Simple 3d polyhedron that is expressed using all types of linear constraints
+ """
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var([0, 1, 2], within=pyo.Reals)
+ m.x[0].setlb(-1)
+ m.x[0].setub(1)
+ m.x[1].setlb(-2)
+ m.x[1].setub(2)
+ m.x[2].setlb(1)
+ m.x[2].setub(2)
+
+ def _constraint_switch_rule(m, i):
+ if i == 0:
+ return m.x[0] + m.x[1] <= 2
+ elif i == 1:
+ return -m.x[0] + m.x[1] <= 2
+ elif i == 2:
+ return m.x[0] + m.x[1] >= -2
+ elif i == 3:
+ return -m.x[0] + m.x[1] >= -2
+ elif i == 4:
+ return m.x[0] + m.x[1] + m.x[2] == 4
+
+ m.c = pyo.Constraint([i for i in range(5)], rule=_constraint_switch_rule)
+
+ m.o = pyo.Objective(expr=m.x[0] + m.x[2], sense=pyo.maximize)
+ return m
+
+
+def get_2d_unbounded_problem():
+ """
+ Simple 2d problem where the feasible region is unbounded, but the problem
+ has an optimal solution.
+ """
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.Reals)
+ m.y = pyo.Var(within=pyo.Reals)
+
+ m.o = pyo.Objective(expr=m.y - m.x)
+
+ m.c1 = pyo.Constraint(expr=m.x <= 4)
+ m.c2 = pyo.Constraint(expr=m.y >= 2)
+
+ m.extreme_points = {(4, 2)}
+
+ m.continuous_bounds = pyo.ComponentMap()
+ m.continuous_bounds[m.x] = (float("-inf"), 4)
+ m.continuous_bounds[m.y] = (2, float("inf"))
+ return m
+
+
+def get_2d_degenerate_lp():
+ """
+ Simple 2d problem that includes a redundant constraint such that three
+ constraints are active at optimality.
+ """
+ m = pyo.ConcreteModel()
+
+ m.x = pyo.Var(within=pyo.Reals, bounds=(-1, 3))
+ m.y = pyo.Var(within=pyo.Reals, bounds=(-3, 2))
+
+ m.obj = pyo.Objective(expr=m.x + 2 * m.y, sense=pyo.maximize)
+
+ m.con1 = pyo.Constraint(expr=m.x + m.y <= 3)
+ m.con2 = pyo.Constraint(expr=m.x + 2 * m.y <= 5)
+ m.con3 = pyo.Constraint(expr=m.x + m.y >= -1)
+
+ return m
+
+
+def get_triangle_ip():
+ """
+ Simple 2d discrete problem where the feasible region looks like a 90-45-45
+ right triangle and the optimal solutions fall along the hypotenuse, where
+ x + y == 5. Alternative near-optimal have integer objective values from 0 to 4.
+ """
+ var_max = 5
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.NonNegativeIntegers, bounds=(0, var_max))
+ m.y = pyo.Var(within=pyo.NonNegativeIntegers, bounds=(0, var_max))
+
+ m.o = pyo.Objective(expr=m.x + m.y, sense=pyo.maximize)
+ m.c = pyo.Constraint(expr=m.x + m.y <= var_max)
+
+ #
+ # Enumerate all feasible solutions
+ #
+ feasible_sols = []
+ for i in range(var_max + 1):
+ for j in range(var_max + 1):
+ if i + j <= var_max:
+ feasible_sols.append(((i, j), i + j))
+ feasible_sols = sorted(feasible_sols, key=lambda sol: sol[1], reverse=True)
+ m.feasible_sols = feasible_sols
+ #
+ # Count of solutions from best to worst
+ #
+ m.num_ranked_solns = [6, 5, 4, 3, 2, 1]
+
+ return m
+
+
+def get_implied_bound_ip():
+ """
+ 2d discrete problem where the bounds of z are impled by x and y. This
+ facilitate testing cases where the impled bounds are tighter than the
+ given bounds for the variable.
+ """
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.NonNegativeIntegers, bounds=(0, 5))
+ m.y = pyo.Var(within=pyo.NonNegativeIntegers, bounds=(0, 5))
+ m.z = pyo.Var(within=pyo.NonNegativeIntegers, bounds=(0, 5))
+
+ m.o = pyo.Objective(expr=m.x + m.z)
+
+ m.c1 = pyo.Constraint(expr=m.x + m.y == 3)
+ m.c2 = pyo.Constraint(expr=m.x + m.y + m.z <= 5)
+ m.c3 = pyo.Constraint(expr=m.x + m.y + m.z >= 4)
+
+ m.var_bounds = pyo.ComponentMap()
+ m.var_bounds[m.x] = (0, 3)
+ m.var_bounds[m.y] = (0, 3)
+ m.var_bounds[m.z] = (1, 2)
+
+ return m
+
+
+def get_aos_test_knapsack(
+ var_max, weights, values, capacity=None, capacity_fraction=1.0
+):
+ """
+ Creates a knapsack problem, given arrays of weights and values, and
+ returns all feasible solutions. The capacity represents the percent of the
+ total max weight that can be selected (sum weights * var_max). The var_max
+ parameter sets the upper bound on all variables, the max number of times
+ they can be selected.
+ """
+ assert len(weights) == len(values), "weights and values must be the same length."
+ assert (
+ 0 <= capacity_fraction and capacity_fraction <= 1
+ ), "capacity_fraction must be between 0 and 1."
+
+ num_vars = len(weights)
+ if capacity is None:
+ capacity = sum(weights) * var_max * capacity_fraction
+
+ m = pyo.ConcreteModel()
+ m.i = pyo.RangeSet(0, num_vars - 1)
+
+ if var_max == 1:
+ m.x = pyo.Var(m.i, within=pyo.Binary)
+ else:
+ m.x = pyo.Var(m.i, within=pyo.NonNegativeIntegers, bounds=(0, var_max))
+
+ m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in m.i), sense=pyo.maximize)
+
+ m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in m.i) <= capacity)
+
+ var_domain = range(var_max + 1)
+ all_combos = product(var_domain, repeat=num_vars)
+
+ feasible_sols = []
+ for sol in all_combos:
+ if np.dot(sol, weights) <= capacity:
+ feasible_sols.append((sol, np.dot(sol, values)))
+ feasible_sols = sorted(feasible_sols, key=lambda sol: sol[1], reverse=True)
+ m.ranked_solution_values = list(sorted([v for x, v in feasible_sols], reverse=True))
+ m.num_ranked_solns = list(Counter([v for x, v in feasible_sols]).values())
+ return m
+
+
+def get_pentagonal_lp():
+ """
+ Pentagonal LP
+ """
+ var_max = 5
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.Reals, bounds=(0, 2 * var_max))
+ m.y = pyo.Var(within=pyo.Reals, bounds=(0, 2 * var_max))
+ m.z = pyo.Var(within=pyo.NonNegativeReals, bounds=(0, 2 * var_max))
+ m.o = pyo.Objective(expr=m.z, sense=pyo.minimize)
+
+ base_points = np.array(
+ [
+ [var_max, 2 * var_max, 0],
+ [2 * var_max, var_max, 0],
+ [3.0 * var_max / 2.0, 0, 0],
+ [var_max / 2.0, 0, 0],
+ [0, var_max, 0],
+ ]
+ )
+ apex_point = np.array([var_max, var_max, var_max])
+
+ m.c = pyo.ConstraintList()
+ for i in range(5):
+ vec_1 = base_points[i] - apex_point
+ vec_2 = base_points[(i + 1) % var_max] - base_points[i]
+ n = np.cross(vec_1, vec_2)
+ m.c.add(
+ n[0] * (m.x - apex_point[0])
+ + n[1] * (m.y - apex_point[1])
+ + n[2] * (m.z - apex_point[2])
+ >= 0
+ )
+
+ return m
+
+
+def get_pentagonal_pyramid_mip():
+ """
+ Pentagonal pyramid with integer coordinates in the first two dimensions and
+ a third continuous dimension.
+ """
+ var_max = 5
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.Integers, bounds=(-var_max, var_max))
+ m.y = pyo.Var(within=pyo.Integers, bounds=(-var_max, var_max))
+ m.z = pyo.Var(within=pyo.NonNegativeReals, bounds=(0, var_max))
+ m.o = pyo.Objective(expr=m.z, sense=pyo.maximize)
+
+ base_points = np.array(
+ [
+ [0, var_max, 0],
+ [var_max, 0, 0],
+ [var_max / 2.0, -var_max, 0],
+ [-var_max / 2.0, -var_max, 0],
+ [-var_max, 0, 0],
+ ]
+ )
+ apex_point = np.array([0, 0, var_max])
+
+ m.c = pyo.ConstraintList()
+ for i in range(5):
+ vec_1 = base_points[i] - apex_point
+ vec_2 = base_points[(i + 1) % var_max] - base_points[i]
+ n = np.cross(vec_1, vec_2)
+ m.c.add(
+ n[0] * (m.x - apex_point[0])
+ + n[1] * (m.y - apex_point[1])
+ + n[2] * (m.z - apex_point[2])
+ >= 0
+ )
+ #
+ # Count of solutions from best to worst
+ #
+ m.num_ranked_solns = [1, 4, 2, 8, 2, 12, 4, 16, 4, 20]
+ return m
+
+
+def get_indexed_pentagonal_pyramid_mip():
+ """
+ Pentagonal pyramid with integer coordinates in the first two dimensions and
+ a third continuous dimension.
+ """
+ var_max = 5
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var([1, 2], within=pyo.Integers, bounds=(-var_max, var_max))
+ m.z = pyo.Var(within=pyo.NonNegativeReals, bounds=(0, var_max))
+ m.o = pyo.Objective(expr=m.z, sense=pyo.maximize)
+ base_points = np.array(
+ [
+ [0, var_max, 0],
+ [var_max, 0, 0],
+ [var_max / 2.0, -var_max, 0],
+ [-var_max / 2.0, -var_max, 0],
+ [-var_max, 0, 0],
+ ]
+ )
+ apex_point = np.array([0, 0, var_max])
+
+ def _con_rule(m, i):
+ vec_1 = base_points[i] - apex_point
+ vec_2 = base_points[(i + 1) % var_max] - base_points[i]
+ n = np.cross(vec_1, vec_2)
+ expr = (
+ n[0] * (m.x[1] - apex_point[0])
+ + n[1] * (m.x[2] - apex_point[1])
+ + n[2] * (m.z - apex_point[2])
+ )
+ return expr >= 0
+
+ m.c = pyo.Constraint([i for i in range(5)], rule=_con_rule)
+ m.num_ranked_solns = [1, 4, 2, 8, 2, 12, 4, 16, 4, 20]
+ return m
+
+
+def get_bloated_pentagonal_pyramid_mip():
+ """
+ Pentagonal pyramid with integer coordinates in the first two dimensions and
+ a third continuous dimension. Bounds are artificially widened for obbt testing purposes
+ """
+ var_max = 5
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(within=pyo.Integers, bounds=(-2 * var_max, 2 * var_max))
+ m.y = pyo.Var(within=pyo.Integers, bounds=(-2 * var_max, var_max))
+ m.z = pyo.Var(within=pyo.NonNegativeReals, bounds=(0, 2 * var_max))
+ m.var_bounds = pyo.ComponentMap()
+ m.o = pyo.Objective(expr=m.z, sense=pyo.maximize)
+ base_points = np.array(
+ [
+ [0, var_max, 0],
+ [var_max, 0, 0],
+ [var_max / 2.0, -var_max, 0],
+ [-var_max / 2.0, -var_max, 0],
+ [-var_max, 0, 0],
+ ]
+ )
+ apex_point = np.array([0, 0, var_max])
+
+ m.c = pyo.ConstraintList()
+ for i in range(5):
+ vec_1 = base_points[i] - apex_point
+ vec_2 = base_points[(i + 1) % var_max] - base_points[i]
+ n = np.cross(vec_1, vec_2)
+ m.c.add(
+ n[0] * (m.x - apex_point[0])
+ + n[1] * (m.y - apex_point[1])
+ + n[2] * (m.z - apex_point[2])
+ >= 0
+ )
+ return m
diff --git a/pyomo/contrib/alternative_solutions/tests/test_lp_enum.py b/pyomo/contrib/alternative_solutions/tests/test_lp_enum.py
new file mode 100644
index 00000000000..27e6fe0cfb1
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_lp_enum.py
@@ -0,0 +1,107 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 numpy, numpy_available
+
+import pyomo.environ as pyo
+from pyomo.common import unittest
+import pyomo.opt
+
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+from pyomo.contrib.alternative_solutions import lp_enum
+
+#
+# Find available solvers. Just use GLPK if it's available.
+#
+solvers = list(
+ pyomo.opt.check_available_solvers("glpk", "gurobi")
+) # , "appsi_gurobi"))
+pytestmark = unittest.pytest.mark.parametrize("mip_solver", solvers)
+
+timelimit = {"gurobi": "TimeLimit", "appsi_gurobi": "TimeLimit", "glpk": "tmlim"}
+
+
+@unittest.pytest.mark.default
+class TestLPEnum:
+
+ def test_bad_solver(self, mip_solver):
+ """
+ Confirm that an exception is thrown with a bad solver name.
+ """
+ m = tc.get_3d_polyhedron_problem()
+ try:
+ lp_enum.enumerate_linear_solutions(m, solver="unknown_solver")
+ except pyomo.common.errors.ApplicationError as e:
+ pass
+
+ @unittest.skipIf(True, "Ignoring fragile test for solver timeout.")
+ def test_no_time(self, mip_solver):
+ """
+ Check that the correct bounds are found for a discrete problem where
+ more restrictive bounds are implied by the constraints.
+ """
+ m = tc.get_3d_polyhedron_problem()
+ with unittest.pytest.raises(Exception):
+ lp_enum.enumerate_linear_solutions(
+ m, solver=mip_solver, solver_options={timelimit[mip_solver]: 0}
+ )
+
+ def test_3d_polyhedron(self, mip_solver):
+ m = tc.get_3d_polyhedron_problem()
+ m.o.deactivate()
+ m.obj = pyo.Objective(expr=m.x[0] + m.x[1] + m.x[2])
+
+ sols = lp_enum.enumerate_linear_solutions(m, solver=mip_solver)
+ assert len(sols) == 2
+ for s in sols:
+ assert s.objective_value == unittest.pytest.approx(4)
+
+ def test_3d_polyhedron(self, mip_solver):
+ m = tc.get_3d_polyhedron_problem()
+ m.o.deactivate()
+ m.obj = pyo.Objective(expr=m.x[0] + 2 * m.x[1] + 3 * m.x[2])
+
+ sols = lp_enum.enumerate_linear_solutions(m, solver=mip_solver)
+ assert len(sols) == 2
+ for s in sols:
+ assert s.objective_value == unittest.pytest.approx(
+ 9
+ ) or s.objective_value == unittest.pytest.approx(10)
+
+ def test_2d_diamond_problem(self, mip_solver):
+ m = tc.get_2d_diamond_problem()
+ sols = lp_enum.enumerate_linear_solutions(m, solver=mip_solver, num_solutions=2)
+ assert len(sols) == 2
+ for s in sols:
+ print(s)
+ assert sols[0].objective_value == unittest.pytest.approx(6.789473684210527)
+ assert sols[1].objective_value == unittest.pytest.approx(3.6923076923076916)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_pentagonal_pyramid(self, mip_solver):
+ n = tc.get_pentagonal_pyramid_mip()
+ n.o.sense = pyo.minimize
+ n.x.domain = pyo.Reals
+ n.y.domain = pyo.Reals
+
+ sols = lp_enum.enumerate_linear_solutions(n, solver=mip_solver, tee=False)
+ for s in sols:
+ print(s)
+ assert len(sols) == 6
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_pentagon(self, mip_solver):
+ n = tc.get_pentagonal_lp()
+
+ sols = lp_enum.enumerate_linear_solutions(n, solver=mip_solver)
+ for s in sols:
+ print(s)
+ assert len(sols) == 6
diff --git a/pyomo/contrib/alternative_solutions/tests/test_lp_enum_solnpool.py b/pyomo/contrib/alternative_solutions/tests/test_lp_enum_solnpool.py
new file mode 100644
index 00000000000..c46466779e1
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_lp_enum_solnpool.py
@@ -0,0 +1,48 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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_available
+from pyomo.common import unittest
+
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+from pyomo.contrib.alternative_solutions import lp_enum
+from pyomo.contrib.alternative_solutions import lp_enum_solnpool
+from pyomo.opt import check_available_solvers
+
+import pyomo.environ as pyo
+
+# lp_enum_solnpool uses both 'gurobi' and 'appsi_gurobi'
+gurobi_available = len(check_available_solvers('gurobi', 'appsi_gurobi')) == 2
+
+#
+# TODO: Setup detailed tests here
+#
+
+
+@unittest.skipUnless(gurobi_available, "Gurobi MIP solver not available")
+@unittest.skipUnless(numpy_available, "NumPy not found")
+class TestLPEnumSolnpool(unittest.TestCase):
+
+ def test_here(self):
+ n = tc.get_pentagonal_pyramid_mip()
+ n.x.domain = pyo.Reals
+ n.y.domain = pyo.Reals
+
+ try:
+ sols = lp_enum_solnpool.enumerate_linear_solutions_soln_pool(n, tee=True)
+ except pyomo.common.errors.ApplicationError as e:
+ sols = []
+
+ # TODO - Confirm how solnpools deal with duplicate solutions
+ if gurobi_available:
+ assert len(sols) == 7
+ else:
+ assert len(sols) == 0
diff --git a/pyomo/contrib/alternative_solutions/tests/test_obbt.py b/pyomo/contrib/alternative_solutions/tests/test_obbt.py
new file mode 100644
index 00000000000..ac40c31a1f4
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_obbt.py
@@ -0,0 +1,245 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import math
+
+from pyomo.common.dependencies import numpy as numpy, numpy_available
+
+if numpy_available:
+ from numpy.testing import assert_array_almost_equal
+
+import pyomo.environ as pyo
+from pyomo.common import unittest
+
+import pyomo.opt
+from pyomo.contrib.alternative_solutions import (
+ obbt_analysis_bounds_and_solutions,
+ obbt_analysis,
+)
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+
+solvers = list(pyomo.opt.check_available_solvers("glpk", "gurobi", "appsi_gurobi"))
+pytestmark = unittest.pytest.mark.parametrize("mip_solver", solvers)
+
+timelimit = {"gurobi": "TimeLimit", "appsi_gurobi": "TimeLimit", "glpk": "tmlim"}
+
+
+@unittest.pytest.mark.default
+class TestOBBTUnit:
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_bad_solver(self, mip_solver):
+ """
+ Confirm that an exception is thrown with a bad solver name.
+ """
+ m = tc.get_2d_diamond_problem()
+ try:
+ obbt_analysis(m, solver="unknown_solver")
+ except pyomo.common.errors.ApplicationError as e:
+ pass
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_analysis(self, mip_solver):
+ """
+ Check that the correct bounds are found for a continuous problem.
+ """
+ m = tc.get_2d_diamond_problem()
+ all_bounds = obbt_analysis(m, solver=mip_solver)
+ assert all_bounds.keys() == m.continuous_bounds.keys()
+ for var, bounds in all_bounds.items():
+ assert_array_almost_equal(bounds, m.continuous_bounds[var])
+
+ def test_obbt_error1(self, mip_solver):
+ """
+ ERROR: Cannot restrict variable list when warmstart is specified
+ """
+ m = tc.get_2d_diamond_problem()
+ with unittest.pytest.raises(AssertionError):
+ obbt_analysis_bounds_and_solutions(m, variables=[m.x], solver=mip_solver)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_some_vars(self, mip_solver):
+ """
+ Check that the correct bounds are found for a continuous problem.
+ """
+ m = tc.get_2d_diamond_problem()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, variables=[m.x], warmstart=False, solver=mip_solver
+ )
+ assert len(all_bounds) == 1
+ assert len(solns) == 2 * len(all_bounds) + 1
+ for var, bounds in all_bounds.items():
+ assert_array_almost_equal(bounds, m.continuous_bounds[var])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_continuous(self, mip_solver):
+ """
+ Check that the correct bounds are found for a continuous problem.
+ """
+ m = tc.get_2d_diamond_problem()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(m, solver=mip_solver)
+ assert len(solns) == 2 * len(all_bounds) + 1
+ assert all_bounds.keys() == m.continuous_bounds.keys()
+ for var, bounds in all_bounds.items():
+ assert_array_almost_equal(bounds, m.continuous_bounds[var])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_rel_objective(self, mip_solver):
+ """
+ Check that relative mip gap constraints are added for a mip with indexed vars and constraints
+ """
+ m = tc.get_indexed_pentagonal_pyramid_mip()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, rel_opt_gap=0.5, solver=mip_solver
+ )
+ assert len(solns) == 2 * len(all_bounds) + 1
+ assert m._obbt.optimality_tol_rel.lb == unittest.pytest.approx(2.5)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_abs_objective(self, mip_solver):
+ """
+ Check that absolute mip gap constraints are added
+ """
+ m = tc.get_pentagonal_pyramid_mip()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, abs_opt_gap=1.99, solver=mip_solver
+ )
+ assert len(solns) == 2 * len(all_bounds) + 1
+ assert m._obbt.optimality_tol_abs.lb == unittest.pytest.approx(3.01)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_warmstart(self, mip_solver):
+ """
+ Check that warmstarting works.
+ """
+ m = tc.get_2d_diamond_problem()
+ m.x.value = 0
+ m.y.value = 0
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, solver=mip_solver, warmstart=True, tee=False
+ )
+ assert len(solns) == 2 * len(all_bounds) + 1
+ assert all_bounds.keys() == m.continuous_bounds.keys()
+ for var, bounds in all_bounds.items():
+ assert_array_almost_equal(bounds, m.continuous_bounds[var])
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_mip(self, mip_solver):
+ """
+ Check that bound tightening only occurs for continuous variables
+ that can be tightened.
+ """
+ m = tc.get_bloated_pentagonal_pyramid_mip()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, solver=mip_solver, tee=False
+ )
+ assert len(solns) == 2 * len(all_bounds) + 1
+ bounds_tightened = False
+ bounds_not_tightned = False
+ for var, bounds in all_bounds.items():
+ if bounds[0] > var.lb:
+ bounds_tightened = True
+ else:
+ bounds_not_tightened = True
+ if bounds[1] < var.ub:
+ bounds_tightened = True
+ else:
+ bounds_not_tightened = True
+ assert bounds_tightened
+ assert bounds_not_tightened
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_obbt_unbounded(self, mip_solver):
+ """
+ Check that the correct bounds are found for an unbounded problem.
+ """
+ m = tc.get_2d_unbounded_problem()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(m, solver=mip_solver)
+ assert all_bounds.keys() == m.continuous_bounds.keys()
+ num = 1
+ for var, bounds in all_bounds.items():
+ if not math.isinf(bounds[0]):
+ num += 1
+ if not math.isinf(bounds[1]):
+ num += 1
+ assert_array_almost_equal(bounds, m.continuous_bounds[var])
+ assert len(solns) == num
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_bound_tightening(self, mip_solver):
+ """
+ Check that the correct bounds are found for a discrete problem where
+ more restrictive bounds are implied by the constraints.
+ """
+ m = tc.get_implied_bound_ip()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(m, solver=mip_solver)
+ assert len(solns) == 2 * len(all_bounds) + 1
+ assert all_bounds.keys() == m.var_bounds.keys()
+ for var, bounds in all_bounds.items():
+ assert_array_almost_equal(bounds, m.var_bounds[var])
+
+ @unittest.skipIf(True, "Ignoring fragile test for solver timeout.")
+ def test_no_time(self, mip_solver):
+ """
+ Check that the correct bounds are found for a discrete problem where
+ more restrictive bounds are implied by the constraints.
+ """
+ m = tc.get_implied_bound_ip()
+ with unittest.pytest.raises(RuntimeError):
+ obbt_analysis_bounds_and_solutions(
+ m, solver=mip_solver, solver_options={timelimit[mip_solver]: 0}
+ )
+
+ def test_bound_refinement(self, mip_solver):
+ """
+ Check that the correct bounds are found for a discrete problem where
+ more restrictive bounds are implied by the constraints and constraints
+ are added.
+ """
+ m = tc.get_implied_bound_ip()
+ all_bounds, solns = obbt_analysis_bounds_and_solutions(
+ m, solver=mip_solver, refine_discrete_bounds=True
+ )
+ assert len(solns) == 2 * len(all_bounds) + 1
+ for var, bounds in all_bounds.items():
+ if m.var_bounds[var][0] > var.lb:
+ match = False
+ for idx in m._obbt.bound_constraints:
+ const = m._obbt.bound_constraints[idx]
+ if var is const.body and bounds[0] == const.lb:
+ match = True
+ break
+ assert match, "Constraint not found for {} lower bound {}".format(
+ var, bounds[0]
+ )
+ if m.var_bounds[var][1] < var.ub:
+ match = False
+ for idx in m._obbt.bound_constraints:
+ const = m._obbt.bound_constraints[idx]
+ if var is const.body and bounds[1] == const.ub:
+ match = True
+ break
+ assert match, "Constraint not found for {} upper bound {}".format(
+ var, bounds[1]
+ )
+
+ def test_obbt_infeasible(self, mip_solver):
+ """
+ Check that code catches cases where the problem is infeasible.
+ """
+ m = tc.get_2d_diamond_problem()
+ m.infeasible_constraint = pyo.Constraint(expr=m.x >= 10)
+ with unittest.pytest.raises(Exception):
+ obbt_analysis_bounds_and_solutions(m, solver=mip_solver)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/alternative_solutions/tests/test_shifted_lp.py b/pyomo/contrib/alternative_solutions/tests/test_shifted_lp.py
new file mode 100644
index 00000000000..0b13bc75b03
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_shifted_lp.py
@@ -0,0 +1,68 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 numpy, numpy_available
+
+if numpy_available:
+ from numpy.testing import assert_array_almost_equal
+
+import pyomo.environ as pyo
+import pyomo.opt
+from pyomo.common import unittest
+
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+from pyomo.contrib.alternative_solutions import shifted_lp
+
+# TODO: add checks that confirm the shifted constraints make sense
+
+#
+# Find available solvers. Just use GLPK if it's available.
+#
+solvers = list(pyomo.opt.check_available_solvers("glpk", "gurobi"))
+if "glpk" in solvers:
+ solver = ["glpk"]
+pytestmark = unittest.pytest.mark.parametrize("lp_solver", solvers)
+
+
+@unittest.pytest.mark.default
+class TestShiftedIP:
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_abs_objective(self, lp_solver):
+ m = tc.get_indexed_pentagonal_pyramid_mip()
+ m.x.domain = pyo.Reals
+
+ opt = pyo.SolverFactory(lp_solver)
+ old_results = opt.solve(m, tee=False)
+ old_obj = pyo.value(m.o)
+
+ new_model = shifted_lp.get_shifted_linear_model(m)
+ new_results = opt.solve(new_model, tee=False)
+ new_obj = pyo.value(new_model.objective)
+
+ assert old_obj == unittest.pytest.approx(new_obj)
+
+ def test_polyhedron(self, lp_solver):
+ m = tc.get_3d_polyhedron_problem()
+
+ opt = pyo.SolverFactory(lp_solver)
+ old_results = opt.solve(m, tee=False)
+ old_obj = pyo.value(m.o)
+
+ new_model = shifted_lp.get_shifted_linear_model(m)
+ new_results = opt.solve(new_model, tee=False)
+ new_obj = pyo.value(new_model.objective)
+
+ assert old_obj == unittest.pytest.approx(new_obj)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/alternative_solutions/tests/test_solnpool.py b/pyomo/contrib/alternative_solutions/tests/test_solnpool.py
new file mode 100644
index 00000000000..5fef32facc9
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_solnpool.py
@@ -0,0 +1,143 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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 collections import Counter
+
+from pyomo.common.dependencies import numpy as np, numpy_available
+from pyomo.common import unittest
+from pyomo.contrib.alternative_solutions import gurobi_generate_solutions
+from pyomo.contrib.appsi.solvers import Gurobi
+
+import pyomo.contrib.alternative_solutions.tests.test_cases as tc
+
+gurobipy_available = Gurobi().available()
+
+
+@unittest.skipIf(not gurobipy_available, "Gurobi MIP solver not available")
+class TestSolnPoolUnit(unittest.TestCase):
+ """
+ Cases to cover:
+
+ LP feasibility (for an LP just one solution should be returned since gurobi cannot enumerate over continuous vars)
+
+ Pass at least one solver option to make sure that work, e.g. time limit
+
+ We need a utility to check that a two sets of solutions are the same.
+ Maybe this should be an AOS utility since it may be a thing we will want to do often.
+ """
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_ip_feasibility(self):
+ """
+ Enumerate all solutions for an ip: triangle_ip.
+
+ Check that the correct number of alternate solutions are found.
+ """
+ m = tc.get_triangle_ip()
+ results = gurobi_generate_solutions(m, num_solutions=100)
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = m.num_ranked_solns
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_ip_num_solutions(self):
+ """
+ Enumerate 8 solutions for an ip: triangle_ip.
+
+ Check that the correct number of alternate solutions are found.
+ """
+ m = tc.get_triangle_ip()
+ results = gurobi_generate_solutions(m, num_solutions=8)
+ assert len(results) == 8
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = [6, 2]
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_feasibility(self):
+ """
+ Enumerate all solutions for a mip: indexed_pentagonal_pyramid_mip.
+
+ Check that the correct number of alternate solutions are found.
+ """
+ m = tc.get_indexed_pentagonal_pyramid_mip()
+ results = gurobi_generate_solutions(m, num_solutions=100)
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = m.num_ranked_solns
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_rel_feasibility(self):
+ """
+ Enumerate solutions for a mip: indexed_pentagonal_pyramid_mip.
+
+ Check that only solutions within a relative tolerance of 0.2 are
+ found.
+ """
+ m = tc.get_pentagonal_pyramid_mip()
+ results = gurobi_generate_solutions(m, num_solutions=100, rel_opt_gap=0.2)
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = m.num_ranked_solns[0:2]
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_rel_feasibility_options(self):
+ """
+ Enumerate solutions for a mip: indexed_pentagonal_pyramid_mip.
+
+ Check that only solutions within a relative tolerance of 0.2 are
+ found.
+ """
+ m = tc.get_pentagonal_pyramid_mip()
+ results = gurobi_generate_solutions(
+ m, num_solutions=100, solver_options={"PoolGap": 0.2}
+ )
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = m.num_ranked_solns[0:2]
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(not numpy_available, "Numpy not installed")
+ def test_mip_abs_feasibility(self):
+ """
+ Enumerate solutions for a mip: indexed_pentagonal_pyramid_mip.
+
+ Check that only solutions within an absolute tolerance of 1.99 are
+ found.
+ """
+ m = tc.get_pentagonal_pyramid_mip()
+ results = gurobi_generate_solutions(m, num_solutions=100, abs_opt_gap=1.99)
+ objectives = [round(result.objective[1], 2) for result in results]
+ actual_solns_by_obj = m.num_ranked_solns[0:3]
+ unique_solns_by_obj = [val for val in Counter(objectives).values()]
+ np.testing.assert_array_almost_equal(unique_solns_by_obj, actual_solns_by_obj)
+
+ @unittest.skipIf(True, "Ignoring fragile test for solver timeout.")
+ def test_mip_no_time(self):
+ """
+ Enumerate solutions for a mip: indexed_pentagonal_pyramid_mip.
+
+ Check that no solutions are returned with a timelimit of 0.
+ """
+ m = tc.get_pentagonal_pyramid_mip()
+ # Use quiet=False to test error message
+ results = gurobi_generate_solutions(
+ m, num_solutions=100, solver_options={"TimeLimit": 0.0}, quiet=False
+ )
+ assert len(results) == 0
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/alternative_solutions/tests/test_solution.py b/pyomo/contrib/alternative_solutions/tests/test_solution.py
new file mode 100644
index 00000000000..961068420be
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_solution.py
@@ -0,0 +1,93 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2025
+# 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.
+# ___________________________________________________________________________
+
+import pyomo.opt
+import pyomo.environ as pyo
+import pyomo.common.unittest as unittest
+import pyomo.contrib.alternative_solutions.aos_utils as au
+from pyomo.contrib.alternative_solutions import Solution
+
+mip_solver = "gurobi"
+mip_available = pyomo.opt.check_available_solvers(mip_solver)
+
+
+class TestSolutionUnit(unittest.TestCase):
+
+ def get_model(self):
+ """
+ Simple model with all variable types and fixed variables to test the
+ Solution code.
+ """
+ m = pyo.ConcreteModel()
+ m.x = pyo.Var(domain=pyo.NonNegativeReals)
+ m.y = pyo.Var(domain=pyo.Binary)
+ m.z = pyo.Var(domain=pyo.NonNegativeIntegers)
+ m.f = pyo.Var(domain=pyo.Reals)
+
+ m.f.fix(1)
+ m.obj = pyo.Objective(expr=m.x + m.y + m.z + m.f, sense=pyo.maximize)
+
+ m.con_x = pyo.Constraint(expr=m.x <= 1.5)
+ m.con_y = pyo.Constraint(expr=m.y <= 1)
+ m.con_z = pyo.Constraint(expr=m.z <= 3)
+ return m
+
+ @unittest.skipUnless(mip_available, "MIP solver not available")
+ def test_solution(self):
+ """
+ Create a Solution Object, call its functions, and ensure the correct
+ data is returned.
+ """
+ model = self.get_model()
+ opt = pyo.SolverFactory(mip_solver)
+ opt.solve(model)
+ all_vars = au.get_model_variables(model, include_fixed=True)
+
+ solution = Solution(model, all_vars, include_fixed=False)
+ sol_str = """{
+ "fixed_variables": [
+ "f"
+ ],
+ "objective": "obj",
+ "objective_value": 6.5,
+ "solution": {
+ "x": 1.5,
+ "y": 1,
+ "z": 3
+ }
+}"""
+ assert str(solution) == sol_str
+
+ solution = Solution(model, all_vars)
+ sol_str = """{
+ "fixed_variables": [
+ "f"
+ ],
+ "objective": "obj",
+ "objective_value": 6.5,
+ "solution": {
+ "f": 1,
+ "x": 1.5,
+ "y": 1,
+ "z": 3
+ }
+}"""
+ assert solution.to_string(round_discrete=True) == sol_str
+
+ sol_val = solution.get_variable_name_values(
+ include_fixed=True, round_discrete=True
+ )
+ self.assertEqual(set(sol_val.keys()), {"x", "y", "z", "f"})
+ self.assertEqual(set(solution.get_fixed_variable_names()), {"f"})
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/pyomo/contrib/ampl_function_demo/__init__.py b/pyomo/contrib/ampl_function_demo/__init__.py
index a4a626013c4..6eb9ea8b81d 100644
--- a/pyomo/contrib/ampl_function_demo/__init__.py
+++ b/pyomo/contrib/ampl_function_demo/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/ampl_function_demo/build.py b/pyomo/contrib/ampl_function_demo/build.py
index 764a613b3d7..10b9667aded 100644
--- a/pyomo/contrib/ampl_function_demo/build.py
+++ b/pyomo/contrib/ampl_function_demo/build.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/ampl_function_demo/plugins.py b/pyomo/contrib/ampl_function_demo/plugins.py
index 5a200174c43..b06dc08614c 100644
--- a/pyomo/contrib/ampl_function_demo/plugins.py
+++ b/pyomo/contrib/ampl_function_demo/plugins.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/ampl_function_demo/src/CMakeLists.txt b/pyomo/contrib/ampl_function_demo/src/CMakeLists.txt
index 67efc13d3c8..447a9897a3b 100644
--- a/pyomo/contrib/ampl_function_demo/src/CMakeLists.txt
+++ b/pyomo/contrib/ampl_function_demo/src/CMakeLists.txt
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,8 +9,8 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-cmake_minimum_required(VERSION 3.0)
-# CMake 3.0 needed by AMPL/asl build
+cmake_minimum_required(VERSION 3.0...3.31)
+# This was developed against CMake 3.0, and appears to comply with 3.5
PROJECT( ampl_function_demo )
diff --git a/pyomo/contrib/ampl_function_demo/src/FindASL.cmake b/pyomo/contrib/ampl_function_demo/src/FindASL.cmake
index 8bbc048fa6e..73c263e5d20 100644
--- a/pyomo/contrib/ampl_function_demo/src/FindASL.cmake
+++ b/pyomo/contrib/ampl_function_demo/src/FindASL.cmake
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -9,15 +9,21 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-cmake_minimum_required(VERSION 3.0)
-# Minimum version inherited from AMPL/asl
+cmake_minimum_required(VERSION 3.0...3.31)
+# CMake 3.0 added GIT_SUBMODULES to ExternalProject_ADD, and without it
+# the Ampl/MP checkout fails because one of the submodules (gecode) is a
+# private repository.
+#
+# CMake will complain/fail if we don't explicitly acknowledge 3.5
+# compatibility. AMPL/asl has moved their min version to 3.5.
include(ExternalProject)
# Dependencies that we manage / can install
-SET(AMPLASL_TAG "9fb7cb8e4f68ed1c3bc066d191e63698b7d7d1d2" CACHE STRING
+SET(AMPLASL_TAG "ae937db9bd1169ec2c4cb8d75196f67cdcb8041b" CACHE STRING
"AMPL/asl git tag/branch to checkout and build")
-# 9fb7cb8e4f68ed1c3bc066d191e63698b7d7d1d2 corresponds to ASLdate = 20211109
+# 9fb7cb8e4f68ed1c3bc066d191e63698b7d7d1d2: ASLdate=20211109
+# ae937db9bd1169ec2c4cb8d75196f67cdcb8041b: v1.0.1 ASLdate = 20241202/20241122
OPTION(BUILD_AMPLASL
"Download and build AMPL/asl ${AMPLASL_TAG} from GitHub" OFF)
diff --git a/pyomo/contrib/ampl_function_demo/src/functions.c b/pyomo/contrib/ampl_function_demo/src/functions.c
index e87af745aea..fd4372693e7 100644
--- a/pyomo/contrib/ampl_function_demo/src/functions.c
+++ b/pyomo/contrib/ampl_function_demo/src/functions.c
@@ -1,6 +1,6 @@
/* ___________________________________________________________________________
* Pyomo: Python Optimization Modeling Objects
- * Copyright (c) 2008-2024
+ * Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/ampl_function_demo/tests/__init__.py b/pyomo/contrib/ampl_function_demo/tests/__init__.py
index a4a626013c4..6eb9ea8b81d 100644
--- a/pyomo/contrib/ampl_function_demo/tests/__init__.py
+++ b/pyomo/contrib/ampl_function_demo/tests/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/ampl_function_demo/tests/test_ampl_function_demo.py b/pyomo/contrib/ampl_function_demo/tests/test_ampl_function_demo.py
index 39890494d55..196d6b2f4e9 100644
--- a/pyomo/contrib/ampl_function_demo/tests/test_ampl_function_demo.py
+++ b/pyomo/contrib/ampl_function_demo/tests/test_ampl_function_demo.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/appsi/__init__.py b/pyomo/contrib/appsi/__init__.py
index 2f06fc89e70..a9ae3d21d58 100644
--- a/pyomo/contrib/appsi/__init__.py
+++ b/pyomo/contrib/appsi/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/appsi/base.py b/pyomo/contrib/appsi/base.py
index 201e5975ac9..0f7cfda4437 100644
--- a/pyomo/contrib/appsi/base.py
+++ b/pyomo/contrib/appsi/base.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -11,6 +11,10 @@
import abc
import enum
+import os
+import re
+import weakref
+
from typing import (
Sequence,
Dict,
@@ -21,21 +25,22 @@
Tuple,
MutableMapping,
)
-from pyomo.core.base.constraint import _GeneralConstraintData, Constraint
-from pyomo.core.base.sos import _SOSConstraintData, SOSConstraint
-from pyomo.core.base.var import _GeneralVarData, Var
-from pyomo.core.base.param import _ParamData, Param
-from pyomo.core.base.block import _BlockData, Block
-from pyomo.core.base.objective import _GeneralObjectiveData
+
+from pyomo.common.config import ConfigDict, ConfigValue, NonNegativeFloat
+from pyomo.common.errors import ApplicationError
+from pyomo.common.enums import IntEnum
+from pyomo.common.factory import Factory
+from pyomo.common.timing import HierarchicalTimer
+from pyomo.core.base.constraint import ConstraintData, Constraint
+from pyomo.core.base.sos import SOSConstraintData, SOSConstraint
+from pyomo.core.base.var import VarData, Var
+from pyomo.core.base.param import ParamData, Param
+from pyomo.core.base.block import BlockData, Block
+from pyomo.core.base.objective import ObjectiveData
from pyomo.common.collections import ComponentMap
from .utils.get_objective import get_objective
from .utils.collect_vars_and_named_exprs import collect_vars_and_named_exprs
-from pyomo.common.timing import HierarchicalTimer
-from pyomo.common.config import ConfigDict, ConfigValue, NonNegativeFloat
-from pyomo.common.errors import ApplicationError
from pyomo.opt.base import SolverFactory as LegacySolverFactory
-from pyomo.common.factory import Factory
-import os
from pyomo.opt.results.results_ import SolverResults as LegacySolverResults
from pyomo.opt.results.solution import (
Solution as LegacySolution,
@@ -47,7 +52,6 @@
)
from pyomo.core.kernel.objective import minimize
from pyomo.core.base import SymbolMap
-import weakref
from .cmodel import cmodel, cmodel_available
from pyomo.core.staleflag import StaleFlagManager
from pyomo.core.expr.numvalue import NumericConstant
@@ -97,6 +101,9 @@ class TerminationCondition(enum.Enum):
class SolverConfig(ConfigDict):
"""
+ Common configuration options for all APPSI solver interfaces
+
+
Attributes
----------
time_limit: float
@@ -132,12 +139,14 @@ def __init__(
)
self.declare('time_limit', ConfigValue(domain=NonNegativeFloat))
+ self.declare('warmstart', ConfigValue(domain=bool))
self.declare('stream_solver', ConfigValue(domain=bool))
self.declare('load_solution', ConfigValue(domain=bool))
self.declare('symbolic_solver_labels', ConfigValue(domain=bool))
self.declare('report_timing', ConfigValue(domain=bool))
self.time_limit: Optional[float] = None
+ self.warmstart: bool = False
self.stream_solver: bool = False
self.load_solution: bool = True
self.symbolic_solver_labels: bool = False
@@ -146,6 +155,8 @@ def __init__(
class MIPSolverConfig(SolverConfig):
"""
+ Configuration options common to all MIP solvers
+
Attributes
----------
mip_gap: float
@@ -179,9 +190,7 @@ def __init__(
class SolutionLoaderBase(abc.ABC):
- def load_vars(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> NoReturn:
+ def load_vars(self, vars_to_load: Optional[Sequence[VarData]] = None) -> NoReturn:
"""
Load the solution of the primal variables into the value attribute of the variables.
@@ -197,8 +206,8 @@ def load_vars(
@abc.abstractmethod
def get_primals(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
"""
Returns a ComponentMap mapping variable to var value.
@@ -216,8 +225,8 @@ def get_primals(
pass
def get_duals(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
"""
Returns a dictionary mapping constraint to dual value.
@@ -235,8 +244,8 @@ def get_duals(
raise NotImplementedError(f'{type(self)} does not support the get_duals method')
def get_slacks(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
"""
Returns a dictionary mapping constraint to slack.
@@ -256,8 +265,8 @@ def get_slacks(
)
def get_reduced_costs(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
"""
Returns a ComponentMap mapping variable to reduced cost.
@@ -303,8 +312,8 @@ def __init__(
self._reduced_costs = reduced_costs
def get_primals(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
if self._primals is None:
raise RuntimeError(
'Solution loader does not currently have a valid solution. Please '
@@ -319,8 +328,8 @@ def get_primals(
return primals
def get_duals(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
if self._duals is None:
raise RuntimeError(
'Solution loader does not currently have valid duals. Please '
@@ -336,8 +345,8 @@ def get_duals(
return duals
def get_slacks(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
if self._slacks is None:
raise RuntimeError(
'Solution loader does not currently have valid slacks. Please '
@@ -353,8 +362,8 @@ def get_slacks(
return slacks
def get_reduced_costs(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
if self._reduced_costs is None:
raise RuntimeError(
'Solution loader does not currently have valid reduced costs. Please '
@@ -372,6 +381,8 @@ def get_reduced_costs(
class Results(object):
"""
+ Base class for all APPSI solver results
+
Attributes
----------
termination_condition: TerminationCondition
@@ -387,13 +398,15 @@ class Results(object):
For solvers that do not provide an objective bound, this should be -inf
(minimization) or inf (maximization)
+ Example
+ -------
Here is an example workflow:
- >>> import pyomo.environ as pe
+ >>> import pyomo.environ as pyo
>>> from pyomo.contrib import appsi
- >>> m = pe.ConcreteModel()
- >>> m.x = pe.Var()
- >>> m.obj = pe.Objective(expr=m.x**2)
+ >>> m = pyo.ConcreteModel()
+ >>> m.x = pyo.Var()
+ >>> m.obj = pyo.Objective(expr=m.x**2)
>>> opt = appsi.solvers.Ipopt()
>>> opt.config.load_solution = False
>>> results = opt.solve(m) #doctest:+SKIP
@@ -429,6 +442,8 @@ def __str__(self):
class UpdateConfig(ConfigDict):
"""
+ Config options common to all persistent solvers
+
Attributes
----------
check_for_new_or_removed_constraints: bool
@@ -596,7 +611,7 @@ def __init__(
class Solver(abc.ABC):
- class Availability(enum.IntEnum):
+ class Availability(IntEnum):
NotFound = 0
BadVersion = -1
BadLicense = -2
@@ -621,20 +636,20 @@ def __str__(self):
return self.name
@abc.abstractmethod
- def solve(self, model: _BlockData, timer: HierarchicalTimer = None) -> Results:
+ def solve(self, model: BlockData, timer: HierarchicalTimer = None) -> Results:
"""
Solve a Pyomo model.
Parameters
----------
- model: _BlockData
+ model: BlockData
The Pyomo model to be solved
timer: HierarchicalTimer
An option timer for reporting timing
Returns
-------
- results: Results
+ results: ~pyomo.contrib.appsi.base.Results
A results object
"""
pass
@@ -683,7 +698,7 @@ def config(self):
Returns
-------
- SolverConfig
+ ~pyomo.contrib.appsi.base.SolverConfig
An object for configuring pyomo solve options such as the time limit.
These options are mostly independent of the solver.
"""
@@ -708,9 +723,7 @@ class PersistentSolver(Solver):
def is_persistent(self):
return True
- def load_vars(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> NoReturn:
+ def load_vars(self, vars_to_load: Optional[Sequence[VarData]] = None) -> NoReturn:
"""
Load the solution of the primal variables into the value attribute of the variables.
@@ -726,13 +739,13 @@ def load_vars(
@abc.abstractmethod
def get_primals(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
pass
def get_duals(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
"""
Declare sign convention in docstring here.
@@ -752,8 +765,8 @@ def get_duals(
)
def get_slacks(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
"""
Parameters
----------
@@ -771,8 +784,8 @@ def get_slacks(
)
def get_reduced_costs(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
"""
Parameters
----------
@@ -799,43 +812,43 @@ def set_instance(self, model):
pass
@abc.abstractmethod
- def add_variables(self, variables: List[_GeneralVarData]):
+ def add_variables(self, variables: List[VarData]):
pass
@abc.abstractmethod
- def add_params(self, params: List[_ParamData]):
+ def add_params(self, params: List[ParamData]):
pass
@abc.abstractmethod
- def add_constraints(self, cons: List[_GeneralConstraintData]):
+ def add_constraints(self, cons: List[ConstraintData]):
pass
@abc.abstractmethod
- def add_block(self, block: _BlockData):
+ def add_block(self, block: BlockData):
pass
@abc.abstractmethod
- def remove_variables(self, variables: List[_GeneralVarData]):
+ def remove_variables(self, variables: List[VarData]):
pass
@abc.abstractmethod
- def remove_params(self, params: List[_ParamData]):
+ def remove_params(self, params: List[ParamData]):
pass
@abc.abstractmethod
- def remove_constraints(self, cons: List[_GeneralConstraintData]):
+ def remove_constraints(self, cons: List[ConstraintData]):
pass
@abc.abstractmethod
- def remove_block(self, block: _BlockData):
+ def remove_block(self, block: BlockData):
pass
@abc.abstractmethod
- def set_objective(self, obj: _GeneralObjectiveData):
+ def set_objective(self, obj: ObjectiveData):
pass
@abc.abstractmethod
- def update_variables(self, variables: List[_GeneralVarData]):
+ def update_variables(self, variables: List[VarData]):
pass
@abc.abstractmethod
@@ -857,20 +870,20 @@ def get_primals(self, vars_to_load=None):
return self._solver.get_primals(vars_to_load=vars_to_load)
def get_duals(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
self._assert_solution_still_valid()
return self._solver.get_duals(cons_to_load=cons_to_load)
def get_slacks(
- self, cons_to_load: Optional[Sequence[_GeneralConstraintData]] = None
- ) -> Dict[_GeneralConstraintData, float]:
+ self, cons_to_load: Optional[Sequence[ConstraintData]] = None
+ ) -> Dict[ConstraintData, float]:
self._assert_solution_still_valid()
return self._solver.get_slacks(cons_to_load=cons_to_load)
def get_reduced_costs(
- self, vars_to_load: Optional[Sequence[_GeneralVarData]] = None
- ) -> Mapping[_GeneralVarData, float]:
+ self, vars_to_load: Optional[Sequence[VarData]] = None
+ ) -> Mapping[VarData, float]:
self._assert_solution_still_valid()
return self._solver.get_reduced_costs(vars_to_load=vars_to_load)
@@ -954,10 +967,10 @@ def set_instance(self, model):
self.set_objective(None)
@abc.abstractmethod
- def _add_variables(self, variables: List[_GeneralVarData]):
+ def _add_variables(self, variables: List[VarData]):
pass
- def add_variables(self, variables: List[_GeneralVarData]):
+ def add_variables(self, variables: List[VarData]):
for v in variables:
if id(v) in self._referenced_variables:
raise ValueError(
@@ -975,19 +988,19 @@ def add_variables(self, variables: List[_GeneralVarData]):
self._add_variables(variables)
@abc.abstractmethod
- def _add_params(self, params: List[_ParamData]):
+ def _add_params(self, params: List[ParamData]):
pass
- def add_params(self, params: List[_ParamData]):
+ def add_params(self, params: List[ParamData]):
for p in params:
self._params[id(p)] = p
self._add_params(params)
@abc.abstractmethod
- def _add_constraints(self, cons: List[_GeneralConstraintData]):
+ def _add_constraints(self, cons: List[ConstraintData]):
pass
- def _check_for_new_vars(self, variables: List[_GeneralVarData]):
+ def _check_for_new_vars(self, variables: List[VarData]):
new_vars = dict()
for v in variables:
v_id = id(v)
@@ -995,7 +1008,7 @@ def _check_for_new_vars(self, variables: List[_GeneralVarData]):
new_vars[v_id] = v
self.add_variables(list(new_vars.values()))
- def _check_to_remove_vars(self, variables: List[_GeneralVarData]):
+ def _check_to_remove_vars(self, variables: List[VarData]):
vars_to_remove = dict()
for v in variables:
v_id = id(v)
@@ -1004,14 +1017,14 @@ def _check_to_remove_vars(self, variables: List[_GeneralVarData]):
vars_to_remove[v_id] = v
self.remove_variables(list(vars_to_remove.values()))
- def add_constraints(self, cons: List[_GeneralConstraintData]):
+ def add_constraints(self, cons: List[ConstraintData]):
all_fixed_vars = dict()
for con in cons:
if con in self._named_expressions:
raise ValueError(
'constraint {name} has already been added'.format(name=con.name)
)
- self._active_constraints[con] = (con.lower, con.body, con.upper)
+ self._active_constraints[con] = con.expr
if self.use_extensions and cmodel_available:
tmp = cmodel.prep_for_repn(con.body, self._expr_types)
else:
@@ -1034,10 +1047,10 @@ def add_constraints(self, cons: List[_GeneralConstraintData]):
v.fix()
@abc.abstractmethod
- def _add_sos_constraints(self, cons: List[_SOSConstraintData]):
+ def _add_sos_constraints(self, cons: List[SOSConstraintData]):
pass
- def add_sos_constraints(self, cons: List[_SOSConstraintData]):
+ def add_sos_constraints(self, cons: List[SOSConstraintData]):
for con in cons:
if con in self._vars_referenced_by_con:
raise ValueError(
@@ -1054,10 +1067,10 @@ def add_sos_constraints(self, cons: List[_SOSConstraintData]):
self._add_sos_constraints(cons)
@abc.abstractmethod
- def _set_objective(self, obj: _GeneralObjectiveData):
+ def _set_objective(self, obj: ObjectiveData):
pass
- def set_objective(self, obj: _GeneralObjectiveData):
+ def set_objective(self, obj: ObjectiveData):
if self._objective is not None:
for v in self._vars_referenced_by_obj:
self._referenced_variables[id(v)][2] = None
@@ -1132,10 +1145,10 @@ def add_block(self, block):
self.set_objective(obj)
@abc.abstractmethod
- def _remove_constraints(self, cons: List[_GeneralConstraintData]):
+ def _remove_constraints(self, cons: List[ConstraintData]):
pass
- def remove_constraints(self, cons: List[_GeneralConstraintData]):
+ def remove_constraints(self, cons: List[ConstraintData]):
self._remove_constraints(cons)
for con in cons:
if con not in self._named_expressions:
@@ -1154,10 +1167,10 @@ def remove_constraints(self, cons: List[_GeneralConstraintData]):
del self._vars_referenced_by_con[con]
@abc.abstractmethod
- def _remove_sos_constraints(self, cons: List[_SOSConstraintData]):
+ def _remove_sos_constraints(self, cons: List[SOSConstraintData]):
pass
- def remove_sos_constraints(self, cons: List[_SOSConstraintData]):
+ def remove_sos_constraints(self, cons: List[SOSConstraintData]):
self._remove_sos_constraints(cons)
for con in cons:
if con not in self._vars_referenced_by_con:
@@ -1174,10 +1187,10 @@ def remove_sos_constraints(self, cons: List[_SOSConstraintData]):
del self._vars_referenced_by_con[con]
@abc.abstractmethod
- def _remove_variables(self, variables: List[_GeneralVarData]):
+ def _remove_variables(self, variables: List[VarData]):
pass
- def remove_variables(self, variables: List[_GeneralVarData]):
+ def remove_variables(self, variables: List[VarData]):
self._remove_variables(variables)
for v in variables:
v_id = id(v)
@@ -1198,10 +1211,10 @@ def remove_variables(self, variables: List[_GeneralVarData]):
del self._vars[v_id]
@abc.abstractmethod
- def _remove_params(self, params: List[_ParamData]):
+ def _remove_params(self, params: List[ParamData]):
pass
- def remove_params(self, params: List[_ParamData]):
+ def remove_params(self, params: List[ParamData]):
self._remove_params(params)
for p in params:
del self._params[id(p)]
@@ -1246,10 +1259,10 @@ def remove_block(self, block):
)
@abc.abstractmethod
- def _update_variables(self, variables: List[_GeneralVarData]):
+ def _update_variables(self, variables: List[VarData]):
pass
- def update_variables(self, variables: List[_GeneralVarData]):
+ def update_variables(self, variables: List[VarData]):
for v in variables:
self._vars[id(v)] = (
v,
@@ -1334,12 +1347,12 @@ def update(self, timer: HierarchicalTimer = None):
for c in self._vars_referenced_by_con.keys():
if c not in current_cons_dict and c not in current_sos_dict:
if (c.ctype is Constraint) or (
- c.ctype is None and isinstance(c, _GeneralConstraintData)
+ c.ctype is None and isinstance(c, ConstraintData)
):
old_cons.append(c)
else:
assert (c.ctype is SOSConstraint) or (
- c.ctype is None and isinstance(c, _SOSConstraintData)
+ c.ctype is None and isinstance(c, SOSConstraintData)
)
old_sos.append(c)
self.remove_constraints(old_cons)
@@ -1367,40 +1380,13 @@ def update(self, timer: HierarchicalTimer = None):
cons_to_remove_and_add = dict()
need_to_set_objective = False
if config.update_constraints:
- cons_to_update = list()
- sos_to_update = list()
for c in current_cons_dict.keys():
- if c not in new_cons_set:
- cons_to_update.append(c)
+ if c not in new_cons_set and c.expr is not self._active_constraints[c]:
+ cons_to_remove_and_add[c] = None
+ sos_to_update = []
for c in current_sos_dict.keys():
if c not in new_sos_set:
sos_to_update.append(c)
- for c in cons_to_update:
- lower, body, upper = self._active_constraints[c]
- new_lower, new_body, new_upper = c.lower, c.body, c.upper
- if new_body is not body:
- cons_to_remove_and_add[c] = None
- continue
- if new_lower is not lower:
- if (
- type(new_lower) is NumericConstant
- and type(lower) is NumericConstant
- and new_lower.value == lower.value
- ):
- pass
- else:
- cons_to_remove_and_add[c] = None
- continue
- if new_upper is not upper:
- if (
- type(new_upper) is NumericConstant
- and type(upper) is NumericConstant
- and new_upper.value == upper.value
- ):
- pass
- else:
- cons_to_remove_and_add[c] = None
- continue
self.remove_sos_constraints(sos_to_update)
self.add_sos_constraints(sos_to_update)
timer.stop('cons')
@@ -1529,7 +1515,7 @@ def update(self, timer: HierarchicalTimer = None):
class LegacySolverInterface(object):
def solve(
self,
- model: _BlockData,
+ model: BlockData,
tee: bool = False,
load_solutions: bool = True,
logfile: Optional[str] = None,
@@ -1541,6 +1527,7 @@ def solve(
options: Optional[Dict] = None,
keepfiles: bool = False,
symbolic_solver_labels: bool = False,
+ warmstart: bool = False,
):
original_config = self.config
self.config = self.config()
@@ -1548,6 +1535,7 @@ def solve(
self.config.load_solution = load_solutions
self.config.symbolic_solver_labels = symbolic_solver_labels
self.config.time_limit = timelimit
+ self.config.warmstart = warmstart
self.config.report_timing = report_timing
if solver_io is not None:
raise NotImplementedError('Still working on this')
@@ -1665,7 +1653,7 @@ def license_is_valid(self) -> bool:
@property
def options(self):
- for solver_name in ['gurobi', 'ipopt', 'cplex', 'cbc', 'highs']:
+ for solver_name in ['gurobi', 'ipopt', 'cplex', 'cbc', 'highs', 'maingo']:
if hasattr(self, solver_name + '_options'):
return getattr(self, solver_name + '_options')
raise NotImplementedError('Could not find the correct options')
@@ -1673,7 +1661,7 @@ def options(self):
@options.setter
def options(self, val):
found = False
- for solver_name in ['gurobi', 'ipopt', 'cplex', 'cbc', 'highs']:
+ for solver_name in ['gurobi', 'ipopt', 'cplex', 'cbc', 'highs', 'maingo']:
if hasattr(self, solver_name + '_options'):
setattr(self, solver_name + '_options', val)
found = True
diff --git a/pyomo/contrib/appsi/build.py b/pyomo/contrib/appsi/build.py
index b3d78467f01..3412fb9fc42 100644
--- a/pyomo/contrib/appsi/build.py
+++ b/pyomo/contrib/appsi/build.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
@@ -16,15 +16,6 @@
import tempfile
-def handleReadonly(function, path, excinfo):
- excvalue = excinfo[1]
- if excvalue.errno == errno.EACCES:
- os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
- function(path)
- else:
- raise
-
-
def get_appsi_extension(in_setup=False, appsi_root=None):
from pybind11.setup_helpers import Pybind11Extension
@@ -66,6 +57,7 @@ def build_appsi(args=[]):
from setuptools import Distribution
from pybind11.setup_helpers import build_ext
import pybind11.setup_helpers
+ from pyomo.common.cmake_builder import handleReadonly
from pyomo.common.envvar import PYOMO_CONFIG_DIR
from pyomo.common.fileutils import this_file_dir
diff --git a/pyomo/contrib/appsi/cmodel/__init__.py b/pyomo/contrib/appsi/cmodel/__init__.py
index cc2aec28241..51978672d27 100644
--- a/pyomo/contrib/appsi/cmodel/__init__.py
+++ b/pyomo/contrib/appsi/cmodel/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2024
+# Copyright (c) 2008-2025
# 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
diff --git a/pyomo/contrib/appsi/cmodel/src/cmodel_bindings.cpp b/pyomo/contrib/appsi/cmodel/src/cmodel_bindings.cpp
index 6acc1d79845..3fc2d621dd4 100644
--- a/pyomo/contrib/appsi/cmodel/src/cmodel_bindings.cpp
+++ b/pyomo/contrib/appsi/cmodel/src/cmodel_bindings.cpp
@@ -1,7 +1,7 @@
/**___________________________________________________________________________
*
* Pyomo: Python Optimization Modeling Objects
- * Copyright (c) 2008-2024
+ * Copyright (c) 2008-2025
# 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
@@ -63,7 +63,8 @@ PYBIND11_MODULE(appsi_cmodel, m) {
m.def("appsi_exprs_from_pyomo_exprs", &appsi_exprs_from_pyomo_exprs);
m.def("appsi_expr_from_pyomo_expr", &appsi_expr_from_pyomo_expr);
m.def("prep_for_repn", &prep_for_repn);
- py::class_(m, "PyomoExprTypes").def(py::init<>());
+ py::class_(m, "PyomoExprTypes", py::module_local())
+ .def(py::init<>());
py::class_>(m, "Node")
.def("is_variable_type", &Node::is_variable_type)
.def("is_param_type", &Node::is_param_type)
@@ -165,7 +166,7 @@ PYBIND11_MODULE(appsi_cmodel, m) {
.def(py::init<>())
.def("write", &LPWriter::write)
.def("get_solve_cons", &LPWriter::get_solve_cons);
- py::enum_(m, "ExprType")
+ py::enum_(m, "ExprType", py::module_local())
.value("py_float", ExprType::py_float)
.value("var", ExprType::var)
.value("param", ExprType::param)
diff --git a/pyomo/contrib/appsi/cmodel/src/common.cpp b/pyomo/contrib/appsi/cmodel/src/common.cpp
index 6f8002cb50e..6681c3f7a45 100644
--- a/pyomo/contrib/appsi/cmodel/src/common.cpp
+++ b/pyomo/contrib/appsi/cmodel/src/common.cpp
@@ -1,7 +1,7 @@
/**___________________________________________________________________________
*
* Pyomo: Python Optimization Modeling Objects
- * Copyright (c) 2008-2024
+ * Copyright (c) 2008-2025
* 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
diff --git a/pyomo/contrib/appsi/cmodel/src/common.hpp b/pyomo/contrib/appsi/cmodel/src/common.hpp
index 9edc9571a4d..ad196010e23 100644
--- a/pyomo/contrib/appsi/cmodel/src/common.hpp
+++ b/pyomo/contrib/appsi/cmodel/src/common.hpp
@@ -1,7 +1,7 @@
/**___________________________________________________________________________
*
* Pyomo: Python Optimization Modeling Objects
- * Copyright (c) 2008-2024
+ * Copyright (c) 2008-2025
* 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
diff --git a/pyomo/contrib/appsi/cmodel/src/expression.cpp b/pyomo/contrib/appsi/cmodel/src/expression.cpp
index 234ef47e86f..cf2e7b9f189 100644
--- a/pyomo/contrib/appsi/cmodel/src/expression.cpp
+++ b/pyomo/contrib/appsi/cmodel/src/expression.cpp
@@ -1,7 +1,7 @@
/**___________________________________________________________________________
*
* Pyomo: Python Optimization Modeling Objects
- * Copyright (c) 2008-2024
+ * Copyright (c) 2008-2025
* 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
@@ -1548,7 +1548,10 @@ appsi_operator_from_pyomo_expr(py::handle expr, py::handle var_map,
break;
}
case param: {
- res = param_map[expr_types.id(expr)].cast