diff --git a/.coin-or/projDesc.xml b/.coin-or/projDesc.xml
index 1ee247e100f..b5da0efb6fa 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.8.2
+ 6.8.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/.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 ef44806d6d4..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,46 +16,101 @@ 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:
name: Build wheels (${{ matrix.wheel-version }}) on ${{ matrix.os }} for native and cross-compiled architecture
runs-on: ${{ matrix.os }}
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: '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.2
+ 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
+ name: native_wheels-${{ matrix.os }}-${{ matrix.TARGET }}
path: dist/*.whl
+ overwrite: true
alternative_wheels:
name: Build wheels (${{ matrix.wheel-version }}) on ${{ matrix.os }} for aarch64
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: '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
@@ -61,21 +118,56 @@ 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.2
+ 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
+ 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 }}
@@ -87,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 }}
@@ -106,4 +198,5 @@ jobs:
with:
name: generictarball
path: dist
+ overwrite: true
diff --git a/.github/workflows/test_branches.yml b/.github/workflows/test_branches.yml
index e5513d25975..caedbfc8fdd 100644
--- a/.github/workflows/test_branches.yml
+++ b/.github/workflows/test_branches.yml
@@ -21,8 +21,8 @@ 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 }}
@@ -40,12 +40,27 @@ 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
+ 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,29 +71,29 @@ 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
TARGET: linux
PYENV: pip
- os: macos-latest
- python: '3.10'
+ python: 3.12
TARGET: osx
PYENV: pip
- os: windows-latest
- python: 3.9
+ python: 3.11
TARGET: win
PYENV: conda
- PACKAGES: glpk pytest-qt
+ PACKAGES: glpk pytest-qt filelock
- os: ubuntu-latest
- python: '3.11'
+ python: 3.11
other: /conda
skip_doctest: 1
TARGET: linux
@@ -86,16 +101,16 @@ jobs:
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
@@ -104,7 +119,7 @@ jobs:
PACKAGES: cython
- os: windows-latest
- python: 3.8
+ python: 3.9
other: /pip
skip_doctest: 1
TARGET: win
@@ -180,7 +195,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 +207,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 +234,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 +280,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
@@ -320,6 +338,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 +355,33 @@ 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() (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.0'
+ else
+ XPRESS='xpress'
+ fi
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
@@ -364,6 +403,7 @@ jobs:
conda install -y "$PKG" || _BUILDS=""
fi
fi
+ echo ""
if test -z "$_BUILDS"; then
echo "WARNING: $PKG is not available"
fi
@@ -401,6 +441,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,6 +451,8 @@ jobs:
IPOPT_DIR=$TPL_DIR/ipopt
echo "$IPOPT_DIR" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LD_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
@@ -484,7 +529,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 +548,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 +593,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"
@@ -610,6 +670,11 @@ 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
@@ -618,6 +683,7 @@ jobs:
- name: Run Pyomo tests
if: matrix.mpi == 0
run: |
+ export PATH=$PYOMO_PATH
$PYTHON_EXE -m pytest -v \
-W ignore::Warning ${{matrix.category}} \
pyomo `pwd`/pyomo-model-libraries \
@@ -631,7 +697,7 @@ jobs:
$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
@@ -651,6 +717,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 +727,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: |
@@ -708,12 +775,12 @@ jobs:
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 +795,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
diff --git a/.github/workflows/test_pr_and_main.yml b/.github/workflows/test_pr_and_main.yml
index c5028606c17..0bd5cac42ea 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,8 +29,8 @@ 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 }}
@@ -34,6 +39,8 @@ jobs:
lint:
name: lint/style-and-typos
runs-on: ubuntu-latest
+ if: |
+ contains(github.event.pull_request.title, '[WIP]') != true && !github.event.pull_request.draft
steps:
- name: Checkout Pyomo source
uses: actions/checkout@v4
@@ -43,7 +50,8 @@ 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
@@ -60,7 +68,7 @@ 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: [""]
@@ -76,10 +84,10 @@ jobs:
- os: windows-latest
TARGET: win
PYENV: conda
- PACKAGES: glpk pytest-qt
+ PACKAGES: glpk pytest-qt filelock
- os: ubuntu-latest
- python: '3.11'
+ python: 3.11
other: /conda
skip_doctest: 1
TARGET: linux
@@ -87,24 +95,16 @@ jobs:
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
-
- - os: ubuntu-latest
- python: '3.11'
- other: /singletest
- category: "-m 'neos or importtest'"
- skip_doctest: 1
- TARGET: linux
- PYENV: pip
+ PACKAGES: openmpi mpi4py
- os: ubuntu-latest
- python: '3.10'
+ python: 3.12
other: /cython
setup_options: --with-cython
skip_doctest: 1
@@ -113,14 +113,22 @@ jobs:
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'"
+ skip_doctest: 1
+ TARGET: linux
+ PYENV: pip
+
+ - os: ubuntu-latest
+ python: 3.9
other: /slim
slim: 1
skip_doctest: 1
@@ -128,14 +136,23 @@ jobs:
PYENV: pip
- os: ubuntu-latest
- python: 3.9
+ python: 3.12
+ other: /numpy2
+ slim: 1
+ skip_doctest: 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
+ python: 'pypy-3.10'
skip_doctest: 1
TARGET: linux
PYENV: pip
@@ -210,7 +227,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 +239,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 +266,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 +312,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
@@ -350,6 +370,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 +387,33 @@ 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() (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.0'
+ else
+ XPRESS='xpress'
+ fi
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
@@ -394,6 +435,7 @@ jobs:
conda install -y "$PKG" || _BUILDS=""
fi
fi
+ echo ""
if test -z "$_BUILDS"; then
echo "WARNING: $PKG is not available"
fi
@@ -431,6 +473,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,6 +483,8 @@ jobs:
IPOPT_DIR=$TPL_DIR/ipopt
echo "$IPOPT_DIR" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=$LD_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
@@ -514,7 +561,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 +580,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 +625,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"
@@ -640,6 +702,11 @@ 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
@@ -648,6 +715,7 @@ jobs:
- name: Run Pyomo tests
if: matrix.mpi == 0
run: |
+ export PATH=$PYOMO_PATH
$PYTHON_EXE -m pytest -v \
-W ignore::Warning ${{matrix.category}} \
pyomo `pwd`/pyomo-model-libraries \
@@ -661,7 +729,7 @@ jobs:
$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
@@ -681,6 +749,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 +759,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 +767,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 +802,18 @@ jobs:
cover:
name: process-coverage-${{ matrix.TARGET }}
needs: build
- if: always() # run even if a build job fails
+ if: success() || failure() # run even if a build job fails, but not if cancelled
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 +828,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
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..8771427805d 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,43 @@ 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
+ CODECOV_JOB_NAME=$(echo ${JOB_NAME} \
+ | sed -r 's/^(.*autotest_)?Pyomo_([^\/]+).*/\2/').$BUILD_NUMBER.$python
+ 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 \
+ --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..af3fa8bfec2 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -8,12 +8,13 @@ version: 2
build:
os: ubuntu-22.04
tools:
- python: "3.8"
+ python: "3.11"
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..5f68e827a92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,310 @@
Pyomo CHANGELOG
===============
+-------------------------------------------------------------------------------
+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 192d315e4b5..9fd5d9b810c 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,7 +1,7 @@
LICENSE
=======
-Copyright (c) 2008-2022 National Technology and Engineering Solutions of
+Copyright (c) 2008-2024 National Technology and Engineering Solutions of
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..34301a529f0 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,17 +1,22 @@
-We are pleased to announce the release of Pyomo 6.7.0.
+We are pleased to announce the release of Pyomo 6.8.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:
-
- - 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
+The following are highlights of the 6.8 release series:
+
+- Complete Documentation Reorganization
+- Added support for Python 3.13
+- Refactor default Gurobi interface to support version 12
+- Support for NumPy2
+- Refactor of Design of Experiments (`contrib.doe`)
+- New packages:
+ - alternative_solutions: alternative (near) optimal solutions
+- New solver interfaces:
+ - SAS: Statistical Analysis System
+ - 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/.codecov.yml b/codecov.yml
similarity index 54%
rename from .codecov.yml
rename to codecov.yml
index 6b88f948fe1..318a907905f 100644
--- a/.codecov.yml
+++ b/codecov.yml
@@ -1,19 +1,21 @@
+codecov:
+ notify:
+ # GHA: 5, Jenkins: 11
+ # Accurate as of July 3, 2024
+ # Potential to change when Python versions change
+ after_n_builds: 16
+ wait_for_ci: true
coverage:
- range: "50...100"
+ range:
+ - 50.0
+ - 100.0
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/conftest.py b/conftest.py
index df5b0f31e59..34b366f9fd6 100644
--- a/conftest.py
+++ b/conftest.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..443a3afaeff 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,12 @@ help:
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-clean clean_tests:
+clean:
@$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@echo "Removing *.spy, *.out"
@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
+
+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/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..83cbcdd9989
--- /dev/null
+++ b/doc/OnlineDocs/code.rst
@@ -0,0 +1,9 @@
+:orphan:
+
+.. autosummary::
+ :toctree: api
+ :caption: Library Reference
+ :template: recursive-module.rst
+ :recursive:
+
+ pyomo
diff --git a/doc/OnlineDocs/conf.py b/doc/OnlineDocs/conf.py
index ef6510daedf..f99aac06b4b 100644
--- a/doc/OnlineDocs/conf.py
+++ b/doc/OnlineDocs/conf.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
@@ -24,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'))
@@ -33,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)
@@ -46,8 +59,7 @@
'numpy': ('https://numpy.org/doc/stable/', None),
'pandas': ('https://pandas.pydata.org/docs/', None),
'scikit-learn': ('https://scikit-learn.org/stable/', None),
- 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None),
- 'Sphinx': ('https://www.sphinx-doc.org/en/stable/', None),
+ 'scipy': ('https://docs.scipy.org/doc/scipy/', None),
}
# -- General configuration ------------------------------------------------
@@ -61,18 +73,17 @@
# 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',
- #'sphinx.ext.githubpages',
+ # Our version of 'autoenum', designed to work with autosummary.
+ # This adds 'sphinx.ext.autosummary', and 'sphinx.ext.autodoc':
+ 'pyomo_autosummary_autoenum',
]
viewcode_follow_imported_members = True
@@ -95,7 +106,7 @@
# General information about the project.
project = u'Pyomo'
-copyright = u'2008-2023, Sandia National Laboratories'
+copyright = u'2008-2024, Sandia National Laboratories'
author = u'Pyomo Developers'
# The version info for the project you're documenting, acts as replacement for
@@ -119,7 +130,21 @@
# 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']
+# 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'
@@ -155,7 +180,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,
@@ -220,7 +245,10 @@
]
# 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
@@ -254,20 +282,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'))
@@ -278,6 +318,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()
@@ -288,4 +333,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/index.rst b/doc/OnlineDocs/contributed_packages/mpc/index.rst
deleted file mode 100644
index b93abf223e2..00000000000
--- a/doc/OnlineDocs/contributed_packages/mpc/index.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-MPC
-===
-
-This package contains data structures and utilities for dynamic optimization
-and rolling horizon applications, e.g. model predictive control.
-
-.. toctree::
- :maxdepth: 1
-
- overview.rst
- examples.rst
- faq.rst
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..9ad5bdfee0e 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,50 +404,10 @@ 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
@@ -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/index.rst b/doc/OnlineDocs/developer_reference/index.rst
deleted file mode 100644
index 8c29150015c..00000000000
--- a/doc/OnlineDocs/developer_reference/index.rst
+++ /dev/null
@@ -1,14 +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
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 64%
rename from doc/OnlineDocs/contributed_packages/doe/doe.rst
rename to doc/OnlineDocs/explanation/analysis/doe/doe.rst
index 8c22ff7370d..05d9d867e2b 100644
--- a/doc/OnlineDocs/contributed_packages/doe/doe.rst
+++ b/doc/OnlineDocs/explanation/analysis/doe/doe.rst
@@ -3,7 +3,7 @@ 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:
@@ -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.
@@ -116,64 +116,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:
+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:
-* 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
----------------------------
-
-.. 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
-----------------------
@@ -203,89 +153,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,
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/explanation/analysis/mpc/api.rst b/doc/OnlineDocs/explanation/analysis/mpc/api.rst
new file mode 100644
index 00000000000..2752fea8af6
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/api.rst
@@ -0,0 +1,10 @@
+.. _mpc_api:
+
+API Reference
+=============
+
+.. toctree::
+ data.rst
+ conversion.rst
+ interface.rst
+ modeling.rst
diff --git a/doc/OnlineDocs/explanation/analysis/mpc/conversion.rst b/doc/OnlineDocs/explanation/analysis/mpc/conversion.rst
new file mode 100644
index 00000000000..e78a1d69e0b
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/conversion.rst
@@ -0,0 +1,6 @@
+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/explanation/analysis/mpc/index.rst b/doc/OnlineDocs/explanation/analysis/mpc/index.rst
new file mode 100644
index 00000000000..e512d1a6ef5
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/index.rst
@@ -0,0 +1,32 @@
+MPC
+===
+
+Pyomo MPC contains data structures and utilities for dynamic optimization
+and rolling horizon applications, e.g. model predictive control.
+
+.. toctree::
+ :maxdepth: 1
+
+ overview.rst
+ examples.rst
+ faq.rst
+ api.rst
+
+Citation
+--------
+
+If you use Pyomo MPC in your research, please cite the following paper:
+
+.. code-block:: bibtex
+
+ @article{parker2023mpc,
+ title = {Model predictive control simulations with block-hierarchical differential-algebraic process models},
+ journal = {Journal of Process Control},
+ volume = {132},
+ pages = {103113},
+ year = {2023},
+ issn = {0959-1524},
+ doi = {https://doi.org/10.1016/j.jprocont.2023.103113},
+ url = {https://www.sciencedirect.com/science/article/pii/S0959152423002007},
+ author = {Robert B. Parker and Bethany L. Nicholson and John D. Siirola and Lorenz T. Biegler},
+ }
diff --git a/doc/OnlineDocs/explanation/analysis/mpc/interface.rst b/doc/OnlineDocs/explanation/analysis/mpc/interface.rst
new file mode 100644
index 00000000000..13a5bf24360
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/interface.rst
@@ -0,0 +1,10 @@
+Interfaces
+==========
+
+.. automodule:: pyomo.contrib.mpc.interfaces.model_interface
+ :noindex:
+ :members:
+
+.. automodule:: pyomo.contrib.mpc.interfaces.var_linker
+ :noindex:
+ :members:
diff --git a/doc/OnlineDocs/explanation/analysis/mpc/modeling.rst b/doc/OnlineDocs/explanation/analysis/mpc/modeling.rst
new file mode 100644
index 00000000000..2bc213f1702
--- /dev/null
+++ b/doc/OnlineDocs/explanation/analysis/mpc/modeling.rst
@@ -0,0 +1,14 @@
+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 99%
rename from doc/OnlineDocs/contributed_packages/mpc/overview.rst
rename to doc/OnlineDocs/explanation/analysis/mpc/overview.rst
index f5dbe85e523..f3bc7504b59 100644
--- a/doc/OnlineDocs/contributed_packages/mpc/overview.rst
+++ b/doc/OnlineDocs/explanation/analysis/mpc/overview.rst
@@ -189,7 +189,7 @@ a tracking cost expression.
>>> m.setpoint_idx = var_set
>>> m.tracking_cost = tr_cost
>>> m.tracking_cost.pprint()
- tracking_cost : Size=6, Index=tracking_cost_index
+ tracking_cost : Size=6, Index=setpoint_idx*time
Key : Expression
(0, 0) : (var[0,A] - 0.5)**2
(0, 1) : (var[1,A] - 0.5)**2
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 93%
rename from doc/OnlineDocs/contributed_packages/sensitivity_toolbox.rst
rename to doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst
index 2a2ccff4b09..6d3bbea426a 100644
--- a/doc/OnlineDocs/contributed_packages/sensitivity_toolbox.rst
+++ b/doc/OnlineDocs/explanation/analysis/sensitivity_toolbox.rst
@@ -67,6 +67,18 @@ 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)
+.. 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:
@@ -138,7 +150,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 +174,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
@@ -183,3 +195,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..3f2653aa732
--- /dev/null
+++ b/doc/OnlineDocs/explanation/experimental/solvers.rst
@@ -0,0 +1,358 @@
+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.factory.SolverFactory``
+ - Name registered in the |br| ``pyomo.opt.base.solvers.LegacySolverFactory``
+ * - Ipopt
+ - ``ipopt``
+ - ``ipopt_v2``
+ * - Gurobi (persistent)
+ - ``gurobi``
+ - ``gurobi_v2``
+ * - Gurobi (direct)
+ - ``gurobi_direct``
+ - ``gurobi_direct_v2``
+
+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
+ 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
+
+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.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 through the new interfaces
+ status.display()
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ solution_loader: ...
+ ...
+ 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.util import assert_optimal_termination
+ from pyomo.contrib.solver.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)
+ assert_optimal_termination(status)
+ # Displays important results information; only available through the new interfaces
+ status.display()
+ model.pprint()
+
+.. testoutput::
+ :skipif: not ipopt_available
+ :hide:
+
+ solution_loader: ...
+ ...
+ 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.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 through the new interfaces
+ 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 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.ipopt.Ipopt
+ :noindex:
+ :members: solve
+
+.. 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
+ :noindex:
+ :members:
+
+Persistent solvers include additional members as well as other configuration options:
+
+.. autoclass:: pyomo.contrib.solver.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.results.Results
+ :noindex:
+ :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
+ :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.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.ipopt.IpoptSolutionLoader
+ :noindex:
+ :members:
+ :show-inheritance:
+ :inherited-members:
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 99%
rename from doc/OnlineDocs/modeling_extensions/dae.rst
rename to doc/OnlineDocs/explanation/modeling/dae.rst
index 703e83f4f14..8661fcf4af7 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
@@ -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
@@ -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
@@ -287,6 +290,7 @@ Declaring Integrals
equations.
.. autoclass:: pyomo.dae.Integral
+ :noindex:
:members:
Declaring an :py:class:`Integral` component is similar to
@@ -556,7 +560,8 @@ 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:
@@ -722,7 +727,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 +744,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.
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/concepts.rst b/doc/OnlineDocs/explanation/modeling/gdp/concepts.rst
similarity index 100%
rename from doc/OnlineDocs/modeling_extensions/gdp/concepts.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/concepts.rst
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/index.rst b/doc/OnlineDocs/explanation/modeling/gdp/index.rst
similarity index 57%
rename from doc/OnlineDocs/modeling_extensions/gdp/index.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/index.rst
index 0c8529c60cb..770be256009 100644
--- a/doc/OnlineDocs/modeling_extensions/gdp/index.rst
+++ b/doc/OnlineDocs/explanation/modeling/gdp/index.rst
@@ -9,7 +9,11 @@ Generalized Disjunctive Programming
: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:
+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::
@@ -32,9 +36,12 @@ Here, we have the minimization of an objective :math:`obj` subject to global lin
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.
+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:
@@ -68,12 +75,3 @@ The following sections describe the key concepts, modeling, and solution approac
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/gdp/modeling.rst b/doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
similarity index 99%
rename from doc/OnlineDocs/modeling_extensions/gdp/modeling.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
index b70e37d5935..996ebcb0366 100644
--- a/doc/OnlineDocs/modeling_extensions/gdp/modeling.rst
+++ b/doc/OnlineDocs/explanation/modeling/gdp/modeling.rst
@@ -166,7 +166,7 @@ Usage:
>>> TransformationFactory('core.logical_to_linear').apply_to(m)
>>> # constraint auto-generated by transformation
>>> m.logic_to_linear.transformed_constraints.pprint()
- transformed_constraints : Size=1, Index=logic_to_linear.transformed_constraints_index, Active=True
+ transformed_constraints : Size=1, Index={1}, Active=True
Key : Lower : Body : Upper : Active
1 : 3.0 : Y_asbinary[1] + Y_asbinary[2] + Y_asbinary[3] + Y_asbinary[4] : +Inf : True
diff --git a/doc/OnlineDocs/modeling_extensions/gdp/solving.rst b/doc/OnlineDocs/explanation/modeling/gdp/solving.rst
similarity index 68%
rename from doc/OnlineDocs/modeling_extensions/gdp/solving.rst
rename to doc/OnlineDocs/explanation/modeling/gdp/solving.rst
index 2f3076862e6..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:
@@ -140,6 +149,10 @@ For example, to apply the transformation and store the M values, use:
From the Pyomo command line, include the ``--transform pyomo.gdp.mbigm`` option.
+.. warning::
+ The Multiple Big-M transformation does not currently support Suffixes and will
+ ignore "BigM" Suffixes.
+
Hull Reformulation (HR)
^^^^^^^^^^^^^^^^^^^^^^^
@@ -164,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:
@@ -181,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 99%
rename from doc/OnlineDocs/pyomo_modeling_components/Sets.rst
rename to doc/OnlineDocs/explanation/modeling/math_programming/sets.rst
index 73c3539d79d..ababa80be5a 100644
--- a/doc/OnlineDocs/pyomo_modeling_components/Sets.rst
+++ b/doc/OnlineDocs/explanation/modeling/math_programming/sets.rst
@@ -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 99%
rename from doc/OnlineDocs/modeling_extensions/network.rst
rename to doc/OnlineDocs/explanation/modeling/network.rst
index 3fce9448997..3c4b60bfb6a 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
@@ -62,10 +64,12 @@ Arc
***
.. autoclass:: pyomo.network.Arc
+ :noindex:
:members:
:exclude-members: construct
.. autoclass:: pyomo.network.arc._ArcData
+ :noindex:
:members:
:special-members: __getattr__
@@ -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 63%
rename from doc/OnlineDocs/advanced_topics/flattener/index.rst
rename to doc/OnlineDocs/explanation/modeling_utils/flattener/index.rst
index 377de5233ec..f9dd8ea6abb 100644
--- a/doc/OnlineDocs/advanced_topics/flattener/index.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/flattener/index.rst
@@ -30,8 +30,9 @@ The ``pyomo.dae.flatten`` module aims to address this use case by providing
utilities to generate all components indexed, explicitly or implicitly, by
user-provided sets.
-**When we say "flatten a model," we mean "generate all components in the model,
-preserving all user-specified indexing sets."**
+**When we say "flatten a model," we mean "recursively generate all components in
+the model," where a component can be indexed only by user-specified indexing
+sets (or is not indexed at all)**.
Data structures
---------------
@@ -42,3 +43,23 @@ Slices are necessary as they can encode "implicit indexing" -- where a
component is contained in an indexed block. It is natural to return references
to these slices, so they may be accessed and manipulated like any other
component.
+
+Citation
+--------
+If you use the ``pyomo.dae.flatten`` module in your research, we would appreciate
+you citing the following paper, which gives more detail about the motivation for
+and examples of using this functinoality.
+
+.. code-block:: bibtex
+
+ @article{parker2023mpc,
+ title = {Model predictive control simulations with block-hierarchical differential-algebraic process models},
+ journal = {Journal of Process Control},
+ volume = {132},
+ pages = {103113},
+ year = {2023},
+ issn = {0959-1524},
+ doi = {https://doi.org/10.1016/j.jprocont.2023.103113},
+ url = {https://www.sciencedirect.com/science/article/pii/S0959152423002007},
+ author = {Robert B. Parker and Bethany L. Nicholson and John D. Siirola and Lorenz T. Biegler},
+ }
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 96%
rename from doc/OnlineDocs/contributed_packages/preprocessing.rst
rename to doc/OnlineDocs/explanation/modeling_utils/preprocessing.rst
index fd26f2bf6db..1f68208fdc3 100644
--- a/doc/OnlineDocs/contributed_packages/preprocessing.rst
+++ b/doc/OnlineDocs/explanation/modeling_utils/preprocessing.rst
@@ -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
@@ -77,6 +78,7 @@ Explicit Constraints to Variable Bounds
>>> 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..29c12c98098
--- /dev/null
+++ b/doc/OnlineDocs/explanation/philosophy/abstract_modeling.rst
@@ -0,0 +1,60 @@
+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 92%
rename from doc/OnlineDocs/contributed_packages/gdpopt.rst
rename to doc/OnlineDocs/explanation/solvers/gdpopt.rst
index d550b0ced76..953799f0555 100644
--- a/doc/OnlineDocs/contributed_packages/gdpopt.rst
+++ b/doc/OnlineDocs/explanation/solvers/gdpopt.rst
@@ -93,10 +93,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 +106,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::
@@ -197,17 +197,11 @@ 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:
+.. autosummary::
-.. autoclass:: pyomo.contrib.gdpopt.loa.GDP_LOA_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
-.. autoclass:: pyomo.contrib.gdpopt.gloa.GDP_GLOA_Solver
- :members:
-
-.. autoclass:: pyomo.contrib.gdpopt.ric.GDP_RIC_Solver
- :members:
-
-.. 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 94%
rename from doc/OnlineDocs/contributed_packages/mindtpy.rst
rename to doc/OnlineDocs/explanation/solvers/mindtpy.rst
index a850a42c740..38798a0183c 100644
--- a/doc/OnlineDocs/contributed_packages/mindtpy.rst
+++ b/doc/OnlineDocs/explanation/solvers/mindtpy.rst
@@ -11,7 +11,7 @@ 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`_]
@@ -26,7 +26,6 @@ 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
@@ -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 98%
rename from doc/OnlineDocs/contributed_packages/multistart.rst
rename to doc/OnlineDocs/explanation/solvers/multistart.rst
index 069d770aa91..f54cb26d00f 100644
--- a/doc/OnlineDocs/contributed_packages/multistart.rst
+++ b/doc/OnlineDocs/explanation/solvers/multistart.rst
@@ -31,4 +31,5 @@ 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 98%
rename from doc/OnlineDocs/advanced_topics/persistent_solvers.rst
rename to doc/OnlineDocs/explanation/solvers/persistent.rst
index aebb0545dd0..8ee32120ff3 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
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 96%
rename from doc/OnlineDocs/contributed_packages/pynumero/tutorial.nlp_interfaces.rst
rename to doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst
index 28818709330..832ba521052 100644
--- a/doc/OnlineDocs/contributed_packages/pynumero/tutorial.nlp_interfaces.rst
+++ b/doc/OnlineDocs/explanation/solvers/pynumero/tutorial.nlp_interfaces.rst
@@ -2,8 +2,8 @@ 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
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 79%
rename from doc/OnlineDocs/contributed_packages/pyros.rst
rename to doc/OnlineDocs/explanation/solvers/pyros.rst
index 3ff1bfccf0e..986603efeab 100644
--- a/doc/OnlineDocs/contributed_packages/pyros.rst
+++ b/doc/OnlineDocs/explanation/solvers/pyros.rst
@@ -14,19 +14,18 @@ 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:
@@ -39,20 +38,21 @@ PyROS is designed to operate on deterministic models of the general form
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 +63,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,7 +77,8 @@ 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}
@@ -100,10 +89,66 @@ Based on the above notation, the form of the robust counterpart addressed by PyR
& & & \displaystyle ~~ h_j\left(x, z, y, q\right) = 0 & & \forall\,j \in \mathcal{J}
\end{array}
-PyROS solves problems of this form using the
-Generalized Robust Cutting-Set algorithm developed in [Isenberg_et_al]_.
+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``:
+
+ ::
+
+ 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,20 +173,25 @@ 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.
+
PyROS Uncertainty Sets
-----------------------------
Uncertainty sets are represented by subclasses of
@@ -210,45 +260,18 @@ 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
-
-.. 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
+.. autosummary::
-.. 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
@@ -304,23 +327,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::
@@ -403,22 +433,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 ``Param`` object that is to be considered uncertain by PyROS
- must have the property ``mutable=True``.
+ Any :class:`~pyomo.core.base.param.Param` object that is
+ to be considered uncertain by PyROS must have the property
+ ``mutable=True``.
+
+.. note::
+ 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.
@@ -465,7 +510,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``.
@@ -518,7 +563,7 @@ correspond to first-stage degrees of freedom.
>>> # === Designate which variables correspond to first-stage
>>> # and second-stage degrees of freedom ===
- >>> first_stage_variables =[
+ >>> first_stage_variables = [
... m.x1, m.x2, m.x3, m.x4, m.x5, m.x6,
... m.x19, m.x20, m.x21, m.x22, m.x23, m.x24, m.x31,
... ]
@@ -530,7 +575,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,
@@ -539,7 +584,7 @@ correspond to first-stage degrees of freedom.
... load_solution=False,
... )
==============================================================================
- PyROS: The Pyomo Robust Optimization Solver.
+ PyROS: The Pyomo Robust Optimization Solver...
...
------------------------------------------------------------------------------
Robust optimal solution identified.
@@ -574,7 +619,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 `,
@@ -604,7 +649,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``:
@@ -623,7 +668,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,
@@ -657,6 +702,54 @@ For this example, we notice a ~25% decrease in the final objective
value when switching from a static decision rule (no second-stage recourse)
to an affine decision rule.
+
+Specifying Arguments Indirectly Through ``options``
+"""""""""""""""""""""""""""""""""""""""""""""""""""
+Like other Pyomo solver interface methods,
+: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.PyROS.solve`
+to their desired values.
+For example, the ``solve()`` statement in the
+:ref:`two-stage problem snippet `
+could have been equivalently written as:
+
+.. doctest::
+ :skipif: not (baron.available() and baron.license_is_valid())
+
+ >>> results_2 = pyros_solver.solve(
+ ... model=m,
+ ... first_stage_variables=first_stage_variables,
+ ... second_stage_variables=second_stage_variables,
+ ... uncertain_params=uncertain_params,
+ ... uncertainty_set=box_uncertainty_set,
+ ... local_solver=local_solver,
+ ... global_solver=global_solver,
+ ... options={
+ ... "objective_focus": pyros.ObjectiveType.worst_case,
+ ... "solve_master_globally": True,
+ ... "decision_rule_order": 1,
+ ... },
+ ... )
+ ==============================================================================
+ PyROS: The Pyomo Robust Optimization Solver...
+ ...
+ ------------------------------------------------------------------------------
+ Robust optimal solution identified.
+ ------------------------------------------------------------------------------
+ ...
+ ------------------------------------------------------------------------------
+ All done. Exiting PyROS.
+ ==============================================================================
+
+In the event an argument is passed directly
+by position or keyword, *and* indirectly through ``options``,
+an appropriate warning is issued,
+and the value passed directly takes precedence over the value
+passed through ``options``.
+
+
The Price of Robustness
""""""""""""""""""""""""
In conjunction with standard Python control flow tools,
@@ -695,7 +788,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,
@@ -750,7 +843,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 `.
@@ -787,11 +880,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
@@ -812,12 +906,20 @@ 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."
* **Iteration log table** (lines 59--69).
Summary information on the problem iterates and subproblem outcomes.
The constituent columns are defined in detail in
@@ -854,21 +956,21 @@ Observe that the log contains the following information:
:linenos:
==============================================================================
- PyROS: The Pyomo Robust Optimization Solver, v1.2.9.
- Pyomo version: 6.7.0
+ PyROS: The Pyomo Robust Optimization Solver, v1.3.4.
+ Pyomo version: 6.9.0
Commit hash: unknown
- Invoked at UTC 2023-12-16T00:00:00.000000
-
+ Invoked at UTC 2025-02-13T00:00:00.000000
+
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).
==============================================================================
================================= DISCLAIMER =================================
- PyROS is still under development.
+ PyROS is still under development.
Please provide feedback and/or report any issues by creating a ticket at
https://github.com/Pyomo/pyomo/issues/new/choose
==============================================================================
@@ -877,6 +979,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
@@ -893,55 +996,55 @@ 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.009s.
------------------------------------------------------------------------------
- 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 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.412
+ 1 3.5838e+07 1.2289e-09 1.5886e-12 5 2.8919e+02 0.992
+ 2 3.6269e+07 3.1647e-01 1.0432e-01 4 2.9020e+02 1.865
+ 3 3.6285e+07 7.6526e-01 2.2258e-01 0 2.3874e-12g 3.508
------------------------------------------------------------------------------
Robust optimal solution identified.
------------------------------------------------------------------------------
Timing breakdown:
-
+
Identifier ncalls cumtime percall %
-----------------------------------------------------------
- main 1 11.457 11.457 100.0
+ main 1 3.509 3.509 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 3 0.209 0.070 6.0
+ global_separation 27 0.590 0.022 16.8
+ local_separation 108 1.569 0.015 44.7
+ master 4 0.654 0.163 18.6
+ master_feasibility 3 0.083 0.028 2.4
+ preprocessing 1 0.009 0.009 0.3
+ other n/a 0.394 n/a 11.2
======================================================
===========================================================
-
+
------------------------------------------------------------------------------
Termination stats:
- Iterations : 5
- Solve time (wall s) : 11.457
+ Iterations : 4
+ Solve time (wall s) : 3.509
Final objective value : 3.6285e+07
Termination condition : pyrosTerminationCondition.robust_optimal
------------------------------------------------------------------------------
@@ -999,10 +1102,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,
@@ -1010,13 +1113,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 99%
rename from doc/OnlineDocs/contributed_packages/trustregion.rst
rename to doc/OnlineDocs/explanation/solvers/trustregion.rst
index f477c905e33..0bdfef2f10d 100644
--- a/doc/OnlineDocs/contributed_packages/trustregion.rst
+++ b/doc/OnlineDocs/explanation/solvers/trustregion.rst
@@ -102,6 +102,7 @@ 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
diff --git a/doc/OnlineDocs/contributed_packages/satsolver.rst b/doc/OnlineDocs/explanation/solvers/z3_interface.rst
similarity index 100%
rename from doc/OnlineDocs/contributed_packages/satsolver.rst
rename to doc/OnlineDocs/explanation/solvers/z3_interface.rst
diff --git a/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py b/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py
new file mode 100644
index 00000000000..a447466b75f
--- /dev/null
+++ b/doc/OnlineDocs/ext/pyomo_autosummary_autoenum.py
@@ -0,0 +1,256 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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,
+ template_name: str,
+ imported_members: bool,
+ app: Any,
+ recursive: bool,
+ context: dict,
+ modname: Union[str, None] = None,
+ qualname: Union[str, None] = None,
+) -> 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:
+ # Sphinx >= 7.2
+ _get_members = caller.f_globals['_get_members']
+ 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,
+ template_name,
+ imported_members,
+ app,
+ recursive,
+ context,
+ modname,
+ qualname,
+ )
+
+
+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 :pt: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/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 100%
rename from doc/OnlineDocs/pyomo_overview/abstract_concrete.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/abstract_concrete.rst
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 98%
rename from doc/OnlineDocs/pyomo_overview/simple_examples.rst
rename to doc/OnlineDocs/getting_started/pyomo_overview/simple_examples.rst
index 11305884c54..1741c694d68 100644
--- a/doc/OnlineDocs/pyomo_overview/simple_examples.rst
+++ b/doc/OnlineDocs/getting_started/pyomo_overview/simple_examples.rst
@@ -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 82%
rename from doc/OnlineDocs/working_abstractmodels/data/raw_dicts.rst
rename to doc/OnlineDocs/howto/abstract_models/data/raw_dicts.rst
index e10042b3ceb..f78e349c28b 100644
--- a/doc/OnlineDocs/working_abstractmodels/data/raw_dicts.rst
+++ b/doc/OnlineDocs/howto/abstract_models/data/raw_dicts.rst
@@ -28,13 +28,10 @@ components, the required data dictionary maps the implicit index
... }}
>>> i = m.create_instance(data)
>>> i.pprint()
- 2 Set Declarations
+ 1 Set Declarations
I : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
- r_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : I*I : 9 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}
3 Param Declarations
p : Size=1, Index=None, Domain=Any, Default=None, Mutable=False
@@ -45,12 +42,12 @@ components, the required data dictionary maps the implicit index
1 : 10
2 : 20
3 : 30
- r : Size=9, Index=r_index, Domain=Any, Default=0, Mutable=False
+ r : Size=9, Index=I*I, Domain=Any, Default=0, Mutable=False
Key : Value
(1, 1) : 110
(1, 2) : 120
(2, 3) : 230
- 5 Declarations: I p q r_index r
+ 4 Declarations: I p q r
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..0d7ccc41592 100644
--- a/doc/OnlineDocs/index.rst
+++ b/doc/OnlineDocs/index.rst
@@ -1,55 +1,116 @@
+=============================
Pyomo Documentation |release|
=============================
+About Pyomo
+-----------
+
.. 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`
+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.
-Pyomo Resources
----------------
-The Pyomo home page provides resources for Pyomo users:
+Contents
+--------
+.. list-table::
+ :width: 100%
+ :class: diataxis
+
+ * - .. toctree::
+ :maxdepth: 2
+ :titlesonly:
+
+ getting_started/index
+ - .. toctree::
+ :maxdepth: 2
+ :titlesonly:
+
+ howto/index
+ * - .. toctree::
+ :maxdepth: 3
+ :titlesonly:
+
+ explanation/index
+ - .. toctree::
+ :maxdepth: 3
+ :titlesonly:
-* http://pyomo.org
+ reference/index
+
+..
+ toctree::
+ :maxdepth: 1
+ :titlesonly:
+ :hidden:
+
+ genindex
+ modindex
+
+
+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 7a400b26ce3..00000000000
--- a/doc/OnlineDocs/library_reference/common/config.rst
+++ /dev/null
@@ -1,83 +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
- 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:: 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 0e92f583c73..00000000000
--- a/doc/OnlineDocs/library_reference/expressions/context_managers.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-
-Context Managers
-================
-
-.. autoclass:: pyomo.core.expr.nonlinear_expression
- :members:
-
-.. autoclass:: pyomo.core.expr.linear_expression
- :members:
-
-.. autoclass:: pyomo.core.expr.current.clone_counter
- :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/examples/conic.py b/doc/OnlineDocs/library_reference/kernel/examples/conic.py
deleted file mode 100644
index 9282bc67f9a..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/examples/conic.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# @Class
-import pyomo.kernel as pmo
-
-m = pmo.block()
-m.x1 = pmo.variable(lb=0)
-m.x2 = pmo.variable()
-m.r = pmo.variable(lb=0)
-m.q = pmo.conic.primal_exponential(x1=m.x1, x2=m.x2, r=m.r)
-# @Class
-del m
-
-# @Domain
-import pyomo.kernel as pmo
-import math
-
-m = pmo.block()
-m.x = pmo.variable(lb=0)
-m.y = pmo.variable(lb=0)
-m.b = pmo.conic.primal_exponential.as_domain(
- x1=math.sqrt(2) * m.x, x2=2.0, r=2 * (m.x + m.y)
-)
-# @Domain
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py b/doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py
deleted file mode 100644
index f2a4ec25ac5..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_containers.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import pyomo.kernel
-
-# @all
-vlist = pyomo.kernel.variable_list()
-vlist.append(pyomo.kernel.variable_dict())
-vlist[0]['x'] = pyomo.kernel.variable()
-# @all
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py b/doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py
deleted file mode 100644
index 5a8eed9fd89..00000000000
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_solving.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import pyomo.kernel as pmo
-
-model = pmo.block()
-model.x = pmo.variable()
-model.c = pmo.constraint(model.x >= 1)
-model.o = pmo.objective(model.x)
-
-opt = pmo.SolverFactory("ipopt")
-
-result = opt.solve(model)
-assert str(result.solver.termination_condition) == "optimal"
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/__init__.py b/doc/OnlineDocs/modeling_extensions/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
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/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..be64644a0f2
--- /dev/null
+++ b/doc/OnlineDocs/reference/bibliography.rst
@@ -0,0 +1,151 @@
+.. _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.
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..830c34f8366
--- /dev/null
+++ b/doc/OnlineDocs/reference/index.rst
@@ -0,0 +1,17 @@
+Reference Guides
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ topical/index
+ 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 99%
rename from doc/OnlineDocs/library_reference/appsi/appsi.rst
rename to doc/OnlineDocs/reference/topical/appsi/appsi.rst
index e26e4b0e82a..4f4a2ffa60c 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:
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 32600b226e1..aa2f46e71fa 100644
--- a/doc/OnlineDocs/src/data/ABCD1.py
+++ b/doc/OnlineDocs/src/data/ABCD1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD2.py b/doc/OnlineDocs/src/data/ABCD2.py
index 65a46415368..ec0e7ccb15c 100644
--- a/doc/OnlineDocs/src/data/ABCD2.py
+++ b/doc/OnlineDocs/src/data/ABCD2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD3.py b/doc/OnlineDocs/src/data/ABCD3.py
index 48797ced5bb..ba55fd970cc 100644
--- a/doc/OnlineDocs/src/data/ABCD3.py
+++ b/doc/OnlineDocs/src/data/ABCD3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD4.py b/doc/OnlineDocs/src/data/ABCD4.py
index 20f6a21c011..2fb397aa3b0 100644
--- a/doc/OnlineDocs/src/data/ABCD4.py
+++ b/doc/OnlineDocs/src/data/ABCD4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD5.py b/doc/OnlineDocs/src/data/ABCD5.py
index 58461af056b..abc03505e96 100644
--- a/doc/OnlineDocs/src/data/ABCD5.py
+++ b/doc/OnlineDocs/src/data/ABCD5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD6.py b/doc/OnlineDocs/src/data/ABCD6.py
index 961408dbc7e..59e0e8e98ae 100644
--- a/doc/OnlineDocs/src/data/ABCD6.py
+++ b/doc/OnlineDocs/src/data/ABCD6.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/ABCD7.py b/doc/OnlineDocs/src/data/ABCD7.py
index a97e764fa5a..1bfb4d1e3fb 100644
--- a/doc/OnlineDocs/src/data/ABCD7.py
+++ b/doc/OnlineDocs/src/data/ABCD7.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import pyomo.common
import sys
diff --git a/doc/OnlineDocs/src/data/ABCD8.py b/doc/OnlineDocs/src/data/ABCD8.py
index 9bcd950c681..aa1ba0b4cf5 100644
--- a/doc/OnlineDocs/src/data/ABCD8.py
+++ b/doc/OnlineDocs/src/data/ABCD8.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import pyomo.common
import sys
diff --git a/doc/OnlineDocs/src/data/ABCD9.py b/doc/OnlineDocs/src/data/ABCD9.py
index 29fcb6426db..194c71486d9 100644
--- a/doc/OnlineDocs/src/data/ABCD9.py
+++ b/doc/OnlineDocs/src/data/ABCD9.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import pyomo.common
import sys
diff --git a/doc/OnlineDocs/src/data/diet1.py b/doc/OnlineDocs/src/data/diet1.py
index ef0d8096350..40582e16ba0 100644
--- a/doc/OnlineDocs/src/data/diet1.py
+++ b/doc/OnlineDocs/src/data/diet1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# diet1.py
from pyomo.environ import *
diff --git a/doc/OnlineDocs/src/data/ex.py b/doc/OnlineDocs/src/data/ex.py
index 8c9473f2852..a66ee30b494 100644
--- a/doc/OnlineDocs/src/data/ex.py
+++ b/doc/OnlineDocs/src/data/ex.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import1.tab.py b/doc/OnlineDocs/src/data/import1.tab.py
index c9164ab73ec..e160e4fdcde 100644
--- a/doc/OnlineDocs/src/data/import1.tab.py
+++ b/doc/OnlineDocs/src/data/import1.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import2.tab.py b/doc/OnlineDocs/src/data/import2.tab.py
index d03f053d090..54339551279 100644
--- a/doc/OnlineDocs/src/data/import2.tab.py
+++ b/doc/OnlineDocs/src/data/import2.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import3.tab.py b/doc/OnlineDocs/src/data/import3.tab.py
index e86557677ee..664151d1438 100644
--- a/doc/OnlineDocs/src/data/import3.tab.py
+++ b/doc/OnlineDocs/src/data/import3.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import4.tab.py b/doc/OnlineDocs/src/data/import4.tab.py
index 93df9c761ab..91dd3f26a42 100644
--- a/doc/OnlineDocs/src/data/import4.tab.py
+++ b/doc/OnlineDocs/src/data/import4.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import5.tab.py b/doc/OnlineDocs/src/data/import5.tab.py
index 1d20476a16f..263677c308c 100644
--- a/doc/OnlineDocs/src/data/import5.tab.py
+++ b/doc/OnlineDocs/src/data/import5.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import6.tab.py b/doc/OnlineDocs/src/data/import6.tab.py
index 8a1ab232f86..8f4824ad3fe 100644
--- a/doc/OnlineDocs/src/data/import6.tab.py
+++ b/doc/OnlineDocs/src/data/import6.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import7.tab.py b/doc/OnlineDocs/src/data/import7.tab.py
index 747d884be31..503f9224323 100644
--- a/doc/OnlineDocs/src/data/import7.tab.py
+++ b/doc/OnlineDocs/src/data/import7.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/import8.tab.py b/doc/OnlineDocs/src/data/import8.tab.py
index b7866d7a3e5..02b8724fe45 100644
--- a/doc/OnlineDocs/src/data/import8.tab.py
+++ b/doc/OnlineDocs/src/data/import8.tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param1.py b/doc/OnlineDocs/src/data/param1.py
index c4bc8de5acc..336a04287b9 100644
--- a/doc/OnlineDocs/src/data/param1.py
+++ b/doc/OnlineDocs/src/data/param1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param2.py b/doc/OnlineDocs/src/data/param2.py
index f46f05ceebc..a7d0feafff9 100644
--- a/doc/OnlineDocs/src/data/param2.py
+++ b/doc/OnlineDocs/src/data/param2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param2a.py b/doc/OnlineDocs/src/data/param2a.py
index 4557f63d841..42056793ffd 100644
--- a/doc/OnlineDocs/src/data/param2a.py
+++ b/doc/OnlineDocs/src/data/param2a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param3.py b/doc/OnlineDocs/src/data/param3.py
index 149155ce67d..952f9a9b707 100644
--- a/doc/OnlineDocs/src/data/param3.py
+++ b/doc/OnlineDocs/src/data/param3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param3a.py b/doc/OnlineDocs/src/data/param3a.py
index 0e99cad0c7a..028e1d07296 100644
--- a/doc/OnlineDocs/src/data/param3a.py
+++ b/doc/OnlineDocs/src/data/param3a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param3b.py b/doc/OnlineDocs/src/data/param3b.py
index deda175ea12..97f8598610a 100644
--- a/doc/OnlineDocs/src/data/param3b.py
+++ b/doc/OnlineDocs/src/data/param3b.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param3c.py b/doc/OnlineDocs/src/data/param3c.py
index 4056dc8107d..582b0f7db75 100644
--- a/doc/OnlineDocs/src/data/param3c.py
+++ b/doc/OnlineDocs/src/data/param3c.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param4.py b/doc/OnlineDocs/src/data/param4.py
index 1190dae8dec..010c46fc9c5 100644
--- a/doc/OnlineDocs/src/data/param4.py
+++ b/doc/OnlineDocs/src/data/param4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param5.py b/doc/OnlineDocs/src/data/param5.py
index 69f6cc46552..2db07f3f990 100644
--- a/doc/OnlineDocs/src/data/param5.py
+++ b/doc/OnlineDocs/src/data/param5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param5a.py b/doc/OnlineDocs/src/data/param5a.py
index 303b92f9f2e..32a53d24e9b 100644
--- a/doc/OnlineDocs/src/data/param5a.py
+++ b/doc/OnlineDocs/src/data/param5a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param6.py b/doc/OnlineDocs/src/data/param6.py
index c3e4b25d144..e3364a933cf 100644
--- a/doc/OnlineDocs/src/data/param6.py
+++ b/doc/OnlineDocs/src/data/param6.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param6a.py b/doc/OnlineDocs/src/data/param6a.py
index 07e8280cc18..3d2fa645411 100644
--- a/doc/OnlineDocs/src/data/param6a.py
+++ b/doc/OnlineDocs/src/data/param6a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param7a.py b/doc/OnlineDocs/src/data/param7a.py
index 3bb68b3f3b7..b3aba9ec23d 100644
--- a/doc/OnlineDocs/src/data/param7a.py
+++ b/doc/OnlineDocs/src/data/param7a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param7b.py b/doc/OnlineDocs/src/data/param7b.py
index 6e5c857851f..8b022f399a8 100644
--- a/doc/OnlineDocs/src/data/param7b.py
+++ b/doc/OnlineDocs/src/data/param7b.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/param8a.py b/doc/OnlineDocs/src/data/param8a.py
index 57c9b08ca43..abfa885ded4 100644
--- a/doc/OnlineDocs/src/data/param8a.py
+++ b/doc/OnlineDocs/src/data/param8a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set1.py b/doc/OnlineDocs/src/data/set1.py
index 5248e9d5dc9..c84c1ef0819 100644
--- a/doc/OnlineDocs/src/data/set1.py
+++ b/doc/OnlineDocs/src/data/set1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set2.py b/doc/OnlineDocs/src/data/set2.py
index 82772f48e46..9048a49fecb 100644
--- a/doc/OnlineDocs/src/data/set2.py
+++ b/doc/OnlineDocs/src/data/set2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set2a.py b/doc/OnlineDocs/src/data/set2a.py
index edf28757f96..f2fa4d71916 100644
--- a/doc/OnlineDocs/src/data/set2a.py
+++ b/doc/OnlineDocs/src/data/set2a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set3.py b/doc/OnlineDocs/src/data/set3.py
index d58e0c0dd43..9cdacbe39e0 100644
--- a/doc/OnlineDocs/src/data/set3.py
+++ b/doc/OnlineDocs/src/data/set3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set4.py b/doc/OnlineDocs/src/data/set4.py
index 29548519571..b3485638c6f 100644
--- a/doc/OnlineDocs/src/data/set4.py
+++ b/doc/OnlineDocs/src/data/set4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/set5.py b/doc/OnlineDocs/src/data/set5.py
index 35acd4e4317..d745d8408d0 100644
--- a/doc/OnlineDocs/src/data/set5.py
+++ b/doc/OnlineDocs/src/data/set5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table0.py b/doc/OnlineDocs/src/data/table0.py
index af7f634bd34..de0fae0c861 100644
--- a/doc/OnlineDocs/src/data/table0.py
+++ b/doc/OnlineDocs/src/data/table0.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table0.ul.py b/doc/OnlineDocs/src/data/table0.ul.py
index 213407b071c..524c3756782 100644
--- a/doc/OnlineDocs/src/data/table0.ul.py
+++ b/doc/OnlineDocs/src/data/table0.ul.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table1.py b/doc/OnlineDocs/src/data/table1.py
index 1f86508c60a..f36714b8f1f 100644
--- a/doc/OnlineDocs/src/data/table1.py
+++ b/doc/OnlineDocs/src/data/table1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table2.py b/doc/OnlineDocs/src/data/table2.py
index d7708b9277f..03648a00f8c 100644
--- a/doc/OnlineDocs/src/data/table2.py
+++ b/doc/OnlineDocs/src/data/table2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table2.txt b/doc/OnlineDocs/src/data/table2.txt
index 60eb55aab4a..a710b6b6042 100644
--- a/doc/OnlineDocs/src/data/table2.txt
+++ b/doc/OnlineDocs/src/data/table2.txt
@@ -1,13 +1,10 @@
-3 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'B1', 'B2', 'B3'}
- N_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 'B1'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B1'), ('A2', 'B2'), ('A2', 'B3'), ('A3', 'B1'), ('A3', 'B2'), ('A3', 'B3')}
2 Param Declarations
M : Size=3, Index=A, Domain=Any, Default=None, Mutable=False
@@ -15,10 +12,10 @@
A1 : 4.3
A2 : 4.4
A3 : 4.5
- N : Size=3, Index=N_index, Domain=Any, Default=None, Mutable=False
+ N : Size=3, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'B1') : 5.3
('A2', 'B2') : 5.4
('A3', 'B3') : 5.5
-5 Declarations: A B M N_index N
+4 Declarations: A B M N
diff --git a/doc/OnlineDocs/src/data/table3.py b/doc/OnlineDocs/src/data/table3.py
index fa871a4f79c..2c598f112df 100644
--- a/doc/OnlineDocs/src/data/table3.py
+++ b/doc/OnlineDocs/src/data/table3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table3.txt b/doc/OnlineDocs/src/data/table3.txt
index cb5e63b30d4..c0c61cd5a5b 100644
--- a/doc/OnlineDocs/src/data/table3.txt
+++ b/doc/OnlineDocs/src/data/table3.txt
@@ -1,13 +1,10 @@
-4 Set Declarations
+3 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'B1', 'B2', 'B3'}
- N_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 'B1'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B1'), ('A2', 'B2'), ('A2', 'B3'), ('A3', 'B1'), ('A3', 'B2'), ('A3', 'B3')}
Z : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 3 : {('A1', 'B1'), ('A2', 'B2'), ('A3', 'B3')}
@@ -18,10 +15,10 @@
A1 : 4.3
A2 : 4.4
A3 : 4.5
- N : Size=3, Index=N_index, Domain=Any, Default=None, Mutable=False
+ N : Size=3, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'B1') : 5.3
('A2', 'B2') : 5.4
('A3', 'B3') : 5.5
-6 Declarations: A B Z M N_index N
+5 Declarations: A B Z M N
diff --git a/doc/OnlineDocs/src/data/table3.ul.py b/doc/OnlineDocs/src/data/table3.ul.py
index 713d36b9f3a..18ced12b388 100644
--- a/doc/OnlineDocs/src/data/table3.ul.py
+++ b/doc/OnlineDocs/src/data/table3.ul.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table3.ul.txt b/doc/OnlineDocs/src/data/table3.ul.txt
index cb5e63b30d4..c0c61cd5a5b 100644
--- a/doc/OnlineDocs/src/data/table3.ul.txt
+++ b/doc/OnlineDocs/src/data/table3.ul.txt
@@ -1,13 +1,10 @@
-4 Set Declarations
+3 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'B1', 'B2', 'B3'}
- N_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 'B1'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B1'), ('A2', 'B2'), ('A2', 'B3'), ('A3', 'B1'), ('A3', 'B2'), ('A3', 'B3')}
Z : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 3 : {('A1', 'B1'), ('A2', 'B2'), ('A3', 'B3')}
@@ -18,10 +15,10 @@
A1 : 4.3
A2 : 4.4
A3 : 4.5
- N : Size=3, Index=N_index, Domain=Any, Default=None, Mutable=False
+ N : Size=3, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'B1') : 5.3
('A2', 'B2') : 5.4
('A3', 'B3') : 5.5
-6 Declarations: A B Z M N_index N
+5 Declarations: A B Z M N
diff --git a/doc/OnlineDocs/src/data/table4.py b/doc/OnlineDocs/src/data/table4.py
index 1af9fe47a44..bd20682b5a9 100644
--- a/doc/OnlineDocs/src/data/table4.py
+++ b/doc/OnlineDocs/src/data/table4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table4.ul.py b/doc/OnlineDocs/src/data/table4.ul.py
index 2acf8e21ca8..9f16f21fe19 100644
--- a/doc/OnlineDocs/src/data/table4.ul.py
+++ b/doc/OnlineDocs/src/data/table4.ul.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table5.py b/doc/OnlineDocs/src/data/table5.py
index 2fe3d08fe91..a3cb01209a2 100644
--- a/doc/OnlineDocs/src/data/table5.py
+++ b/doc/OnlineDocs/src/data/table5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table6.py b/doc/OnlineDocs/src/data/table6.py
index fcbc2f10860..1db0a764a23 100644
--- a/doc/OnlineDocs/src/data/table6.py
+++ b/doc/OnlineDocs/src/data/table6.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/data/table7.py b/doc/OnlineDocs/src/data/table7.py
index f8f8e769b2e..84a841aca86 100644
--- a/doc/OnlineDocs/src/data/table7.py
+++ b/doc/OnlineDocs/src/data/table7.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/dataportal/PP_sqlite.py b/doc/OnlineDocs/src/dataportal/PP_sqlite.py
index 9c6fc5ddc0b..1592e820900 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 d1a75196c99..655329d31de 100644
--- a/doc/OnlineDocs/src/dataportal/dataportal_tab.py
+++ b/doc/OnlineDocs/src/dataportal/dataportal_tab.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
# --------------------------------------------------
diff --git a/doc/OnlineDocs/src/dataportal/dataportal_tab.txt b/doc/OnlineDocs/src/dataportal/dataportal_tab.txt
index 2e507971157..a23c63d90c9 100644
--- a/doc/OnlineDocs/src/dataportal/dataportal_tab.txt
+++ b/doc/OnlineDocs/src/dataportal/dataportal_tab.txt
@@ -85,19 +85,16 @@
A3 : 4.5
2 Declarations: A w
-3 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
I : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {'I1', 'I2', 'I3', 'I4'}
- u_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : I*A : 12 : {('I1', 'A1'), ('I1', 'A2'), ('I1', 'A3'), ('I2', 'A1'), ('I2', 'A2'), ('I2', 'A3'), ('I3', 'A1'), ('I3', 'A2'), ('I3', 'A3'), ('I4', 'A1'), ('I4', 'A2'), ('I4', 'A3')}
1 Param Declarations
- u : Size=12, Index=u_index, Domain=Any, Default=None, Mutable=False
+ u : Size=12, Index=I*A, Domain=Any, Default=None, Mutable=False
Key : Value
('I1', 'A1') : 1.3
('I1', 'A2') : 2.3
@@ -112,20 +109,17 @@
('I4', 'A2') : 2.6
('I4', 'A3') : 3.6
-4 Declarations: A I u_index u
-3 Set Declarations
+3 Declarations: A I u
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
I : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {'I1', 'I2', 'I3', 'I4'}
- t_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*I : 12 : {('A1', 'I1'), ('A1', 'I2'), ('A1', 'I3'), ('A1', 'I4'), ('A2', 'I1'), ('A2', 'I2'), ('A2', 'I3'), ('A2', 'I4'), ('A3', 'I1'), ('A3', 'I2'), ('A3', 'I3'), ('A3', 'I4')}
1 Param Declarations
- t : Size=12, Index=t_index, Domain=Any, Default=None, Mutable=False
+ t : Size=12, Index=A*I, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'I1') : 1.3
('A1', 'I2') : 1.4
@@ -140,7 +134,7 @@
('A3', 'I3') : 3.5
('A3', 'I4') : 3.6
-4 Declarations: A I t_index t
+3 Declarations: A I t
1 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
@@ -185,13 +179,9 @@
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
1 Declarations: A
-1 Set Declarations
- y_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
2 Param Declarations
- y : Size=3, Index=y_index, Domain=Any, Default=None, Mutable=False
+ y : Size=3, Index={A1, A2, A3}, Domain=Any, Default=None, Mutable=False
Key : Value
A1 : 3.3
A2 : 3.4
@@ -200,7 +190,7 @@
Key : Value
None : 1.1
-3 Declarations: z y_index y
+2 Declarations: z y
['A1', 'A2', 'A3']
1.1
A1 3.3
diff --git a/doc/OnlineDocs/src/dataportal/param_initialization.py b/doc/OnlineDocs/src/dataportal/param_initialization.py
index 5567b01f284..7f9270b5fda 100644
--- a/doc/OnlineDocs/src/dataportal/param_initialization.py
+++ b/doc/OnlineDocs/src/dataportal/param_initialization.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import numpy
diff --git a/doc/OnlineDocs/src/dataportal/param_initialization.txt b/doc/OnlineDocs/src/dataportal/param_initialization.txt
index fec8a06a84a..49ea105f120 100644
--- a/doc/OnlineDocs/src/dataportal/param_initialization.txt
+++ b/doc/OnlineDocs/src/dataportal/param_initialization.txt
@@ -1,24 +1,16 @@
-2 Set Declarations
- b_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- c_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
-
3 Param Declarations
a : Size=1, Index=None, Domain=Any, Default=None, Mutable=False
Key : Value
None : 1.1
- b : Size=3, Index=b_index, Domain=Any, Default=None, Mutable=False
+ b : Size=3, Index={1, 2, 3}, Domain=Any, Default=None, Mutable=False
Key : Value
1 : 1
2 : 2
3 : 3
- c : Size=3, Index=c_index, Domain=Any, Default=None, Mutable=False
+ c : Size=3, Index={1, 2, 3}, Domain=Any, Default=None, Mutable=False
Key : Value
1 : 1
2 : 2
3 : 3
-5 Declarations: a b_index b c_index c
+3 Declarations: a b c
diff --git a/doc/OnlineDocs/src/dataportal/set_initialization.py b/doc/OnlineDocs/src/dataportal/set_initialization.py
index aa7b426fa82..a5ab03894e3 100644
--- a/doc/OnlineDocs/src/dataportal/set_initialization.py
+++ b/doc/OnlineDocs/src/dataportal/set_initialization.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import numpy
diff --git a/doc/OnlineDocs/src/dataportal/set_initialization.txt b/doc/OnlineDocs/src/dataportal/set_initialization.txt
index c6be448eba9..3c2960ce4ef 100644
--- a/doc/OnlineDocs/src/dataportal/set_initialization.txt
+++ b/doc/OnlineDocs/src/dataportal/set_initialization.txt
@@ -1,6 +1,6 @@
WARNING: Initializing ordered Set B with a fundamentally unordered data source
(type: set). This WILL potentially lead to nondeterministic behavior in Pyomo
-9 Set Declarations
+8 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {2, 3, 5}
@@ -22,13 +22,10 @@ WARNING: Initializing ordered Set B with a fundamentally unordered data source
G : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {2, 3, 5}
- H : Size=3, Index=H_index, Ordered=Insertion
+ H : Size=3, Index={2, 3, 4}, Ordered=Insertion
Key : Dimen : Domain : Size : Members
2 : 1 : Any : 3 : {1, 3, 5}
3 : 1 : Any : 3 : {2, 4, 6}
4 : 1 : Any : 3 : {3, 5, 7}
- H_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {2, 3, 4}
-9 Declarations: A B C D E F G H_index H
+8 Declarations: A B C D E F G H
diff --git a/doc/OnlineDocs/src/expr/design.py b/doc/OnlineDocs/src/expr/design.py
index b122a5f2bf3..647a4537ca4 100644
--- a/doc/OnlineDocs/src/expr/design.py
+++ b/doc/OnlineDocs/src/expr/design.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
# ---------------------------------------------
diff --git a/doc/OnlineDocs/src/expr/index.py b/doc/OnlineDocs/src/expr/index.py
index 9c9c79bf7be..fe5b03461c0 100644
--- a/doc/OnlineDocs/src/expr/index.py
+++ b/doc/OnlineDocs/src/expr/index.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
# ---------------------------------------------
diff --git a/doc/OnlineDocs/src/expr/managing.py b/doc/OnlineDocs/src/expr/managing.py
index 0a59c13bc1b..7342d0616a7 100644
--- a/doc/OnlineDocs/src/expr/managing.py
+++ b/doc/OnlineDocs/src/expr/managing.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
from math import isclose
import math
@@ -90,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
# ---------------------------------------------
@@ -111,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 = ConcreteModel()
+m.x = Var()
+m.p = 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
@@ -170,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
diff --git a/doc/OnlineDocs/src/expr/overview.py b/doc/OnlineDocs/src/expr/overview.py
index 6207a4c4288..d33725edb88 100644
--- a/doc/OnlineDocs/src/expr/overview.py
+++ b/doc/OnlineDocs/src/expr/overview.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
# ---------------------------------------------
diff --git a/doc/OnlineDocs/src/expr/performance.py b/doc/OnlineDocs/src/expr/performance.py
index 53ac5bb4f9e..8936bd2ed8c 100644
--- a/doc/OnlineDocs/src/expr/performance.py
+++ b/doc/OnlineDocs/src/expr/performance.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
# ---------------------------------------------
diff --git a/doc/OnlineDocs/src/expr/quicksum.py b/doc/OnlineDocs/src/expr/quicksum.py
index a1ad9660664..1b6cd3f9909 100644
--- a/doc/OnlineDocs/src/expr/quicksum.py
+++ b/doc/OnlineDocs/src/expr/quicksum.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
from pyomo.repn import generate_standard_repn
import 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/src/kernel/examples.txt b/doc/OnlineDocs/src/kernel/examples.txt
index e85c64efd86..8ba072d28b1 100644
--- a/doc/OnlineDocs/src/kernel/examples.txt
+++ b/doc/OnlineDocs/src/kernel/examples.txt
@@ -1,22 +1,7 @@
-6 Set Declarations
- cd_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : s*q : 6 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)}
- cl_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- ol_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
+1 Set Declarations
s : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 2 : {1, 2}
- sd_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
- vl_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
1 RangeSet Declarations
q : Dimen=1, Size=3, Bounds=(1, 3)
@@ -43,7 +28,7 @@
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : None : 9 : False : True : Reals
2 : None : None : 9 : False : True : Reals
- vl : Size=3, Index=vl_index
+ vl : Size=3, Index={1, 2, 3}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : 1 : None : None : False : True : Reals
2 : 2 : None : None : False : True : Reals
@@ -66,7 +51,7 @@
Key : Active : Sense : Expression
1 : True : minimize : - vd[1]
2 : True : minimize : - vd[2]
- ol : Size=3, Index=ol_index, Active=True
+ ol : Size=3, Index={1, 2, 3}, Active=True
Key : Active : Sense : Expression
1 : True : minimize : - vl[1]
2 : True : minimize : - vl[2]
@@ -76,7 +61,7 @@
c : Size=1, Index=None, Active=True
Key : Lower : Body : Upper : Active
None : -Inf : vd[1] + vd[2] : 9.0 : True
- cd : Size=6, Index=cd_index, Active=True
+ cd : Size=6, Index=s*q, Active=True
Key : Lower : Body : Upper : Active
(1, 1) : 1.0 : vd[1] : 1.0 : True
(1, 2) : 2.0 : vd[1] : 2.0 : True
@@ -84,14 +69,14 @@
(2, 1) : 1.0 : vd[2] : 1.0 : True
(2, 2) : 2.0 : vd[2] : 2.0 : True
(2, 3) : 3.0 : vd[2] : 3.0 : True
- cl : Size=3, Index=cl_index, Active=True
+ cl : Size=3, Index={1, 2, 3}, Active=True
Key : Lower : Body : Upper : Active
1 : -5.0 : vl[1] - v : 5.0 : True
2 : -5.0 : vl[2] - v : 5.0 : True
3 : -5.0 : vl[3] - v : 5.0 : True
3 SOSConstraint Declarations
- sd : Size=2 Index= sd_index
+ sd : Size=2 Index= OrderedScalarSet
1
Type=1
Weight : Variable
@@ -119,16 +104,8 @@
b : Size=1, Index=None, Active=True
0 Declarations:
pw : Size=1, Index=None, Active=True
- 2 Set Declarations
- SOS2_constraint_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- SOS2_y_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {0, 1, 2, 3}
-
1 Var Declarations
- SOS2_y : Size=4, Index=pw.SOS2_y_index
+ SOS2_y : Size=4, Index={0, 1, 2, 3}
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : None : None : False : True : NonNegativeReals
1 : 0 : None : None : False : True : NonNegativeReals
@@ -136,7 +113,7 @@
3 : 0 : None : None : False : True : NonNegativeReals
1 Constraint Declarations
- SOS2_constraint : Size=3, Index=pw.SOS2_constraint_index, Active=True
+ SOS2_constraint : Size=3, Index={1, 2, 3}, Active=True
Key : Lower : Body : Upper : Active
1 : 0.0 : v - (pw.SOS2_y[0] + 2*pw.SOS2_y[1] + 3*pw.SOS2_y[2] + 4*pw.SOS2_y[3]) : 0.0 : True
2 : 0.0 : f - (pw.SOS2_y[0] + 2*pw.SOS2_y[1] + pw.SOS2_y[2] + 2*pw.SOS2_y[3]) : 0.0 : True
@@ -151,13 +128,13 @@
3 : pw.SOS2_y[2]
4 : pw.SOS2_y[3]
- 5 Declarations: SOS2_y_index SOS2_y SOS2_constraint_index SOS2_constraint SOS2_sosconstraint
+ 3 Declarations: SOS2_y SOS2_constraint SOS2_sosconstraint
1 Suffix Declarations
dual : Direction=IMPORT, Datatype=FLOAT
Key : Value
-27 Declarations: b s q p pd v vd vl_index vl c cd_index cd cl_index cl e ed o od ol_index ol sos1 sos2 sd_index sd dual f pw
+22 Declarations: b s q p pd v vd vl c cd cl e ed o od ol sos1 sos2 sd dual f pw
: block(active=True, ctype=IBlock)
- b: block(active=True, ctype=IBlock)
- p: parameter(active=True, value=0)
@@ -231,4 +208,4 @@
- pw.c[2]: linear_constraint(active=True, expr=pw.v[0] + pw.v[1] + pw.v[2] + pw.v[3] == 1)
- pw.s: sos(active=True, level=2, entries=['(pw.v[0],1)', '(pw.v[1],2)', '(pw.v[2],3)', '(pw.v[3],4)'])
Memory: 1.9 KB
-Memory: 9.5 KB
+Memory: 9.7 KB
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/aml_example.py b/doc/OnlineDocs/src/kernel/examples/aml_example.py
similarity index 83%
rename from doc/OnlineDocs/library_reference/kernel/examples/aml_example.py
rename to doc/OnlineDocs/src/kernel/examples/aml_example.py
index 146048a6046..a640b94cc76 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/aml_example.py
+++ b/doc/OnlineDocs/src/kernel/examples/aml_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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_Syntax
import pyomo.environ as aml
diff --git a/pyomo/core/base/rangeset.py b/doc/OnlineDocs/src/kernel/examples/conic.py
similarity index 53%
rename from pyomo/core/base/rangeset.py
rename to doc/OnlineDocs/src/kernel/examples/conic.py
index 18dedb84c34..0418d188722 100644
--- a/pyomo/core/base/rangeset.py
+++ b/doc/OnlineDocs/src/kernel/examples/conic.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,25 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-__all__ = ['RangeSet']
+# @Class
+import pyomo.kernel as pmo
-from .set import RangeSet
+m = pmo.block()
+m.x1 = pmo.variable(lb=0)
+m.x2 = pmo.variable()
+m.r = pmo.variable(lb=0)
+m.q = pmo.conic.primal_exponential(x1=m.x1, x2=m.x2, r=m.r)
+# @Class
+del m
-from pyomo.common.deprecation import deprecation_warning
+# @Domain
+import pyomo.kernel as pmo
+import math
-deprecation_warning(
- 'The pyomo.core.base.rangeset module is deprecated. '
- 'Import RangeSet objects from pyomo.core.base.set or pyomo.core.',
- version='5.7',
+m = pmo.block()
+m.x = pmo.variable(lb=0)
+m.y = pmo.variable(lb=0)
+m.b = pmo.conic.primal_exponential.as_domain(
+ x1=math.sqrt(2) * m.x, x2=2.0, r=2 * (m.x + m.y)
)
+# @Domain
diff --git a/doc/OnlineDocs/src/kernel/examples/kernel_containers.py b/doc/OnlineDocs/src/kernel/examples/kernel_containers.py
new file mode 100644
index 00000000000..1931c6d9b56
--- /dev/null
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_containers.py
@@ -0,0 +1,18 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel
+
+# @all
+vlist = pyomo.kernel.variable_list()
+vlist.append(pyomo.kernel.variable_dict())
+vlist[0]['x'] = pyomo.kernel.variable()
+# @all
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py b/doc/OnlineDocs/src/kernel/examples/kernel_example.py
similarity index 84%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_example.py
index 1caf064bb2a..1f80bce9788 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_example.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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_Syntax
import pyomo.kernel as pmo
diff --git a/pyomo/solvers/tests/mip/test_mip.py b/doc/OnlineDocs/src/kernel/examples/kernel_solving.py
similarity index 63%
rename from pyomo/solvers/tests/mip/test_mip.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_solving.py
index 0257e65de20..13d7efc052a 100644
--- a/pyomo/solvers/tests/mip/test_mip.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_solving.py
@@ -1,23 +1,22 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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.
# ___________________________________________________________________________
-#
-# Tests driven by test_mip.yml
-#
-import os
-from os.path import abspath, dirname
+import pyomo.kernel as pmo
-currdir = dirname(abspath(__file__)) + os.sep
+model = pmo.block()
+model.x = pmo.variable()
+model.c = pmo.constraint(model.x >= 1)
+model.o = pmo.objective(model.x)
-import pyomo.common.unittest as unittest
+opt = pmo.SolverFactory("ipopt")
-if __name__ == "__main__":
- unittest.main()
+result = opt.solve(model)
+assert str(result.solver.termination_condition) == "optimal"
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py b/doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
similarity index 76%
rename from doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py
rename to doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
index c21c6dc890b..d6e38f6b0e0 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/kernel_subclassing.py
+++ b/doc/OnlineDocs/src/kernel/examples/kernel_subclassing.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel
diff --git a/doc/OnlineDocs/library_reference/kernel/examples/transformer.py b/doc/OnlineDocs/src/kernel/examples/transformer.py
similarity index 71%
rename from doc/OnlineDocs/library_reference/kernel/examples/transformer.py
rename to doc/OnlineDocs/src/kernel/examples/transformer.py
index 66893008cf9..43a1d0675bf 100644
--- a/doc/OnlineDocs/library_reference/kernel/examples/transformer.py
+++ b/doc/OnlineDocs/src/kernel/examples/transformer.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
import pyomo.kernel
diff --git a/doc/OnlineDocs/src/scripting/AbstractSuffixes.py b/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
index 20a4cc20581..1c064042c6b 100644
--- a/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
+++ b/doc/OnlineDocs/src/scripting/AbstractSuffixes.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/doc/OnlineDocs/src/scripting/Isinglebuild.py b/doc/OnlineDocs/src/scripting/Isinglebuild.py
index 00f79c9a750..344f8905a4a 100644
--- a/doc/OnlineDocs/src/scripting/Isinglebuild.py
+++ b/doc/OnlineDocs/src/scripting/Isinglebuild.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Isinglebuild.py
# NodesIn and NodesOut are created by a build action using the Arcs
from pyomo.environ import *
diff --git a/doc/OnlineDocs/src/scripting/NodesIn_init.py b/doc/OnlineDocs/src/scripting/NodesIn_init.py
index 4a90029baa3..c17b70150bc 100644
--- a/doc/OnlineDocs/src/scripting/NodesIn_init.py
+++ b/doc/OnlineDocs/src/scripting/NodesIn_init.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
def NodesIn_init(model, node):
retval = []
for i, j in model.Arcs:
diff --git a/doc/OnlineDocs/src/scripting/Z_init.py b/doc/OnlineDocs/src/scripting/Z_init.py
index 426de6f7d08..1dd2843f4f0 100644
--- a/doc/OnlineDocs/src/scripting/Z_init.py
+++ b/doc/OnlineDocs/src/scripting/Z_init.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
def Z_init(model, i):
if i > 10:
return Set.End
diff --git a/doc/OnlineDocs/src/scripting/abstract2.py b/doc/OnlineDocs/src/scripting/abstract2.py
index 1e14d1d1898..544399a8a42 100644
--- a/doc/OnlineDocs/src/scripting/abstract2.py
+++ b/doc/OnlineDocs/src/scripting/abstract2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract2.py
diff --git a/doc/OnlineDocs/src/scripting/abstract2piece.py b/doc/OnlineDocs/src/scripting/abstract2piece.py
index 225ec0d1a64..03c5139004e 100644
--- a/doc/OnlineDocs/src/scripting/abstract2piece.py
+++ b/doc/OnlineDocs/src/scripting/abstract2piece.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract2piece.py
# Similar to abstract2.py, but the objective is now c times x to the fourth power
diff --git a/doc/OnlineDocs/src/scripting/abstract2piecebuild.py b/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
index 1f00cdb0265..d454d7fbc79 100644
--- a/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
+++ b/doc/OnlineDocs/src/scripting/abstract2piecebuild.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract2piecebuild.py
# Similar to abstract2piece.py, but the breakpoints are created using a build action
diff --git a/doc/OnlineDocs/src/scripting/block_iter_example.py b/doc/OnlineDocs/src/scripting/block_iter_example.py
index 680e0d1728b..10c8a4ea43d 100644
--- a/doc/OnlineDocs/src/scripting/block_iter_example.py
+++ b/doc/OnlineDocs/src/scripting/block_iter_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# written by jds, adapted for doc by dlw
from pyomo.environ import *
diff --git a/doc/OnlineDocs/src/scripting/concrete1.py b/doc/OnlineDocs/src/scripting/concrete1.py
index 2cd1a1f722c..399715efde6 100644
--- a/doc/OnlineDocs/src/scripting/concrete1.py
+++ b/doc/OnlineDocs/src/scripting/concrete1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = ConcreteModel()
diff --git a/doc/OnlineDocs/src/scripting/doubleA.py b/doc/OnlineDocs/src/scripting/doubleA.py
index 12a07944db3..abf35979a05 100644
--- a/doc/OnlineDocs/src/scripting/doubleA.py
+++ b/doc/OnlineDocs/src/scripting/doubleA.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
def doubleA_init(model):
return (i * 2 for i in model.A)
diff --git a/doc/OnlineDocs/src/scripting/driveabs2.py b/doc/OnlineDocs/src/scripting/driveabs2.py
index 45862195a57..f8f972460b1 100644
--- a/doc/OnlineDocs/src/scripting/driveabs2.py
+++ b/doc/OnlineDocs/src/scripting/driveabs2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# driveabs2.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/driveconc1.py b/doc/OnlineDocs/src/scripting/driveconc1.py
index 95b0f42806d..49b92f32d09 100644
--- a/doc/OnlineDocs/src/scripting/driveconc1.py
+++ b/doc/OnlineDocs/src/scripting/driveconc1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# driveconc1.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/iterative1.py b/doc/OnlineDocs/src/scripting/iterative1.py
index 61b0fd3828e..939120e834f 100644
--- a/doc/OnlineDocs/src/scripting/iterative1.py
+++ b/doc/OnlineDocs/src/scripting/iterative1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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_symbols_for_pyomo
# iterative1.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/iterative2.py b/doc/OnlineDocs/src/scripting/iterative2.py
index e559a2c8400..7506337a491 100644
--- a/doc/OnlineDocs/src/scripting/iterative2.py
+++ b/doc/OnlineDocs/src/scripting/iterative2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# iterative2.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/noiteration1.py b/doc/OnlineDocs/src/scripting/noiteration1.py
index be9fb529855..c7a86e9d1e9 100644
--- a/doc/OnlineDocs/src/scripting/noiteration1.py
+++ b/doc/OnlineDocs/src/scripting/noiteration1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# noiteration1.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/parallel.py b/doc/OnlineDocs/src/scripting/parallel.py
index cf9b55d9605..e6cfa002780 100644
--- a/doc/OnlineDocs/src/scripting/parallel.py
+++ b/doc/OnlineDocs/src/scripting/parallel.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# parallel.py
# run with mpirun -np 2 python -m mpi4py parallel.py
import pyomo.environ as pyo
diff --git a/doc/OnlineDocs/src/scripting/spy4Constraints.py b/doc/OnlineDocs/src/scripting/spy4Constraints.py
index f0033bbc33e..66f82802402 100644
--- a/doc/OnlineDocs/src/scripting/spy4Constraints.py
+++ b/doc/OnlineDocs/src/scripting/spy4Constraints.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
David L. Woodruff and Mingye Yang, Spring 2018
Code snippets for Constraints.rst in testable form
diff --git a/doc/OnlineDocs/src/scripting/spy4Expressions.py b/doc/OnlineDocs/src/scripting/spy4Expressions.py
index 0e8a50c78b3..cf7ed1f112f 100644
--- a/doc/OnlineDocs/src/scripting/spy4Expressions.py
+++ b/doc/OnlineDocs/src/scripting/spy4Expressions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
David L. Woodruff and Mingye Yang, Spring 2018
Code snippets for Expressions.rst in testable form
diff --git a/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py b/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
index f655b812076..9f6698d63c9 100644
--- a/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
+++ b/doc/OnlineDocs/src/scripting/spy4PyomoCommand.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
David L. Woodruff and Mingye Yang, Spring 2018
Code snippets for PyomoCommand.rst in testable form
diff --git a/doc/OnlineDocs/src/scripting/spy4Variables.py b/doc/OnlineDocs/src/scripting/spy4Variables.py
index c4e2ff612f1..1bc2dc9f1ef 100644
--- a/doc/OnlineDocs/src/scripting/spy4Variables.py
+++ b/doc/OnlineDocs/src/scripting/spy4Variables.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
David L. Woodruff and Mingye Yang, Spring 2018
Code snippets for Variables.rst in testable form
diff --git a/doc/OnlineDocs/src/scripting/spy4scripts.py b/doc/OnlineDocs/src/scripting/spy4scripts.py
index 48ba923d09c..f71a1b67b11 100644
--- a/doc/OnlineDocs/src/scripting/spy4scripts.py
+++ b/doc/OnlineDocs/src/scripting/spy4scripts.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
###NOTE: as of May 16, this will not even come close to running. DLW
### and it is "wrong" in a lot of places.
### Someone should edit this file, then delete these comment lines. DLW may 16
diff --git a/doc/OnlineDocs/src/strip_examples.py b/doc/OnlineDocs/src/strip_examples.py
index 045af6b87cc..2fd03256499 100644
--- a/doc/OnlineDocs/src/strip_examples.py
+++ b/doc/OnlineDocs/src/strip_examples.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 script finds all *.py files in the current and subdirectories.
# It processes these files to find blocks that start/end with "# @"
diff --git a/doc/OnlineDocs/src/test_examples.py b/doc/OnlineDocs/src/test_examples.py
index a7991eadf19..c5c9a135ee9 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 11f35fddd13..7e11ec59263 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/Optimal_Control.py b/examples/dae/Optimal_Control.py
index ed44d5eeb59..676c95271f2 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/PDE_example.py b/examples/dae/PDE_example.py
index 6cb7eb4a7fe..0aea173415b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/Parameter_Estimation.py b/examples/dae/Parameter_Estimation.py
index 7ee2f112b94..332a21d93dc 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/Path_Constraint.py b/examples/dae/Path_Constraint.py
index 866b4b3b90a..69f31980c63 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/ReactionKinetics.py b/examples/dae/ReactionKinetics.py
index ef760820c4b..2e474ae40d3 100644
--- a/examples/dae/ReactionKinetics.py
+++ b/examples/dae/ReactionKinetics.py
@@ -2,7 +2,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
@@ -304,7 +304,10 @@ def regression_model():
# Model & data from:
#
- # http://www.doiserbia.nb.rs/img/doi/0367-598X/2014/0367-598X1300037A.pdf
+ # https://doiserbia.nb.rs/img/doi/0367-598X/2014/0367-598X1300037A.pdf
+ # Almagrbi, A. M., Hatami, T., Glišić, S., & Orlović, A. (2014).
+ # Determination of kinetic parameters for complex transesterification
+ # reaction by standard optimisation methods.
#
model = ConcreteModel()
diff --git a/examples/dae/car_example.py b/examples/dae/car_example.py
index a157159cf6c..b6ca2203860 100644
--- a/examples/dae/car_example.py
+++ b/examples/dae/car_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Ampl Car Example
#
# Shows how to convert a minimize final time optimal control problem
diff --git a/examples/dae/disease_DAE.py b/examples/dae/disease_DAE.py
index 59e598aa504..bfeb2530fc9 100644
--- a/examples/dae/disease_DAE.py
+++ b/examples/dae/disease_DAE.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
###
# SIR disease model using radau collocation
###
diff --git a/examples/dae/distill_DAE.py b/examples/dae/distill_DAE.py
index cdfd543f9a8..e822cfb1752 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/dynamic_scheduling.py b/examples/dae/dynamic_scheduling.py
index 13cabeb5bcf..137307e31a9 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/laplace_BVP.py b/examples/dae/laplace_BVP.py
index 6b2e2841575..61f911b3826 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/run_Optimal_Control.py b/examples/dae/run_Optimal_Control.py
index 2523bd8c607..2e7bc79dff4 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/run_Parameter_Estimation.py b/examples/dae/run_Parameter_Estimation.py
index a319000cb59..c9b649df8dd 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/run_Path_Constraint.py b/examples/dae/run_Path_Constraint.py
index 17a576a57d8..996b432a555 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/run_disease.py b/examples/dae/run_disease.py
index 139046d434e..5d9595a89d5 100644
--- a/examples/dae/run_disease.py
+++ b/examples/dae/run_disease.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
from pyomo.dae import *
from disease_DAE import model
diff --git a/examples/dae/run_distill.py b/examples/dae/run_distill.py
index d9ececf34fc..9b09850f90a 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/dae/run_stochpdegas_automatic.py b/examples/dae/run_stochpdegas_automatic.py
index dd710588406..6fc9f6d594c 100644
--- a/examples/dae/run_stochpdegas_automatic.py
+++ b/examples/dae/run_stochpdegas_automatic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 time
from pyomo.environ import *
diff --git a/examples/dae/simulator_dae_example.py b/examples/dae/simulator_dae_example.py
index ef6484be6c6..4ea1f9fd5f0 100644
--- a/examples/dae/simulator_dae_example.py
+++ b/examples/dae/simulator_dae_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#
# Batch reactor example from Biegler book on Nonlinear Programming Chapter 9
#
diff --git a/examples/dae/simulator_dae_multindex_example.py b/examples/dae/simulator_dae_multindex_example.py
index d1a97fec79f..775eb4f8c79 100644
--- a/examples/dae/simulator_dae_multindex_example.py
+++ b/examples/dae/simulator_dae_multindex_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#
# Batch reactor example from Biegler book on Nonlinear Programming Chapter 9
#
diff --git a/examples/dae/simulator_ode_example.py b/examples/dae/simulator_ode_example.py
index bf600cf163e..f6f28b87d07 100644
--- a/examples/dae/simulator_ode_example.py
+++ b/examples/dae/simulator_ode_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#
# Example from Scipy odeint examples
#
diff --git a/examples/dae/simulator_ode_multindex_example.py b/examples/dae/simulator_ode_multindex_example.py
index fa2623f4cc2..b1b9111084b 100644
--- a/examples/dae/simulator_ode_multindex_example.py
+++ b/examples/dae/simulator_ode_multindex_example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#
# Example from Scipy odeint examples
#
diff --git a/examples/dae/stochpdegas_automatic.py b/examples/dae/stochpdegas_automatic.py
index fdde099a396..397b4a18100 100644
--- a/examples/dae/stochpdegas_automatic.py
+++ b/examples/dae/stochpdegas_automatic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# stochastic pde model for natural gas network
# victor m. zavala / 2013
diff --git a/examples/doc/samples/__init__.py b/examples/doc/samples/__init__.py
index 3115f06ef53..0110902b288 100644
--- a/examples/doc/samples/__init__.py
+++ b/examples/doc/samples/__init__.py
@@ -1 +1,12 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Dummy file for pytest
diff --git a/examples/doc/samples/case_studies/deer/DeerProblem.py b/examples/doc/samples/case_studies/deer/DeerProblem.py
index 0b6b7252aaa..d09c9b53887 100644
--- a/examples/doc/samples/case_studies/deer/DeerProblem.py
+++ b/examples/doc/samples/case_studies/deer/DeerProblem.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
#
diff --git a/examples/doc/samples/case_studies/diet/DietProblem.py b/examples/doc/samples/case_studies/diet/DietProblem.py
index f070201c28e..64624310943 100644
--- a/examples/doc/samples/case_studies/diet/DietProblem.py
+++ b/examples/doc/samples/case_studies/diet/DietProblem.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/case_studies/diet/DietProblem.tex b/examples/doc/samples/case_studies/diet/DietProblem.tex
index d933e097d88..e2ae7ba4c62 100644
--- a/examples/doc/samples/case_studies/diet/DietProblem.tex
+++ b/examples/doc/samples/case_studies/diet/DietProblem.tex
@@ -54,7 +54,7 @@ \subsection*{Build the model}
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}
diff --git a/examples/doc/samples/case_studies/diet/README.txt b/examples/doc/samples/case_studies/diet/README.txt
index c30e963dc27..c382b4d653c 100644
--- a/examples/doc/samples/case_studies/diet/README.txt
+++ b/examples/doc/samples/case_studies/diet/README.txt
@@ -68,7 +68,7 @@ model.nutrient_value=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
diff --git a/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py b/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
index c685a6ee67f..6a0edb38350 100644
--- a/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
+++ b/examples/doc/samples/case_studies/disease_est/DiseaseEstimation.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/case_studies/max_flow/MaxFlow.py b/examples/doc/samples/case_studies/max_flow/MaxFlow.py
index c6eb42ccf7d..1e75fa4e79d 100644
--- a/examples/doc/samples/case_studies/max_flow/MaxFlow.py
+++ b/examples/doc/samples/case_studies/max_flow/MaxFlow.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/case_studies/network_flow/networkFlow1.py b/examples/doc/samples/case_studies/network_flow/networkFlow1.py
index adfaab4476b..eb8c8e48a1a 100644
--- a/examples/doc/samples/case_studies/network_flow/networkFlow1.py
+++ b/examples/doc/samples/case_studies/network_flow/networkFlow1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/case_studies/rosen/Rosenbrock.py b/examples/doc/samples/case_studies/rosen/Rosenbrock.py
index 9677cea95dd..51e7d51b57d 100644
--- a/examples/doc/samples/case_studies/rosen/Rosenbrock.py
+++ b/examples/doc/samples/case_studies/rosen/Rosenbrock.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# @intro:
from pyomo.core import *
diff --git a/examples/doc/samples/case_studies/transportation/transportation.py b/examples/doc/samples/case_studies/transportation/transportation.py
index 26fcb5f0b66..588ae764953 100644
--- a/examples/doc/samples/case_studies/transportation/transportation.py
+++ b/examples/doc/samples/case_studies/transportation/transportation.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py b/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
index 796c39810f8..f49c5b591ae 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_cplex.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 cplex
from cutstock_util import *
from cplex.exceptions import CplexSolverError
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_grb.py b/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
index 4fa4556fc96..483d84b02e6 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_grb.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 gurobipy import *
from cutstock_util import *
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py b/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
index 658ee006c30..9a6c8301e8f 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_lpsolve.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 lpsolve55 import *
from cutstock_util import *
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py b/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
index 2f2506ba3d6..d14b0fe46c1 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_pulpor.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pulp import *
from cutstock_util import *
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py b/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
index a67ebdd0675..48d7e6b26fd 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_pyomo.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
import pyomo.opt
from cutstock_util import *
diff --git a/examples/doc/samples/comparisons/cutstock/cutstock_util.py b/examples/doc/samples/comparisons/cutstock/cutstock_util.py
index 1cd8c61922f..da5349ec06c 100644
--- a/examples/doc/samples/comparisons/cutstock/cutstock_util.py
+++ b/examples/doc/samples/comparisons/cutstock/cutstock_util.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
def getCutCount():
cutCount = 0
fout1 = open('WidthDemand.csv', 'r')
diff --git a/examples/doc/samples/comparisons/sched/pyomo/sched.py b/examples/doc/samples/comparisons/sched/pyomo/sched.py
index 627bc083fbe..cf781713641 100644
--- a/examples/doc/samples/comparisons/sched/pyomo/sched.py
+++ b/examples/doc/samples/comparisons/sched/pyomo/sched.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/doc/samples/scripts/__init__.py b/examples/doc/samples/scripts/__init__.py
index 3115f06ef53..0110902b288 100644
--- a/examples/doc/samples/scripts/__init__.py
+++ b/examples/doc/samples/scripts/__init__.py
@@ -1 +1,12 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Dummy file for pytest
diff --git a/examples/doc/samples/scripts/s1/knapsack.py b/examples/doc/samples/scripts/s1/knapsack.py
index 642e0faaaed..cee3937b668 100644
--- a/examples/doc/samples/scripts/s1/knapsack.py
+++ b/examples/doc/samples/scripts/s1/knapsack.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
diff --git a/examples/doc/samples/scripts/s1/script.py b/examples/doc/samples/scripts/s1/script.py
index 02b6b406922..4ddaea45e19 100644
--- a/examples/doc/samples/scripts/s1/script.py
+++ b/examples/doc/samples/scripts/s1/script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
import pyomo.opt
import pyomo.environ
diff --git a/examples/doc/samples/scripts/s2/knapsack.py b/examples/doc/samples/scripts/s2/knapsack.py
index a7d693f5d35..3131cee7bc5 100644
--- a/examples/doc/samples/scripts/s2/knapsack.py
+++ b/examples/doc/samples/scripts/s2/knapsack.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
diff --git a/examples/doc/samples/scripts/s2/script.py b/examples/doc/samples/scripts/s2/script.py
index 88de1dec680..fe97d6ab8fd 100644
--- a/examples/doc/samples/scripts/s2/script.py
+++ b/examples/doc/samples/scripts/s2/script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
import pyomo.opt
import pyomo.environ
diff --git a/examples/doc/samples/scripts/test_scripts.py b/examples/doc/samples/scripts/test_scripts.py
index ca0c8a7cc4e..691a44aea2d 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 9eae2f4b694..8789413303c 100644
--- a/examples/doc/samples/update.py
+++ b/examples/doc/samples/update.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#!/usr/bin/env python
#
# This is a Python script that regenerates the top-level TRAC.txt file, which
diff --git a/examples/gdp/batchProcessing.py b/examples/gdp/batchProcessing.py
index f0980dd5034..9810f5d63f1 100644
--- a/examples/gdp/batchProcessing.py
+++ b/examples/gdp/batchProcessing.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
from pyomo.gdp import *
diff --git a/examples/gdp/circles/circles.py b/examples/gdp/circles/circles.py
index ae905998403..586cc7d3af3 100644
--- a/examples/gdp/circles/circles.py
+++ b/examples/gdp/circles/circles.py
@@ -1,6 +1,17 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
-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 245aa2df58e..d38fd0cc66b 100644
--- a/examples/gdp/constrained_layout/cons_layout_model.py
+++ b/examples/gdp/constrained_layout/cons_layout_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""2-D constrained layout example.
Example based on: https://www.minlp.org/library/problem/index.php?i=107&lib=GDP
diff --git a/examples/gdp/disease_model.py b/examples/gdp/disease_model.py
index bc3e69600ec..498337e35e6 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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_logical.py b/examples/gdp/eight_process/eight_proc_logical.py
index 60f7acee876..4496427d421 100644
--- a/examples/gdp/eight_process/eight_proc_logical.py
+++ b/examples/gdp/eight_process/eight_proc_logical.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Disjunctive re-implementation of eight-process problem.
Re-implementation of Duran example 3 superstructure synthesis problem in Pyomo
diff --git a/examples/gdp/eight_process/eight_proc_model.py b/examples/gdp/eight_process/eight_proc_model.py
index 840b6911d83..41bb6d462f1 100644
--- a/examples/gdp/eight_process/eight_proc_model.py
+++ b/examples/gdp/eight_process/eight_proc_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Disjunctive re-implementation of eight-process problem.
Re-implementation of Duran example 3 superstructure synthesis problem in Pyomo
diff --git a/examples/gdp/eight_process/eight_proc_verbose_model.py b/examples/gdp/eight_process/eight_proc_verbose_model.py
index cae584d4127..1fd68909146 100644
--- a/examples/gdp/eight_process/eight_proc_verbose_model.py
+++ b/examples/gdp/eight_process/eight_proc_verbose_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Disjunctive re-implementation of eight-process problem.
This is the more verbose formulation of the same problem given in
diff --git a/examples/gdp/farm_layout/farm_layout.py b/examples/gdp/farm_layout/farm_layout.py
index 411e2de3242..487b3b73cd2 100644
--- a/examples/gdp/farm_layout/farm_layout.py
+++ b/examples/gdp/farm_layout/farm_layout.py
@@ -1,9 +1,20 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""
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 bc656dc4717..0cd5b5ab274 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/jobshop.py b/examples/gdp/jobshop.py
index 619ece47e72..7119ee7655c 100644
--- a/examples/gdp/jobshop.py
+++ b/examples/gdp/jobshop.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/medTermPurchasing_Literal.py b/examples/gdp/medTermPurchasing_Literal.py
index c9b27920396..b6d16c216fe 100755
--- a/examples/gdp/medTermPurchasing_Literal.py
+++ b/examples/gdp/medTermPurchasing_Literal.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
from pyomo.gdp import *
diff --git a/examples/gdp/nine_process/small_process.py b/examples/gdp/nine_process/small_process.py
index 2758069f316..d5b7ac5d327 100644
--- a/examples/gdp/nine_process/small_process.py
+++ b/examples/gdp/nine_process/small_process.py
@@ -1,6 +1,15 @@
-"""Small process synthesis-inspired toy GDP example.
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
-"""
+"""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 f7c77b111f0..de41c0bfd00 100644
--- a/examples/gdp/simple1.py
+++ b/examples/gdp/simple1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Example: modeling a complementarity condition as a
# disjunction
#
diff --git a/examples/gdp/simple2.py b/examples/gdp/simple2.py
index 6bcc7bbf747..b066d705036 100644
--- a/examples/gdp/simple2.py
+++ b/examples/gdp/simple2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Example: modeling a complementarity condition as a
# disjunction
#
diff --git a/examples/gdp/simple3.py b/examples/gdp/simple3.py
index 6b3d6ec46c4..890daf8882b 100644
--- a/examples/gdp/simple3.py
+++ b/examples/gdp/simple3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Example: modeling a complementarity condition as a
# disjunction
#
diff --git a/examples/gdp/small_lit/basic_step.py b/examples/gdp/small_lit/basic_step.py
index 48ef52d9ba0..1919a6e16f8 100644
--- a/examples/gdp/small_lit/basic_step.py
+++ b/examples/gdp/small_lit/basic_step.py
@@ -1,7 +1,18 @@
-""" Example from Section 3.2 in paper of Pseudo Basic Steps
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+"""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
diff --git a/examples/gdp/small_lit/contracts_problem.py b/examples/gdp/small_lit/contracts_problem.py
index 500fe15cb2a..0c59d2264ee 100644
--- a/examples/gdp/small_lit/contracts_problem.py
+++ b/examples/gdp/small_lit/contracts_problem.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
""" Example from 'Lagrangean Relaxation of the Hull-Reformulation of Linear \
Generalized Disjunctive Programs and its use in Disjunctive Branch \
and Bound' Page 25 f.
diff --git a/examples/gdp/small_lit/ex1_Lee.py b/examples/gdp/small_lit/ex1_Lee.py
index ddd2e1c3d2f..abbf470a1c3 100644
--- a/examples/gdp/small_lit/ex1_Lee.py
+++ b/examples/gdp/small_lit/ex1_Lee.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 example of nonlinear problem modeled with GDP framework.
Taken from Example 1 of the paper "New Algorithms for Nonlinear Generalized Disjunctive Programming" by Lee and Grossmann
diff --git a/examples/gdp/small_lit/ex_633_trespalacios.py b/examples/gdp/small_lit/ex_633_trespalacios.py
index 61b7294e3ba..b0c5fbd85ac 100644
--- a/examples/gdp/small_lit/ex_633_trespalacios.py
+++ b/examples/gdp/small_lit/ex_633_trespalacios.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Analytical example from Section 6.3.3 of F. Trespalacions Ph.D. Thesis (2015)
Analytical example for a nonconvex GDP with 2 disjunctions, each with 2 disjuncts.
diff --git a/examples/gdp/small_lit/nonconvex_HEN.py b/examples/gdp/small_lit/nonconvex_HEN.py
index 99e2c4f15e2..05fad970b84 100644
--- a/examples/gdp/small_lit/nonconvex_HEN.py
+++ b/examples/gdp/small_lit/nonconvex_HEN.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
""" Example from 'Systematic Modeling of Discrete-Continuous Optimization \
Models through Generalized Disjunctive Programming'
Ignacio E. Grossmann and Francisco Trespalacios, 2013
diff --git a/examples/gdp/stickies.py b/examples/gdp/stickies.py
index 75beb911415..73b537ff13d 100644
--- a/examples/gdp/stickies.py
+++ b/examples/gdp/stickies.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 os
from pyomo.common.fileutils import this_file_dir
diff --git a/examples/gdp/strip_packing/stripPacking.py b/examples/gdp/strip_packing/stripPacking.py
index 0e8902c5ee4..39f7208b838 100644
--- a/examples/gdp/strip_packing/stripPacking.py
+++ b/examples/gdp/strip_packing/stripPacking.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
from pyomo.gdp import *
diff --git a/examples/gdp/strip_packing/strip_packing_8rect.py b/examples/gdp/strip_packing/strip_packing_8rect.py
index e1350dbc39e..2bd7c4840ca 100644
--- a/examples/gdp/strip_packing/strip_packing_8rect.py
+++ b/examples/gdp/strip_packing/strip_packing_8rect.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Strip packing example from MINLP.org library.
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
diff --git a/examples/gdp/strip_packing/strip_packing_concrete.py b/examples/gdp/strip_packing/strip_packing_concrete.py
index 1313d75561c..b0907cdea61 100644
--- a/examples/gdp/strip_packing/strip_packing_concrete.py
+++ b/examples/gdp/strip_packing/strip_packing_concrete.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Strip packing example from MINLP.org library.
Strip-packing example from http://minlp.org/library/lib.php?lib=GDP
diff --git a/examples/gdp/two_rxn_lee/two_rxn_model.py b/examples/gdp/two_rxn_lee/two_rxn_model.py
index 2e5f1734130..98e4cc2e878 100644
--- a/examples/gdp/two_rxn_lee/two_rxn_model.py
+++ b/examples/gdp/two_rxn_lee/two_rxn_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
"""Two reactor model from literature. See README.md."""
from pyomo.core import ConcreteModel, Constraint, Objective, Param, Var, maximize
diff --git a/examples/kernel/blocks.py b/examples/kernel/blocks.py
index 7036981dcc8..db1cb6655c2 100644
--- a/examples/kernel/blocks.py
+++ b/examples/kernel/blocks.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/conic.py b/examples/kernel/conic.py
index a2a787794a4..5ee66a00ee9 100644
--- a/examples/kernel/conic.py
+++ b/examples/kernel/conic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/constraints.py b/examples/kernel/constraints.py
index 6495ad12f63..69823a6ebbe 100644
--- a/examples/kernel/constraints.py
+++ b/examples/kernel/constraints.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
v = pmo.variable()
diff --git a/examples/kernel/containers.py b/examples/kernel/containers.py
index 9b525e87af6..9ec749b8c3e 100644
--- a/examples/kernel/containers.py
+++ b/examples/kernel/containers.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/expressions.py b/examples/kernel/expressions.py
index 1756e5d3fd4..faef8d1d4ad 100644
--- a/examples/kernel/expressions.py
+++ b/examples/kernel/expressions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
v = pmo.variable(value=2)
diff --git a/examples/kernel/mosek/geometric1.py b/examples/kernel/mosek/geometric1.py
index b5ec59541c4..8148e707819 100644
--- a/examples/kernel/mosek/geometric1.py
+++ b/examples/kernel/mosek/geometric1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Source: https://docs.mosek.com/9.0/pythonapi/tutorial-gp-shared.html
import pyomo.kernel as pmo
diff --git a/examples/kernel/mosek/geometric2.py b/examples/kernel/mosek/geometric2.py
index 84825c0a39b..3fb62c86312 100644
--- a/examples/kernel/mosek/geometric2.py
+++ b/examples/kernel/mosek/geometric2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Source: https://docs.mosek.com/modeling-cookbook/expo.html
# (first example in Section 5.3.1)
diff --git a/examples/kernel/mosek/maximum_volume_cuboid.py b/examples/kernel/mosek/maximum_volume_cuboid.py
index 92e210cf400..df200cc801c 100644
--- a/examples/kernel/mosek/maximum_volume_cuboid.py
+++ b/examples/kernel/mosek/maximum_volume_cuboid.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 scipy.spatial import ConvexHull
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
diff --git a/examples/kernel/mosek/power1.py b/examples/kernel/mosek/power1.py
index d7a12c1ce54..a6d6ebbe47d 100644
--- a/examples/kernel/mosek/power1.py
+++ b/examples/kernel/mosek/power1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Source: https://docs.mosek.com/9.0/pythonapi/tutorial-pow-shared.html
import pyomo.kernel as pmo
diff --git a/examples/kernel/mosek/semidefinite.py b/examples/kernel/mosek/semidefinite.py
index 44ab7c95a68..6be47d85451 100644
--- a/examples/kernel/mosek/semidefinite.py
+++ b/examples/kernel/mosek/semidefinite.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# Source: https://docs.mosek.com/latest/pythonfusion/tutorial-sdo-shared.html#doc-tutorial-sdo
# This examples illustrates SDP formulations in Pyomo using
diff --git a/examples/kernel/objectives.py b/examples/kernel/objectives.py
index 7d87671ef8d..27a41f4edb5 100644
--- a/examples/kernel/objectives.py
+++ b/examples/kernel/objectives.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
v = pmo.variable(value=2)
diff --git a/examples/kernel/parameters.py b/examples/kernel/parameters.py
index 55b230add6b..e9e412525bb 100644
--- a/examples/kernel/parameters.py
+++ b/examples/kernel/parameters.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/piecewise_functions.py b/examples/kernel/piecewise_functions.py
index 528d4c16791..73a7f680725 100644
--- a/examples/kernel/piecewise_functions.py
+++ b/examples/kernel/piecewise_functions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/piecewise_nd_functions.py b/examples/kernel/piecewise_nd_functions.py
index 847bb5f4a84..7de37fcbfc6 100644
--- a/examples/kernel/piecewise_nd_functions.py
+++ b/examples/kernel/piecewise_nd_functions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 random
import sys
diff --git a/examples/kernel/special_ordered_sets.py b/examples/kernel/special_ordered_sets.py
index 9526a551c12..abacc3d4205 100644
--- a/examples/kernel/special_ordered_sets.py
+++ b/examples/kernel/special_ordered_sets.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
v1 = pmo.variable()
diff --git a/examples/kernel/suffixes.py b/examples/kernel/suffixes.py
index 39caa5b8652..ae95fbbdd09 100644
--- a/examples/kernel/suffixes.py
+++ b/examples/kernel/suffixes.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/kernel/variables.py b/examples/kernel/variables.py
index 7ab571245a1..36865b58183 100644
--- a/examples/kernel/variables.py
+++ b/examples/kernel/variables.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.kernel as pmo
#
diff --git a/examples/mpec/bard1.py b/examples/mpec/bard1.py
index dbe666a7004..59955eefb8e 100644
--- a/examples/mpec/bard1.py
+++ b/examples/mpec/bard1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# bard1.py QQR2-MN-8-5
# Original Pyomo coding by William Hart
# Adapted from AMPL coding by Sven Leyffer
diff --git a/examples/mpec/df.py b/examples/mpec/df.py
index 41984992bdd..7bb25b11e07 100644
--- a/examples/mpec/df.py
+++ b/examples/mpec/df.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 b69d5093477..0aff5de5b20 100644
--- a/examples/mpec/indexed.py
+++ b/examples/mpec/indexed.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 eba04759ae3..f24fd357e62 100644
--- a/examples/mpec/linear1.py
+++ b/examples/mpec/linear1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 debdf709db9..99c240b5c06 100644
--- a/examples/mpec/munson1.py
+++ b/examples/mpec/munson1.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 519db4e6ec2..67f8f318531 100644
--- a/examples/mpec/munson1a.py
+++ b/examples/mpec/munson1a.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ff2b7b51294..46fff90a785 100644
--- a/examples/mpec/munson1b.py
+++ b/examples/mpec/munson1b.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 2592b25c515..dee5b224e75 100644
--- a/examples/mpec/munson1c.py
+++ b/examples/mpec/munson1c.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 0fb08ce73fb..157177f2eb0 100644
--- a/examples/mpec/munson1d.py
+++ b/examples/mpec/munson1d.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 904729780cf..8d574dd1916 100644
--- a/examples/mpec/scholtes4.py
+++ b/examples/mpec/scholtes4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# scholtes4.py LQR2-MN-3-2
# Original Pyomo coding by William Hart
# Adapted from AMPL coding by Sven Leyffer
diff --git a/examples/performance/dae/run_stochpdegas1_automatic.py b/examples/performance/dae/run_stochpdegas1_automatic.py
index 993e22c7c86..fffa1a71ae1 100644
--- a/examples/performance/dae/run_stochpdegas1_automatic.py
+++ b/examples/performance/dae/run_stochpdegas1_automatic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 time
from pyomo.environ import *
diff --git a/examples/performance/dae/stochpdegas1_automatic.py b/examples/performance/dae/stochpdegas1_automatic.py
index 905ec9a5330..ce6132e6cf5 100644
--- a/examples/performance/dae/stochpdegas1_automatic.py
+++ b/examples/performance/dae/stochpdegas1_automatic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# stochastic pde model for natural gas network
# victor m. zavala / 2013
diff --git a/examples/performance/jump/clnlbeam.py b/examples/performance/jump/clnlbeam.py
index d2ceda790ec..410068a6753 100644
--- a/examples/performance/jump/clnlbeam.py
+++ b/examples/performance/jump/clnlbeam.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = AbstractModel()
diff --git a/examples/performance/jump/facility.py b/examples/performance/jump/facility.py
index 6832e8d32ac..fa0c306d6e5 100644
--- a/examples/performance/jump/facility.py
+++ b/examples/performance/jump/facility.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = AbstractModel()
diff --git a/examples/performance/jump/lqcp.py b/examples/performance/jump/lqcp.py
index bb3e66b36f5..b8ef096d7be 100644
--- a/examples/performance/jump/lqcp.py
+++ b/examples/performance/jump/lqcp.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.core import *
model = ConcreteModel()
diff --git a/examples/performance/jump/opf_66200bus.py b/examples/performance/jump/opf_66200bus.py
index f3e1822fbfb..702ff59a61c 100644
--- a/examples/performance/jump/opf_66200bus.py
+++ b/examples/performance/jump/opf_66200bus.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/jump/opf_6620bus.py b/examples/performance/jump/opf_6620bus.py
index 64348ae931e..34b910f43c0 100644
--- a/examples/performance/jump/opf_6620bus.py
+++ b/examples/performance/jump/opf_6620bus.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/jump/opf_662bus.py b/examples/performance/jump/opf_662bus.py
index 6ff97c577e3..8a768ca16e0 100644
--- a/examples/performance/jump/opf_662bus.py
+++ b/examples/performance/jump/opf_662bus.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/bilinear1_100.py b/examples/performance/misc/bilinear1_100.py
index e68fbba6283..d86091c4c76 100644
--- a/examples/performance/misc/bilinear1_100.py
+++ b/examples/performance/misc/bilinear1_100.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/bilinear1_100000.py b/examples/performance/misc/bilinear1_100000.py
index 924d7233d24..0fa2eafedc6 100644
--- a/examples/performance/misc/bilinear1_100000.py
+++ b/examples/performance/misc/bilinear1_100000.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/bilinear2_100.py b/examples/performance/misc/bilinear2_100.py
index 4dd9f9ead57..227bfe000e0 100644
--- a/examples/performance/misc/bilinear2_100.py
+++ b/examples/performance/misc/bilinear2_100.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/bilinear2_100000.py b/examples/performance/misc/bilinear2_100000.py
index 90eeaf82271..9d2a4d6fb7c 100644
--- a/examples/performance/misc/bilinear2_100000.py
+++ b/examples/performance/misc/bilinear2_100000.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/diag1_100.py b/examples/performance/misc/diag1_100.py
index e47a9179974..369d81982f0 100644
--- a/examples/performance/misc/diag1_100.py
+++ b/examples/performance/misc/diag1_100.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/diag1_100000.py b/examples/performance/misc/diag1_100000.py
index a110c0d9d67..536758fda5d 100644
--- a/examples/performance/misc/diag1_100000.py
+++ b/examples/performance/misc/diag1_100000.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/diag2_100.py b/examples/performance/misc/diag2_100.py
index fe820e8590b..6ad47528ff2 100644
--- a/examples/performance/misc/diag2_100.py
+++ b/examples/performance/misc/diag2_100.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/diag2_100000.py b/examples/performance/misc/diag2_100000.py
index 38563de57b9..b95e2dd1d6f 100644
--- a/examples/performance/misc/diag2_100000.py
+++ b/examples/performance/misc/diag2_100000.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
diff --git a/examples/performance/misc/set1.py b/examples/performance/misc/set1.py
index 53227a3ee73..8a8b84fdcc3 100644
--- a/examples/performance/misc/set1.py
+++ b/examples/performance/misc/set1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
model = ConcreteModel()
diff --git a/examples/performance/misc/sparse1.py b/examples/performance/misc/sparse1.py
index 264862760f9..b4883d379bc 100644
--- a/examples/performance/misc/sparse1.py
+++ b/examples/performance/misc/sparse1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 performance test that we cannot easily execute right now
#
diff --git a/examples/performance/pmedian/pmedian1.py b/examples/performance/pmedian/pmedian1.py
index 3d3f6c5407f..a22540efdd5 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/pmedian/pmedian2.py b/examples/performance/pmedian/pmedian2.py
index 434ded6dcbc..ff25a6c15eb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/diet.py b/examples/pyomo/amplbook2/diet.py
index 8cdffefa20f..cc52eacae20 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/dieti.py b/examples/pyomo/amplbook2/dieti.py
index 0934dcf83c6..45d403dd810 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/econ2min.py b/examples/pyomo/amplbook2/econ2min.py
index 0d27df780bb..fb870e02364 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/econmin.py b/examples/pyomo/amplbook2/econmin.py
index 84e41107ff2..d9c95758d4d 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/prod.py b/examples/pyomo/amplbook2/prod.py
index 74e456e013f..236f7254b29 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/steel.py b/examples/pyomo/amplbook2/steel.py
index 43bea775526..8c5c9b2a1d3 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/steel3.py b/examples/pyomo/amplbook2/steel3.py
index e9e494b6a1a..dd3b3ac202f 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/amplbook2/steel4.py b/examples/pyomo/amplbook2/steel4.py
index b6709e478e9..10cb0979d24 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/benders/master.py b/examples/pyomo/benders/master.py
index a457bf28b06..372810dc024 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/benders/subproblem.py b/examples/pyomo/benders/subproblem.py
index 886f71ff321..ae46dad2d41 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sc.py b/examples/pyomo/callbacks/sc.py
index ce32b0a1074..0882815c6b7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sc_callback.py b/examples/pyomo/callbacks/sc_callback.py
index 0dae9e1befc..cacc438b380 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sc_script.py b/examples/pyomo/callbacks/sc_script.py
index 8e4ade21b51..d3044e4d667 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/scalability/run.py b/examples/pyomo/callbacks/scalability/run.py
index 8465e3f5019..cf95076fcc3 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 d3e28a98d3f..8526a540b66 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/columngeneration/cutting_stock.py b/examples/pyomo/columngeneration/cutting_stock.py
index 58df6a5ad16..d331da9608b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 9bc8dd87e9d..3d3c19e94ac 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/knapsack-abstract.py b/examples/pyomo/concrete/knapsack-abstract.py
index bbef95f7810..9766d902722 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/knapsack-concrete.py b/examples/pyomo/concrete/knapsack-concrete.py
index cd115ab40a3..8966d0b8498 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/rosen.py b/examples/pyomo/concrete/rosen.py
index a8e8a175127..ae51ae50ac0 100644
--- a/examples/pyomo/concrete/rosen.py
+++ b/examples/pyomo/concrete/rosen.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# rosen.py
from pyomo.environ import *
diff --git a/examples/pyomo/concrete/sodacan.py b/examples/pyomo/concrete/sodacan.py
index 3c0cfd3aab2..5429b27a9d5 100644
--- a/examples/pyomo/concrete/sodacan.py
+++ b/examples/pyomo/concrete/sodacan.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# sodacan.py
from pyomo.environ import *
from math import pi
diff --git a/examples/pyomo/concrete/sodacan_fig.py b/examples/pyomo/concrete/sodacan_fig.py
index bf9ae476b4c..b263eaf558d 100644
--- a/examples/pyomo/concrete/sodacan_fig.py
+++ b/examples/pyomo/concrete/sodacan_fig.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
diff --git a/examples/pyomo/concrete/sp.py b/examples/pyomo/concrete/sp.py
index edc2d68b170..e82a4bca0a9 100644
--- a/examples/pyomo/concrete/sp.py
+++ b/examples/pyomo/concrete/sp.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# sp.py
from pyomo.environ import *
from sp_data import * # define c, b, h, and d
diff --git a/examples/pyomo/concrete/sp_data.py b/examples/pyomo/concrete/sp_data.py
index 58210126819..4453a10cead 100644
--- a/examples/pyomo/concrete/sp_data.py
+++ b/examples/pyomo/concrete/sp_data.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
c = 1.0
b = 1.5
h = 0.1
diff --git a/examples/pyomo/connectors/network_flow.py b/examples/pyomo/connectors/network_flow.py
index cb75ca7ecf2..d5587fdf4c8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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_proposed.py b/examples/pyomo/connectors/network_flow_proposed.py
index ed603ff6626..f234f2decf4 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/block1.py b/examples/pyomo/core/block1.py
index 96f8114f19c..161fc2ca2f7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/integrality1.py b/examples/pyomo/core/integrality1.py
index db81805555f..0ab3a433dac 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/integrality2.py b/examples/pyomo/core/integrality2.py
index 2d85c9f2455..6461d36f923 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/simple.py b/examples/pyomo/core/simple.py
index d0359c143bf..6976f3d25ad 100644
--- a/examples/pyomo/core/simple.py
+++ b/examples/pyomo/core/simple.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/t1.py b/examples/pyomo/core/t1.py
index 4135049d4be..5d5416985a9 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/t2.py b/examples/pyomo/core/t2.py
index 5d687917fba..4d3f1934cbe 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/core/t5.py b/examples/pyomo/core/t5.py
index 38605751015..6b9d94e0ff1 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/diet-sqlite.py b/examples/pyomo/diet/diet-sqlite.py
index e8963485294..dccd3c338d0 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 1fd61ca268c..217f80b9c25 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/diet2.py b/examples/pyomo/diet/diet2.py
index 526dbcef484..291261b0901 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/draft/api.py b/examples/pyomo/draft/api.py
index 5b506882d9b..d785f41935e 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/draft/bpack.py b/examples/pyomo/draft/bpack.py
index 697ce531013..7b076f7737b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/draft/diet2.py b/examples/pyomo/draft/diet2.py
index 9e4d2c5d9c4..d23fa3cf5db 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/p-median/decorated_pmedian.py b/examples/pyomo/p-median/decorated_pmedian.py
index 90345daf78d..c66971945f3 100644
--- a/examples/pyomo/p-median/decorated_pmedian.py
+++ b/examples/pyomo/p-median/decorated_pmedian.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.environ import *
import random
diff --git a/examples/pyomo/p-median/pmedian.py b/examples/pyomo/p-median/pmedian.py
index 88731f287d8..865aa7cb61f 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/p-median/solver1.py b/examples/pyomo/p-median/solver1.py
index 113bf9fdd29..2652ab13943 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/p-median/solver2.py b/examples/pyomo/p-median/solver2.py
index c62f161fd24..50ec5388811 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/convex.py b/examples/pyomo/piecewise/convex.py
index a3233ae5c3e..fb8095f80e3 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/indexed.py b/examples/pyomo/piecewise/indexed.py
index dea56df3911..cde21ec847e 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/indexed_nonlinear.py b/examples/pyomo/piecewise/indexed_nonlinear.py
index e871508d1be..d72fbc8a899 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/indexed_points.py b/examples/pyomo/piecewise/indexed_points.py
index 15b1c33a7ec..66110bea342 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/nonconvex.py b/examples/pyomo/piecewise/nonconvex.py
index 004748ab2eb..5300278d5b9 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/points.py b/examples/pyomo/piecewise/points.py
index c822ceb5860..91d45684c4f 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/piecewise/step.py b/examples/pyomo/piecewise/step.py
index c3fbb4762ab..95aac74d7f7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/quadratic/example1.py b/examples/pyomo/quadratic/example1.py
index dff911a0f0c..ab77c5a1733 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/quadratic/example2.py b/examples/pyomo/quadratic/example2.py
index 981f2ef0bfb..ce02c6f70c8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/quadratic/example3.py b/examples/pyomo/quadratic/example3.py
index 4d96afe3328..bdba936f694 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/quadratic/example4.py b/examples/pyomo/quadratic/example4.py
index 256fc862a16..ecfc9981162 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_1.py b/examples/pyomo/radertext/Ex2_1.py
index d352325798a..981388d4c72 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_2.py b/examples/pyomo/radertext/Ex2_2.py
index 13c23dd1816..41b56e52669 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_3.py b/examples/pyomo/radertext/Ex2_3.py
index d4dc3109ea1..7dc39afa773 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_5.py b/examples/pyomo/radertext/Ex2_5.py
index da90b473b1f..fee49b46cb0 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_6a.py b/examples/pyomo/radertext/Ex2_6a.py
index dc33a9b64e2..24bb866ec51 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/radertext/Ex2_6b.py b/examples/pyomo/radertext/Ex2_6b.py
index 8049d4ebb05..1be55461b9e 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sos/DepotSiting.py b/examples/pyomo/sos/DepotSiting.py
index 98697681f44..40826e989b7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sos/basic_sos2_example.py b/examples/pyomo/sos/basic_sos2_example.py
index 655169ffe54..3aa0887356c 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/sos/sos2_piecewise.py b/examples/pyomo/sos/sos2_piecewise.py
index 4e79ce2ee62..1d952beb336 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 @@
# ___________________________________________________________________________
"""
-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
"""
diff --git a/examples/pyomo/suffixes/duals_pyomo.py b/examples/pyomo/suffixes/duals_pyomo.py
index 9743add3ddd..6ce88fde429 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/duals_script.py b/examples/pyomo/suffixes/duals_script.py
index a9db615cad3..e8ef9aef1bc 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/gurobi_ampl_basis.py b/examples/pyomo/suffixes/gurobi_ampl_basis.py
index cd8e4e8f129..eab86f8aa47 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/gurobi_ampl_example.py b/examples/pyomo/suffixes/gurobi_ampl_example.py
index d133fa422dc..4f3364c09dc 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/gurobi_ampl_iis.py b/examples/pyomo/suffixes/gurobi_ampl_iis.py
index ccba226db78..da5bad073e7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/ipopt_scaling.py b/examples/pyomo/suffixes/ipopt_scaling.py
index c192a98dd98..7113128c21d 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/ipopt_warmstart.py b/examples/pyomo/suffixes/ipopt_warmstart.py
index 6975bbaaa62..4882c48c8c8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/sipopt_hicks.py b/examples/pyomo/suffixes/sipopt_hicks.py
index dbf4e07b8f7..c7e058d5907 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/suffixes/sipopt_parametric.py b/examples/pyomo/suffixes/sipopt_parametric.py
index 29bba934bd8..0cb1c35f441 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/transform/scaling_ex.py b/examples/pyomo/transform/scaling_ex.py
index a5960393e75..34f937cbb45 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/tutorials/data.out b/examples/pyomo/tutorials/data.out
index d1353f87858..7dce6012e2f 100644
--- a/examples/pyomo/tutorials/data.out
+++ b/examples/pyomo/tutorials/data.out
@@ -1,4 +1,4 @@
-20 Set Declarations
+14 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
@@ -9,30 +9,18 @@
Key : Dimen : Domain : Size : Members
None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
D : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : D_domain : 3 : {('A1', 1), ('A2', 2), ('A3', 3)}
- D_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
+ None : 2 : A*B : 3 : {('A1', 1), ('A2', 2), ('A3', 3)}
E : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain : 6 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A3')}
- E_domain : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain_index_0*A : 27 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A1', 1, 'A3'), ('A1', 2, 'A1'), ('A1', 2, 'A2'), ('A1', 2, 'A3'), ('A1', 3, 'A1'), ('A1', 3, 'A2'), ('A1', 3, 'A3'), ('A2', 1, 'A1'), ('A2', 1, 'A2'), ('A2', 1, 'A3'), ('A2', 2, 'A1'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A2', 3, 'A1'), ('A2', 3, 'A2'), ('A2', 3, 'A3'), ('A3', 1, 'A1'), ('A3', 1, 'A2'), ('A3', 1, 'A3'), ('A3', 2, 'A1'), ('A3', 2, 'A2'), ('A3', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A2'), ('A3', 3, 'A3')}
- E_domain_index_0 : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
+ None : 3 : A*B*A : 6 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A3')}
F : Size=3, Index=A, Ordered=Insertion
Key : Dimen : Domain : Size : Members
A1 : 1 : Any : 3 : {1, 3, 5}
A2 : 1 : Any : 3 : {2, 4, 6}
A3 : 1 : Any : 3 : {3, 5, 7}
- G : Size=0, Index=G_index, Ordered=Insertion
+ G : Size=0, Index=A*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- G_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
H : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'H1', 'H2', 'H3'}
@@ -45,12 +33,6 @@
K : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 3 : {('A1', 'B1'), ('A2', 'B2'), ('A3', 'B3')}
- T_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*I : 12 : {('A1', 'I1'), ('A1', 'I2'), ('A1', 'I3'), ('A1', 'I4'), ('A2', 'I1'), ('A2', 'I2'), ('A2', 'I3'), ('A2', 'I4'), ('A3', 'I1'), ('A3', 'I2'), ('A3', 'I3'), ('A3', 'I4')}
- U_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : I*A : 12 : {('I1', 'A1'), ('I1', 'A2'), ('I1', 'A3'), ('I2', 'A1'), ('I2', 'A2'), ('I2', 'A3'), ('I3', 'A1'), ('I3', 'A2'), ('I3', 'A3'), ('I4', 'A1'), ('I4', 'A2'), ('I4', 'A3')}
x : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
@@ -116,7 +98,7 @@
Key : Value
A1 : 3.3
A3 : 3.5
- T : Size=12, Index=T_index, Domain=Any, Default=None, Mutable=False
+ T : Size=12, Index=A*I, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'I1') : 1.3
('A1', 'I2') : 1.4
@@ -130,7 +112,7 @@
('A3', 'I2') : 3.4
('A3', 'I3') : 3.5
('A3', 'I4') : 3.6
- U : Size=12, Index=U_index, Domain=Any, Default=None, Mutable=False
+ U : Size=12, Index=I*A, Domain=Any, Default=None, Mutable=False
Key : Value
('I1', 'A1') : 1.3
('I1', 'A2') : 2.3
@@ -166,4 +148,4 @@
Key : Value
None : 2
-38 Declarations: A B C D_domain D E_domain_index_0 E_domain E F G_index G H I J K Z ZZ Y X W U_index U T_index T S R Q P PP O z y x M N MM MMM NNN
+32 Declarations: A B C D E F G H I J K Z ZZ Y X W U T S R Q P PP O z y x M N MM MMM NNN
diff --git a/examples/pyomo/tutorials/data.py b/examples/pyomo/tutorials/data.py
index d065c9ff9bc..ea2569af934 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/tutorials/excel.out b/examples/pyomo/tutorials/excel.out
index 5064d4fa511..5e30827f7ae 100644
--- a/examples/pyomo/tutorials/excel.out
+++ b/examples/pyomo/tutorials/excel.out
@@ -1,4 +1,4 @@
-16 Set Declarations
+10 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
@@ -9,27 +9,15 @@
Key : Dimen : Domain : Size : Members
None : 2 : A*B : 9 : {('A1', 1.0), ('A1', 2.0), ('A1', 3.0), ('A2', 1.0), ('A2', 2.0), ('A2', 3.0), ('A3', 1.0), ('A3', 2.0), ('A3', 3.0)}
D : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : D_domain : 3 : {('A1', 1.0), ('A2', 2.0), ('A3', 3.0)}
- D_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1.0), ('A1', 2.0), ('A1', 3.0), ('A2', 1.0), ('A2', 2.0), ('A2', 3.0), ('A3', 1.0), ('A3', 2.0), ('A3', 3.0)}
+ None : 2 : A*B : 3 : {('A1', 1.0), ('A2', 2.0), ('A3', 3.0)}
E : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain : 6 : {('A1', 1.0, 'A1'), ('A1', 1.0, 'A2'), ('A2', 2.0, 'A2'), ('A2', 2.0, 'A3'), ('A3', 3.0, 'A1'), ('A3', 3.0, 'A3')}
- E_domain : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain_index_0*A : 27 : {('A1', 1.0, 'A1'), ('A1', 1.0, 'A2'), ('A1', 1.0, 'A3'), ('A1', 2.0, 'A1'), ('A1', 2.0, 'A2'), ('A1', 2.0, 'A3'), ('A1', 3.0, 'A1'), ('A1', 3.0, 'A2'), ('A1', 3.0, 'A3'), ('A2', 1.0, 'A1'), ('A2', 1.0, 'A2'), ('A2', 1.0, 'A3'), ('A2', 2.0, 'A1'), ('A2', 2.0, 'A2'), ('A2', 2.0, 'A3'), ('A2', 3.0, 'A1'), ('A2', 3.0, 'A2'), ('A2', 3.0, 'A3'), ('A3', 1.0, 'A1'), ('A3', 1.0, 'A2'), ('A3', 1.0, 'A3'), ('A3', 2.0, 'A1'), ('A3', 2.0, 'A2'), ('A3', 2.0, 'A3'), ('A3', 3.0, 'A1'), ('A3', 3.0, 'A2'), ('A3', 3.0, 'A3')}
- E_domain_index_0 : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1.0), ('A1', 2.0), ('A1', 3.0), ('A2', 1.0), ('A2', 2.0), ('A2', 3.0), ('A3', 1.0), ('A3', 2.0), ('A3', 3.0)}
+ None : 3 : A*B : 6 : {('A1', 1.0, 'A1'), ('A1', 1.0, 'A2'), ('A2', 2.0, 'A2'), ('A2', 2.0, 'A3'), ('A3', 3.0, 'A1'), ('A3', 3.0, 'A3')}
F : Size=0, Index=A, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- G : Size=0, Index=G_index, Ordered=Insertion
+ G : Size=0, Index=A*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- G_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1.0), ('A1', 2.0), ('A1', 3.0), ('A2', 1.0), ('A2', 2.0), ('A2', 3.0), ('A3', 1.0), ('A3', 2.0), ('A3', 3.0)}
H : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'H1', 'H2', 'H3'}
@@ -39,12 +27,6 @@
J : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 3 : {('A1', 'B1'), ('A2', 'B2'), ('A3', 'B3')}
- T_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*I : 12 : {('A1', 'I1'), ('A1', 'I2'), ('A1', 'I3'), ('A1', 'I4'), ('A2', 'I1'), ('A2', 'I2'), ('A2', 'I3'), ('A2', 'I4'), ('A3', 'I1'), ('A3', 'I2'), ('A3', 'I3'), ('A3', 'I4')}
- U_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : I*A : 12 : {('I1', 'A1'), ('I1', 'A2'), ('I1', 'A3'), ('I2', 'A1'), ('I2', 'A2'), ('I2', 'A3'), ('I3', 'A1'), ('I3', 'A2'), ('I3', 'A3'), ('I4', 'A1'), ('I4', 'A2'), ('I4', 'A3')}
12 Param Declarations
O : Size=3, Index=J, Domain=Reals, Default=None, Mutable=False
@@ -76,7 +58,7 @@
Key : Value
A1 : 3.3
A3 : 3.5
- T : Size=12, Index=T_index, Domain=Any, Default=None, Mutable=False
+ T : Size=12, Index=A*I, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'I1') : 1.3
('A1', 'I2') : 1.4
@@ -90,7 +72,7 @@
('A3', 'I2') : 3.4
('A3', 'I3') : 3.5
('A3', 'I4') : 3.6
- U : Size=12, Index=U_index, Domain=Any, Default=None, Mutable=False
+ U : Size=12, Index=I*A, Domain=Any, Default=None, Mutable=False
Key : Value
('I1', 'A1') : 1.3
('I1', 'A2') : 2.3
@@ -123,4 +105,4 @@
Key : Value
None : 1.01
-28 Declarations: A B C D_domain D E_domain_index_0 E_domain E F G_index G H I J Z Y X W U_index U T_index T S R Q P PP O
+22 Declarations: A B C D E F G H I J Z Y X W U T S R Q P PP O
diff --git a/examples/pyomo/tutorials/excel.py b/examples/pyomo/tutorials/excel.py
index 127db722c07..f9a5f66826b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/tutorials/param.out b/examples/pyomo/tutorials/param.out
index 57e6a752ea5..ea258f5b493 100644
--- a/examples/pyomo/tutorials/param.out
+++ b/examples/pyomo/tutorials/param.out
@@ -1,22 +1,13 @@
-5 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {2, 4, 6, 8}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
- R_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(2, 1), (2, 2), (2, 3), (4, 1), (4, 2), (4, 3), (6, 1), (6, 2), (6, 3), (8, 1), (8, 2), (8, 3)}
- W_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(2, 1), (2, 2), (2, 3), (4, 1), (4, 2), (4, 3), (6, 1), (6, 2), (6, 3), (8, 1), (8, 2), (8, 3)}
- X_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(2, 1), (2, 2), (2, 3), (4, 1), (4, 2), (4, 3), (6, 1), (6, 2), (6, 3), (8, 1), (8, 2), (8, 3)}
9 Param Declarations
- R : Size=12, Index=R_index, Domain=Any, Default=99.0, Mutable=False
+ R : Size=12, Index=A*B, Domain=Any, Default=99.0, Mutable=False
Key : Value
(2, 1) : 1
(2, 2) : 1
@@ -35,7 +26,7 @@
1 : 1
2 : 2
3 : 9
- W : Size=12, Index=W_index, Domain=Any, Default=None, Mutable=False
+ W : Size=12, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
(2, 1) : 2
(2, 2) : 4
@@ -49,7 +40,7 @@
(8, 1) : 8
(8, 2) : 16
(8, 3) : 24
- X : Size=12, Index=X_index, Domain=Any, Default=None, Mutable=False
+ X : Size=12, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
(2, 1) : 1.3
(2, 2) : 1.4
@@ -73,4 +64,4 @@
Key : Value
None : 1.1
-14 Declarations: A B Z Y X_index X W_index W V U T S R_index R
+11 Declarations: A B Z Y X W V U T S R
diff --git a/examples/pyomo/tutorials/param.py b/examples/pyomo/tutorials/param.py
index ba31975ab4b..5a94bafaa5e 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/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 b01b666c012..3f278a2f9b2 100644
--- a/examples/pyomo/tutorials/set.out
+++ b/examples/pyomo/tutorials/set.out
@@ -1,15 +1,12 @@
-28 Set Declarations
+25 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {2, 3, 4, 5}
- C : Size=0, Index=C_index, Ordered=Insertion
+ C : Size=0, Index=A*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- C_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
D : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 1 : A | B : 5 : {1, 2, 3, 4, 5}
@@ -26,15 +23,9 @@
Key : Dimen : Domain : Size : Members
None : 2 : A*B : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
Hsub : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : Hsub_domain : 3 : {(1, 2), (1, 3), (3, 3)}
- Hsub_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
+ None : 2 : A*B : 3 : {(1, 2), (1, 3), (3, 3)}
I : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : I_domain : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
- I_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
None : 2 : A*B : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
J : Size=1, Index=None, Ordered=Insertion
@@ -53,15 +44,12 @@
Key : Dimen : Domain : Size : Members
None : 1 : Any : 2 : {1, 3}
N : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : N_domain : 0 : {}
- N_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 12 : {(1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5)}
+ None : 2 : A*B : 0 : {}
O : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : -- : Any : 0 : {}
- P : Size=16, Index=P_index, Ordered=Insertion
+ P : Size=16, Index=B*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
(2, 2) : 1 : Any : 4 : {0, 1, 2, 3}
(2, 3) : 1 : Any : 6 : {0, 1, 2, 3, 4, 5}
@@ -79,9 +67,6 @@
(5, 3) : 1 : Any : 15 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
(5, 4) : 1 : Any : 20 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
(5, 5) : 1 : Any : 25 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}
- P_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : B*B : 16 : {(2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5), (4, 2), (4, 3), (4, 4), (4, 5), (5, 2), (5, 3), (5, 4), (5, 5)}
R : Size=3, Index=B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
2 : 1 : Any : 3 : {1, 3, 5}
@@ -95,19 +80,23 @@
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}
- V : Size=4, Index=V_index, Ordered=Insertion
+ V : Size=4, Index=[1:4], Ordered=Insertion
Key : Dimen : Domain : Size : Members
1 : 1 : Any : 5 : {1, 2, 3, 4, 5}
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}
-1 RangeSet Declarations
- V_index : Dimen=1, Size=4, Bounds=(1, 4)
- Key : Finite : Members
- None : True : [1:4]
-
-29 Declarations: A B C_index C D E F G H Hsub_domain Hsub I_domain I J K K_2 L M N_domain N O P_index P R S T U V_index 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 78f2656d739..220bfbc82da 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
@@ -171,6 +171,13 @@ def P_init(model, i, j):
#
model.S = 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 = Set(model.B, within=model.S)
+
#
# Validation of set arrays can also be performed with the _validate_ option.
@@ -180,7 +187,17 @@ def T_validate(model, value):
return value in model.A
-model.T = Set(model.B, validate=M_validate)
+model.T = 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 = Set(model.B, validate=T_indexed_validate)
##
diff --git a/examples/pyomo/tutorials/table.out b/examples/pyomo/tutorials/table.out
index 1eba28afd19..75e2b0aee33 100644
--- a/examples/pyomo/tutorials/table.out
+++ b/examples/pyomo/tutorials/table.out
@@ -1,4 +1,4 @@
-16 Set Declarations
+10 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'A1', 'A2', 'A3'}
@@ -9,27 +9,15 @@
Key : Dimen : Domain : Size : Members
None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
D : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 2 : D_domain : 3 : {('A1', 1), ('A2', 2), ('A3', 3)}
- D_domain : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
+ None : 2 : A*B : 3 : {('A1', 1), ('A2', 2), ('A3', 3)}
E : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain : 6 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A3')}
- E_domain : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 3 : E_domain_index_0*A : 27 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A1', 1, 'A3'), ('A1', 2, 'A1'), ('A1', 2, 'A2'), ('A1', 2, 'A3'), ('A1', 3, 'A1'), ('A1', 3, 'A2'), ('A1', 3, 'A3'), ('A2', 1, 'A1'), ('A2', 1, 'A2'), ('A2', 1, 'A3'), ('A2', 2, 'A1'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A2', 3, 'A1'), ('A2', 3, 'A2'), ('A2', 3, 'A3'), ('A3', 1, 'A1'), ('A3', 1, 'A2'), ('A3', 1, 'A3'), ('A3', 2, 'A1'), ('A3', 2, 'A2'), ('A3', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A2'), ('A3', 3, 'A3')}
- E_domain_index_0 : Size=1, Index=None, Ordered=True
Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
+ None : 3 : A*B*A : 6 : {('A1', 1, 'A1'), ('A1', 1, 'A2'), ('A2', 2, 'A2'), ('A2', 2, 'A3'), ('A3', 3, 'A1'), ('A3', 3, 'A3')}
F : Size=0, Index=A, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- G : Size=0, Index=G_index, Ordered=Insertion
+ G : Size=0, Index=A*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
- G_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {('A1', 1), ('A1', 2), ('A1', 3), ('A2', 1), ('A2', 2), ('A2', 3), ('A3', 1), ('A3', 2), ('A3', 3)}
H : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {'H1', 'H2', 'H3'}
@@ -39,12 +27,6 @@
J : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 3 : {('A1', 'B1'), ('A2', 'B2'), ('A3', 'B3')}
- T_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*I : 12 : {('A1', 'I1'), ('A1', 'I2'), ('A1', 'I3'), ('A1', 'I4'), ('A2', 'I1'), ('A2', 'I2'), ('A2', 'I3'), ('A2', 'I4'), ('A3', 'I1'), ('A3', 'I2'), ('A3', 'I3'), ('A3', 'I4')}
- U_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : I*A : 12 : {('I1', 'A1'), ('I1', 'A2'), ('I1', 'A3'), ('I2', 'A1'), ('I2', 'A2'), ('I2', 'A3'), ('I3', 'A1'), ('I3', 'A2'), ('I3', 'A3'), ('I4', 'A1'), ('I4', 'A2'), ('I4', 'A3')}
12 Param Declarations
O : Size=3, Index=J, Domain=Reals, Default=None, Mutable=False
@@ -76,7 +58,7 @@
Key : Value
A1 : 3.3
A3 : 3.5
- T : Size=12, Index=T_index, Domain=Any, Default=None, Mutable=False
+ T : Size=12, Index=A*I, Domain=Any, Default=None, Mutable=False
Key : Value
('A1', 'I1') : 1.3
('A1', 'I2') : 1.4
@@ -90,7 +72,7 @@
('A3', 'I2') : 3.4
('A3', 'I3') : 3.5
('A3', 'I4') : 3.6
- U : Size=12, Index=U_index, Domain=Any, Default=None, Mutable=False
+ U : Size=12, Index=I*A, Domain=Any, Default=None, Mutable=False
Key : Value
('I1', 'A1') : 1.3
('I1', 'A2') : 2.3
@@ -123,4 +105,4 @@
Key : Value
None : 1.01
-28 Declarations: A B C D_domain D E_domain_index_0 E_domain E F G_index G H I J Z Y X W U_index U T_index T S R Q P PP O
+22 Declarations: A B C D E F G H I J Z Y X W U T S R Q P PP O
diff --git a/examples/pyomo/tutorials/table.py b/examples/pyomo/tutorials/table.py
index 16951352ee1..7d9fceda14a 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/__init__.py b/examples/pyomobook/__init__.py
index e69de29bb2d..a4a626013c4 100644
--- a/examples/pyomobook/__init__.py
+++ b/examples/pyomobook/__init__.py
@@ -0,0 +1,10 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
diff --git a/examples/pyomobook/abstract-ch/AbstHLinScript.py b/examples/pyomobook/abstract-ch/AbstHLinScript.py
index adf700bfd5c..687d3fc4e6b 100644
--- a/examples/pyomobook/abstract-ch/AbstHLinScript.py
+++ b/examples/pyomobook/abstract-ch/AbstHLinScript.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# AbstHLinScript.py - Script for a simple linear version of (H)
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/AbstractH.py b/examples/pyomobook/abstract-ch/AbstractH.py
index da9f0a4931c..7595cbc4933 100644
--- a/examples/pyomobook/abstract-ch/AbstractH.py
+++ b/examples/pyomobook/abstract-ch/AbstractH.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# AbstractH.py - Implement model (H)
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/AbstractHLinear.py b/examples/pyomobook/abstract-ch/AbstractHLinear.py
index 575487d3e95..f312020a9d5 100644
--- a/examples/pyomobook/abstract-ch/AbstractHLinear.py
+++ b/examples/pyomobook/abstract-ch/AbstractHLinear.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# AbstractHLinear.py - A simple linear version of (H)
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/abstract5.py b/examples/pyomobook/abstract-ch/abstract5.py
index 3a06256dff8..8849d2dfe7f 100644
--- a/examples/pyomobook/abstract-ch/abstract5.py
+++ b/examples/pyomobook/abstract-ch/abstract5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract5.py
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/abstract6.py b/examples/pyomobook/abstract-ch/abstract6.py
index d11a4652f64..121b12a51fa 100644
--- a/examples/pyomobook/abstract-ch/abstract6.py
+++ b/examples/pyomobook/abstract-ch/abstract6.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract6.py
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/abstract7.py b/examples/pyomobook/abstract-ch/abstract7.py
index 2fd5d467d3e..3e8131bf42b 100644
--- a/examples/pyomobook/abstract-ch/abstract7.py
+++ b/examples/pyomobook/abstract-ch/abstract7.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# abstract7.py
import pyomo.environ as pyo
import pickle
diff --git a/examples/pyomobook/abstract-ch/buildactions.py b/examples/pyomobook/abstract-ch/buildactions.py
index ad918e2b5f2..6963f285c4c 100644
--- a/examples/pyomobook/abstract-ch/buildactions.py
+++ b/examples/pyomobook/abstract-ch/buildactions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# buildactions.py: Warehouse location problem showing build actions
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/concrete1.py b/examples/pyomobook/abstract-ch/concrete1.py
index 0ad41c79ea3..2c89fbafaad 100644
--- a/examples/pyomobook/abstract-ch/concrete1.py
+++ b/examples/pyomobook/abstract-ch/concrete1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/abstract-ch/concrete2.py b/examples/pyomobook/abstract-ch/concrete2.py
index 6aee434d556..f68c4d6e242 100644
--- a/examples/pyomobook/abstract-ch/concrete2.py
+++ b/examples/pyomobook/abstract-ch/concrete2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/abstract-ch/diet1.py b/examples/pyomobook/abstract-ch/diet1.py
index eb8b071cdb5..fa8bf5f549f 100644
--- a/examples/pyomobook/abstract-ch/diet1.py
+++ b/examples/pyomobook/abstract-ch/diet1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# diet1.py
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/ex.py b/examples/pyomobook/abstract-ch/ex.py
index 88005b7dc0c..83cfd445e01 100644
--- a/examples/pyomobook/abstract-ch/ex.py
+++ b/examples/pyomobook/abstract-ch/ex.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param1.py b/examples/pyomobook/abstract-ch/param1.py
index fc9fac99ff4..3ff8b648661 100644
--- a/examples/pyomobook/abstract-ch/param1.py
+++ b/examples/pyomobook/abstract-ch/param1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param2.py b/examples/pyomobook/abstract-ch/param2.py
index d51cbeffe84..aca8fac0baf 100644
--- a/examples/pyomobook/abstract-ch/param2.py
+++ b/examples/pyomobook/abstract-ch/param2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param2a.py b/examples/pyomobook/abstract-ch/param2a.py
index fe928eb4197..6b6f77f2a8f 100644
--- a/examples/pyomobook/abstract-ch/param2a.py
+++ b/examples/pyomobook/abstract-ch/param2a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param3.py b/examples/pyomobook/abstract-ch/param3.py
index 64efba5c5ad..7545b47dadc 100644
--- a/examples/pyomobook/abstract-ch/param3.py
+++ b/examples/pyomobook/abstract-ch/param3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param3a.py b/examples/pyomobook/abstract-ch/param3a.py
index 857d96f8318..4c52b6432fb 100644
--- a/examples/pyomobook/abstract-ch/param3a.py
+++ b/examples/pyomobook/abstract-ch/param3a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param3b.py b/examples/pyomobook/abstract-ch/param3b.py
index 655694c33dd..786d6b58a16 100644
--- a/examples/pyomobook/abstract-ch/param3b.py
+++ b/examples/pyomobook/abstract-ch/param3b.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param3c.py b/examples/pyomobook/abstract-ch/param3c.py
index 7d58b8b6a39..3f5da5f837e 100644
--- a/examples/pyomobook/abstract-ch/param3c.py
+++ b/examples/pyomobook/abstract-ch/param3c.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param4.py b/examples/pyomobook/abstract-ch/param4.py
index c902b9034ad..c1926ddea74 100644
--- a/examples/pyomobook/abstract-ch/param4.py
+++ b/examples/pyomobook/abstract-ch/param4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param5.py b/examples/pyomobook/abstract-ch/param5.py
index 488e1debda8..7e0020f70b7 100644
--- a/examples/pyomobook/abstract-ch/param5.py
+++ b/examples/pyomobook/abstract-ch/param5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param5a.py b/examples/pyomobook/abstract-ch/param5a.py
index 7e814b917cc..efdd1855f3f 100644
--- a/examples/pyomobook/abstract-ch/param5a.py
+++ b/examples/pyomobook/abstract-ch/param5a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param6.py b/examples/pyomobook/abstract-ch/param6.py
index d9c49a548b2..f6d60f11e4b 100644
--- a/examples/pyomobook/abstract-ch/param6.py
+++ b/examples/pyomobook/abstract-ch/param6.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param6a.py b/examples/pyomobook/abstract-ch/param6a.py
index e9aca384ee6..280e942d01d 100644
--- a/examples/pyomobook/abstract-ch/param6a.py
+++ b/examples/pyomobook/abstract-ch/param6a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param7a.py b/examples/pyomobook/abstract-ch/param7a.py
index 2a18cceabf6..21839bf3b64 100644
--- a/examples/pyomobook/abstract-ch/param7a.py
+++ b/examples/pyomobook/abstract-ch/param7a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param7b.py b/examples/pyomobook/abstract-ch/param7b.py
index acf02ddd62f..a4d79b6dee9 100644
--- a/examples/pyomobook/abstract-ch/param7b.py
+++ b/examples/pyomobook/abstract-ch/param7b.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/param8a.py b/examples/pyomobook/abstract-ch/param8a.py
index e68378961ed..f00ed649c30 100644
--- a/examples/pyomobook/abstract-ch/param8a.py
+++ b/examples/pyomobook/abstract-ch/param8a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/postprocess_fn.py b/examples/pyomobook/abstract-ch/postprocess_fn.py
index f96a5b4dac1..2f2d114c216 100644
--- a/examples/pyomobook/abstract-ch/postprocess_fn.py
+++ b/examples/pyomobook/abstract-ch/postprocess_fn.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 csv
diff --git a/examples/pyomobook/abstract-ch/set1.py b/examples/pyomobook/abstract-ch/set1.py
index ee281bd10bd..5a23fe683e0 100644
--- a/examples/pyomobook/abstract-ch/set1.py
+++ b/examples/pyomobook/abstract-ch/set1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/set2.py b/examples/pyomobook/abstract-ch/set2.py
index 27af609cead..5ecc0914bee 100644
--- a/examples/pyomobook/abstract-ch/set2.py
+++ b/examples/pyomobook/abstract-ch/set2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/set2a.py b/examples/pyomobook/abstract-ch/set2a.py
index bf8f06dd7a8..7252ec0ad69 100644
--- a/examples/pyomobook/abstract-ch/set2a.py
+++ b/examples/pyomobook/abstract-ch/set2a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/set3.py b/examples/pyomobook/abstract-ch/set3.py
index 7661963d19d..f3e3efc33c7 100644
--- a/examples/pyomobook/abstract-ch/set3.py
+++ b/examples/pyomobook/abstract-ch/set3.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/set4.py b/examples/pyomobook/abstract-ch/set4.py
index c9125dad657..0c29798b816 100644
--- a/examples/pyomobook/abstract-ch/set4.py
+++ b/examples/pyomobook/abstract-ch/set4.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/set5.py b/examples/pyomobook/abstract-ch/set5.py
index 9f79870d3ff..781b956404e 100644
--- a/examples/pyomobook/abstract-ch/set5.py
+++ b/examples/pyomobook/abstract-ch/set5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/abstract-ch/wl_abstract.py b/examples/pyomobook/abstract-ch/wl_abstract.py
index f35a5327bfb..61eeed6b506 100644
--- a/examples/pyomobook/abstract-ch/wl_abstract.py
+++ b/examples/pyomobook/abstract-ch/wl_abstract.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_abstract.py: AbstractModel version of warehouse location determination problem
import pyomo.environ as pyo
diff --git a/examples/pyomobook/abstract-ch/wl_abstract_script.py b/examples/pyomobook/abstract-ch/wl_abstract_script.py
index 0b042405714..7f0871350fc 100644
--- a/examples/pyomobook/abstract-ch/wl_abstract_script.py
+++ b/examples/pyomobook/abstract-ch/wl_abstract_script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_abstract_script.py: Scripting using an AbstractModel
import pyomo.environ as pyo
diff --git a/examples/pyomobook/blocks-ch/blocks_gen.py b/examples/pyomobook/blocks-ch/blocks_gen.py
index 109e881cad5..31a4462f7d6 100644
--- a/examples/pyomobook/blocks-ch/blocks_gen.py
+++ b/examples/pyomobook/blocks-ch/blocks_gen.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
time = range(5)
diff --git a/examples/pyomobook/blocks-ch/blocks_gen.txt b/examples/pyomobook/blocks-ch/blocks_gen.txt
index 63d634b3b95..1636f7e4590 100644
--- a/examples/pyomobook/blocks-ch/blocks_gen.txt
+++ b/examples/pyomobook/blocks-ch/blocks_gen.txt
@@ -9,13 +9,8 @@
1 Block Declarations
Generator : Size=2, Index=GEN_UNITS, Active=True
Generator[G_EAST] : Active=True
- 1 Set Declarations
- CostCoef_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
3 Param Declarations
- CostCoef : Size=0, Index=Generator[G_EAST].CostCoef_index, Domain=Any, Default=None, Mutable=False
+ CostCoef : Size=0, Index={1, 2}, Domain=Any, Default=None, Mutable=False
Key : Value
MaxPower : Size=1, Index=None, Domain=NonNegativeReals, Default=None, Mutable=False
Key : Value
@@ -27,11 +22,11 @@
2 Var Declarations
Power : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
- 0 : 0 : 120.0 : 500 : False : False : Reals
- 1 : 0 : 145.0 : 500 : False : False : Reals
- 2 : 0 : 119.0 : 500 : False : False : Reals
- 3 : 0 : 42.0 : 500 : False : False : Reals
- 4 : 0 : 190.0 : 500 : False : False : Reals
+ 0 : 0 : 120.0 : 500.0 : False : False : Reals
+ 1 : 0 : 145.0 : 500.0 : False : False : Reals
+ 2 : 0 : 119.0 : 500.0 : False : False : Reals
+ 3 : 0 : 42.0 : 500.0 : False : False : Reals
+ 4 : 0 : 190.0 : 500.0 : False : False : Reals
UnitOn : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : None : 1 : False : True : Binary
@@ -57,15 +52,10 @@
3 : -50.0 : Generator[G_EAST].Power[3] - Generator[G_EAST].Power[2] : Generator[G_EAST].RampLimit : True
4 : -50.0 : Generator[G_EAST].Power[4] - Generator[G_EAST].Power[3] : Generator[G_EAST].RampLimit : True
- 8 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef_index CostCoef Cost
+ 7 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef Cost
Generator[G_MAIN] : Active=True
- 1 Set Declarations
- CostCoef_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
3 Param Declarations
- CostCoef : Size=0, Index=Generator[G_MAIN].CostCoef_index, Domain=Any, Default=None, Mutable=False
+ CostCoef : Size=0, Index={1, 2}, Domain=Any, Default=None, Mutable=False
Key : Value
MaxPower : Size=1, Index=None, Domain=NonNegativeReals, Default=None, Mutable=False
Key : Value
@@ -77,11 +67,11 @@
2 Var Declarations
Power : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
- 0 : 0 : 120.0 : 500 : False : False : Reals
- 1 : 0 : 145.0 : 500 : False : False : Reals
- 2 : 0 : 119.0 : 500 : False : False : Reals
- 3 : 0 : 42.0 : 500 : False : False : Reals
- 4 : 0 : 190.0 : 500 : False : False : Reals
+ 0 : 0 : 120.0 : 500.0 : False : False : Reals
+ 1 : 0 : 145.0 : 500.0 : False : False : Reals
+ 2 : 0 : 119.0 : 500.0 : False : False : Reals
+ 3 : 0 : 42.0 : 500.0 : False : False : Reals
+ 4 : 0 : 190.0 : 500.0 : False : False : Reals
UnitOn : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : None : 1 : False : True : Binary
@@ -107,7 +97,7 @@
3 : -50.0 : Generator[G_MAIN].Power[3] - Generator[G_MAIN].Power[2] : Generator[G_MAIN].RampLimit : True
4 : -50.0 : Generator[G_MAIN].Power[4] - Generator[G_MAIN].Power[3] : Generator[G_MAIN].RampLimit : True
- 8 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef_index CostCoef Cost
+ 7 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef Cost
3 Declarations: TIME GEN_UNITS Generator
2 Set Declarations
@@ -121,13 +111,8 @@
1 Block Declarations
Generator : Size=2, Index=GEN_UNITS, Active=True
Generator[G_EAST] : Active=True
- 1 Set Declarations
- CostCoef_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
3 Param Declarations
- CostCoef : Size=0, Index=Generator[G_EAST].CostCoef_index, Domain=Any, Default=None, Mutable=False
+ CostCoef : Size=0, Index={1, 2}, Domain=Any, Default=None, Mutable=False
Key : Value
MaxPower : Size=1, Index=None, Domain=NonNegativeReals, Default=None, Mutable=False
Key : Value
@@ -139,11 +124,11 @@
2 Var Declarations
Power : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
- 0 : 0 : 120.0 : 500 : False : False : Reals
- 1 : 0 : 145.0 : 500 : False : False : Reals
- 2 : 0 : 119.0 : 500 : False : False : Reals
- 3 : 0 : 42.0 : 500 : False : False : Reals
- 4 : 0 : 190.0 : 500 : False : False : Reals
+ 0 : 0 : 120.0 : 500.0 : False : False : Reals
+ 1 : 0 : 145.0 : 500.0 : False : False : Reals
+ 2 : 0 : 119.0 : 500.0 : False : False : Reals
+ 3 : 0 : 42.0 : 500.0 : False : False : Reals
+ 4 : 0 : 190.0 : 500.0 : False : False : Reals
UnitOn : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : None : 1 : False : True : Binary
@@ -169,15 +154,10 @@
3 : -50.0 : Generator[G_EAST].Power[3] - Generator[G_EAST].Power[2] : Generator[G_EAST].RampLimit : True
4 : -50.0 : Generator[G_EAST].Power[4] - Generator[G_EAST].Power[3] : Generator[G_EAST].RampLimit : True
- 8 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef_index CostCoef Cost
+ 7 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef Cost
Generator[G_MAIN] : Active=True
- 1 Set Declarations
- CostCoef_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
3 Param Declarations
- CostCoef : Size=0, Index=Generator[G_MAIN].CostCoef_index, Domain=Any, Default=None, Mutable=False
+ CostCoef : Size=0, Index={1, 2}, Domain=Any, Default=None, Mutable=False
Key : Value
MaxPower : Size=1, Index=None, Domain=NonNegativeReals, Default=None, Mutable=False
Key : Value
@@ -189,11 +169,11 @@
2 Var Declarations
Power : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
- 0 : 0 : 120.0 : 500 : False : False : Reals
- 1 : 0 : 145.0 : 500 : False : False : Reals
- 2 : 0 : 119.0 : 500 : False : False : Reals
- 3 : 0 : 42.0 : 500 : False : False : Reals
- 4 : 0 : 190.0 : 500 : False : False : Reals
+ 0 : 0 : 120.0 : 500.0 : False : False : Reals
+ 1 : 0 : 145.0 : 500.0 : False : False : Reals
+ 2 : 0 : 119.0 : 500.0 : False : False : Reals
+ 3 : 0 : 42.0 : 500.0 : False : False : Reals
+ 4 : 0 : 190.0 : 500.0 : False : False : Reals
UnitOn : Size=5, Index=TIME
Key : Lower : Value : Upper : Fixed : Stale : Domain
0 : 0 : None : 1 : False : True : Binary
@@ -219,7 +199,7 @@
3 : -50.0 : Generator[G_MAIN].Power[3] - Generator[G_MAIN].Power[2] : Generator[G_MAIN].RampLimit : True
4 : -50.0 : Generator[G_MAIN].Power[4] - Generator[G_MAIN].Power[3] : Generator[G_MAIN].RampLimit : True
- 8 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef_index CostCoef Cost
+ 7 Declarations: MaxPower RampLimit Power UnitOn limit_ramp CostCoef Cost
3 Declarations: TIME GEN_UNITS Generator
Generator[G_MAIN].Power[4] = 190.0
diff --git a/examples/pyomobook/blocks-ch/blocks_intro.py b/examples/pyomobook/blocks-ch/blocks_intro.py
index ad3ceaa4349..ba2bd9d3a97 100644
--- a/examples/pyomobook/blocks-ch/blocks_intro.py
+++ b/examples/pyomobook/blocks-ch/blocks_intro.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
# @hierarchy:
diff --git a/examples/pyomobook/blocks-ch/blocks_lotsizing.py b/examples/pyomobook/blocks-ch/blocks_lotsizing.py
index fe0717d8c7c..758ad964dc5 100644
--- a/examples/pyomobook/blocks-ch/blocks_lotsizing.py
+++ b/examples/pyomobook/blocks-ch/blocks_lotsizing.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/blocks-ch/lotsizing.py b/examples/pyomobook/blocks-ch/lotsizing.py
index 47ea265246e..ece4d6b541c 100644
--- a/examples/pyomobook/blocks-ch/lotsizing.py
+++ b/examples/pyomobook/blocks-ch/lotsizing.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/blocks-ch/lotsizing_no_time.py b/examples/pyomobook/blocks-ch/lotsizing_no_time.py
index 901467a0cbb..60e8ba44424 100644
--- a/examples/pyomobook/blocks-ch/lotsizing_no_time.py
+++ b/examples/pyomobook/blocks-ch/lotsizing_no_time.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/blocks-ch/lotsizing_uncertain.py b/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
index 6d16de7e3a7..f72161db5c6 100644
--- a/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
+++ b/examples/pyomobook/blocks-ch/lotsizing_uncertain.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/blocks-ch/lotsizing_uncertain.txt b/examples/pyomobook/blocks-ch/lotsizing_uncertain.txt
index db9eee79cc3..08f92ae9262 100644
--- a/examples/pyomobook/blocks-ch/lotsizing_uncertain.txt
+++ b/examples/pyomobook/blocks-ch/lotsizing_uncertain.txt
@@ -1,20 +1,3 @@
-5 Set Declarations
- i_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : T*S : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
- i_neg_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : T*S : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
- i_pos_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : T*S : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
- x_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : T*S : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
- y_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : T*S : 25 : {(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}
-
2 RangeSet Declarations
S : Dimen=1, Size=5, Bounds=(1, 5)
Key : Finite : Members
@@ -24,7 +7,7 @@
None : True : [1:5]
5 Var Declarations
- i : Size=25, Index=i_index
+ i : Size=25, Index=T*S
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : None : None : None : False : True : Reals
(1, 2) : None : None : None : False : True : Reals
@@ -51,7 +34,7 @@
(5, 3) : None : None : None : False : True : Reals
(5, 4) : None : None : None : False : True : Reals
(5, 5) : None : None : None : False : True : Reals
- i_neg : Size=25, Index=i_neg_index
+ i_neg : Size=25, Index=T*S
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : None : None : False : True : NonNegativeReals
(1, 2) : 0 : None : None : False : True : NonNegativeReals
@@ -78,7 +61,7 @@
(5, 3) : 0 : None : None : False : True : NonNegativeReals
(5, 4) : 0 : None : None : False : True : NonNegativeReals
(5, 5) : 0 : None : None : False : True : NonNegativeReals
- i_pos : Size=25, Index=i_pos_index
+ i_pos : Size=25, Index=T*S
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : None : None : False : True : NonNegativeReals
(1, 2) : 0 : None : None : False : True : NonNegativeReals
@@ -105,7 +88,7 @@
(5, 3) : 0 : None : None : False : True : NonNegativeReals
(5, 4) : 0 : None : None : False : True : NonNegativeReals
(5, 5) : 0 : None : None : False : True : NonNegativeReals
- x : Size=25, Index=x_index
+ x : Size=25, Index=T*S
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : None : None : False : True : NonNegativeReals
(1, 2) : 0 : None : None : False : True : NonNegativeReals
@@ -132,7 +115,7 @@
(5, 3) : 0 : None : None : False : True : NonNegativeReals
(5, 4) : 0 : None : None : False : True : NonNegativeReals
(5, 5) : 0 : None : None : False : True : NonNegativeReals
- y : Size=25, Index=y_index
+ y : Size=25, Index=T*S
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : None : 1 : False : True : Binary
(1, 2) : 0 : None : 1 : False : True : Binary
@@ -160,4 +143,4 @@
(5, 4) : 0 : None : 1 : False : True : Binary
(5, 5) : 0 : None : 1 : False : True : Binary
-12 Declarations: T S y_index y x_index x i_index i i_pos_index i_pos i_neg_index i_neg
+7 Declarations: T S y x i i_pos i_neg
diff --git a/examples/pyomobook/dae-ch/dae_tester_model.py b/examples/pyomobook/dae-ch/dae_tester_model.py
index 9e0da9f4a62..396b8a53db1 100644
--- a/examples/pyomobook/dae-ch/dae_tester_model.py
+++ b/examples/pyomobook/dae-ch/dae_tester_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 file for testing miscellaneous code snippets from the DAE chapter
import pyomo.environ as pyo
import pyomo.dae as dae
diff --git a/examples/pyomobook/dae-ch/path_constraint.py b/examples/pyomobook/dae-ch/path_constraint.py
index 5fe41dd132d..5e252d1b99f 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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.txt b/examples/pyomobook/dae-ch/path_constraint.txt
index 421692b33e9..97e56ab8816 100644
--- a/examples/pyomobook/dae-ch/path_constraint.txt
+++ b/examples/pyomobook/dae-ch/path_constraint.txt
@@ -1,8 +1,3 @@
-1 RangeSet Declarations
- t_domain : Dimen=1, Size=Inf, Bounds=(0, 1)
- Key : Finite : Members
- None : False : [0..1]
-
1 Param Declarations
tf : Size=1, Index=None, Domain=Any, Default=None, Mutable=False
Key : Value
@@ -68,4 +63,4 @@
0 : None : None : None : False : True : Reals
1 : None : None : None : False : True : Reals
-15 Declarations: tf t_domain t u x1 x2 x3 dx1 dx2 dx3 x1dotcon x2dotcon x3dotcon obj con
+14 Declarations: tf t u x1 x2 x3 dx1 dx2 dx3 x1dotcon x2dotcon x3dotcon obj con
diff --git a/examples/pyomobook/dae-ch/plot_path_constraint.py b/examples/pyomobook/dae-ch/plot_path_constraint.py
index 4c04bc1b6b6..be86f13cbc0 100644
--- a/examples/pyomobook/dae-ch/plot_path_constraint.py
+++ b/examples/pyomobook/dae-ch/plot_path_constraint.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
# @plot_path:
def plotter(subplot, x, *y, **kwds):
plt.subplot(subplot)
diff --git a/examples/pyomobook/dae-ch/run_path_constraint.py b/examples/pyomobook/dae-ch/run_path_constraint.py
index b819d6a7127..fc115f5649c 100644
--- a/examples/pyomobook/dae-ch/run_path_constraint.py
+++ b/examples/pyomobook/dae-ch/run_path_constraint.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.dae import *
from path_constraint import m
diff --git a/examples/pyomobook/dae-ch/run_path_constraint_tester.py b/examples/pyomobook/dae-ch/run_path_constraint_tester.py
index bbcd83f5da5..22d887e9b11 100644
--- a/examples/pyomobook/dae-ch/run_path_constraint_tester.py
+++ b/examples/pyomobook/dae-ch/run_path_constraint_tester.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.tee import capture_output
from six import StringIO
diff --git a/examples/pyomobook/gdp-ch/gdp_uc.py b/examples/pyomobook/gdp-ch/gdp_uc.py
index 2495ed9bef1..ff3c554c039 100644
--- a/examples/pyomobook/gdp-ch/gdp_uc.py
+++ b/examples/pyomobook/gdp-ch/gdp_uc.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# gdp_uc.py
import pyomo.environ as pyo
from pyomo.gdp import *
@@ -105,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 76597326700..d1cf4b172bd 100644
--- a/examples/pyomobook/gdp-ch/scont.py
+++ b/examples/pyomobook/gdp-ch/scont.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# scont.py
import pyomo.environ as pyo
from pyomo.gdp import Disjunct, Disjunction
diff --git a/examples/pyomobook/gdp-ch/scont2.py b/examples/pyomobook/gdp-ch/scont2.py
index 94e510b358a..2c77fe670d5 100644
--- a/examples/pyomobook/gdp-ch/scont2.py
+++ b/examples/pyomobook/gdp-ch/scont2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
import scont
diff --git a/examples/pyomobook/gdp-ch/scont_script.py b/examples/pyomobook/gdp-ch/scont_script.py
index 22c9b88ad0c..fe0702dc262 100644
--- a/examples/pyomobook/gdp-ch/scont_script.py
+++ b/examples/pyomobook/gdp-ch/scont_script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
import scont
diff --git a/examples/pyomobook/gdp-ch/verify_scont.py b/examples/pyomobook/gdp-ch/verify_scont.py
index db44024fe66..222453560b6 100644
--- a/examples/pyomobook/gdp-ch/verify_scont.py
+++ b/examples/pyomobook/gdp-ch/verify_scont.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 os
diff --git a/examples/pyomobook/intro-ch/abstract5.py b/examples/pyomobook/intro-ch/abstract5.py
index 2184ed7b3aa..2caad5f9351 100644
--- a/examples/pyomobook/intro-ch/abstract5.py
+++ b/examples/pyomobook/intro-ch/abstract5.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/intro-ch/coloring_concrete.py b/examples/pyomobook/intro-ch/coloring_concrete.py
index 107a31668c4..9931b5d80de 100644
--- a/examples/pyomobook/intro-ch/coloring_concrete.py
+++ b/examples/pyomobook/intro-ch/coloring_concrete.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
#
# Graph coloring example adapted from
#
diff --git a/examples/pyomobook/intro-ch/concrete1.py b/examples/pyomobook/intro-ch/concrete1.py
index a39ca1d41cd..169fbeb281c 100644
--- a/examples/pyomobook/intro-ch/concrete1.py
+++ b/examples/pyomobook/intro-ch/concrete1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/intro-ch/concrete1_generic.py b/examples/pyomobook/intro-ch/concrete1_generic.py
index de648470469..9a2d26bded8 100644
--- a/examples/pyomobook/intro-ch/concrete1_generic.py
+++ b/examples/pyomobook/intro-ch/concrete1_generic.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
import mydata
diff --git a/examples/pyomobook/intro-ch/mydata.py b/examples/pyomobook/intro-ch/mydata.py
index 83aa26bacd9..209546ebeaf 100644
--- a/examples/pyomobook/intro-ch/mydata.py
+++ b/examples/pyomobook/intro-ch/mydata.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
N = [1, 2]
M = [1, 2]
c = {1: 1, 2: 2}
diff --git a/examples/pyomobook/mpec-ch/ex1a.py b/examples/pyomobook/mpec-ch/ex1a.py
index 30cd2842556..e6f1c33fbbc 100644
--- a/examples/pyomobook/mpec-ch/ex1a.py
+++ b/examples/pyomobook/mpec-ch/ex1a.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex1a.py
import pyomo.environ as pyo
from pyomo.mpec import Complementarity, complements
diff --git a/examples/pyomobook/mpec-ch/ex1b.py b/examples/pyomobook/mpec-ch/ex1b.py
index 9592c81c4f6..2b0ac2ce1b7 100644
--- a/examples/pyomobook/mpec-ch/ex1b.py
+++ b/examples/pyomobook/mpec-ch/ex1b.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex1b.py
import pyomo.environ as pyo
from pyomo.mpec import ComplementarityList, complements
diff --git a/examples/pyomobook/mpec-ch/ex1c.py b/examples/pyomobook/mpec-ch/ex1c.py
index aad9c9b0d47..eaf0292b50d 100644
--- a/examples/pyomobook/mpec-ch/ex1c.py
+++ b/examples/pyomobook/mpec-ch/ex1c.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex1c.py
import pyomo.environ as pyo
from pyomo.mpec import ComplementarityList, complements
diff --git a/examples/pyomobook/mpec-ch/ex1d.py b/examples/pyomobook/mpec-ch/ex1d.py
index fa5247ff831..4c0e0d9fd0f 100644
--- a/examples/pyomobook/mpec-ch/ex1d.py
+++ b/examples/pyomobook/mpec-ch/ex1d.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex1d.py
import pyomo.environ as pyo
from pyomo.mpec import Complementarity, complements
diff --git a/examples/pyomobook/mpec-ch/ex1e.py b/examples/pyomobook/mpec-ch/ex1e.py
index bf714411396..c552847fcfb 100644
--- a/examples/pyomobook/mpec-ch/ex1e.py
+++ b/examples/pyomobook/mpec-ch/ex1e.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex1e.py
import pyomo.environ as pyo
from pyomo.mpec import ComplementarityList, complements
diff --git a/examples/pyomobook/mpec-ch/ex2.py b/examples/pyomobook/mpec-ch/ex2.py
index c192ccc7a34..6981af33376 100644
--- a/examples/pyomobook/mpec-ch/ex2.py
+++ b/examples/pyomobook/mpec-ch/ex2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ex2.py
import pyomo.environ as pyo
from pyomo.mpec import *
diff --git a/examples/pyomobook/mpec-ch/munson1.py b/examples/pyomobook/mpec-ch/munson1.py
index c7d171eb416..e85d9359768 100644
--- a/examples/pyomobook/mpec-ch/munson1.py
+++ b/examples/pyomobook/mpec-ch/munson1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# munson1.py
import pyomo.environ as pyo
from pyomo.mpec import Complementarity, complements
diff --git a/examples/pyomobook/mpec-ch/ralph1.py b/examples/pyomobook/mpec-ch/ralph1.py
index 1d44a303b84..b6a8b45e8df 100644
--- a/examples/pyomobook/mpec-ch/ralph1.py
+++ b/examples/pyomobook/mpec-ch/ralph1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ralph1.py
import pyomo.environ as pyo
from pyomo.mpec import Complementarity, complements
diff --git a/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py b/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
index c076a7f4687..dc3ca179a58 100644
--- a/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
+++ b/examples/pyomobook/nonlinear-ch/deer/DeerProblem.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# DeerProblem.py
import pyomo.environ as pyo
diff --git a/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py b/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
index 4eb859dc349..5675d7a715b 100644
--- a/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
+++ b/examples/pyomobook/nonlinear-ch/disease_est/disease_estimation.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# disease_estimation.py
import pyomo.environ as pyo
diff --git a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
index c435cafc3d5..a50bf3321d6 100644
--- a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
+++ b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init1.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# multimodal_init1.py
import pyomo.environ as pyo
from math import pi
diff --git a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
index aa0dbae1e66..6a209334521 100644
--- a/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
+++ b/examples/pyomobook/nonlinear-ch/multimodal/multimodal_init2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 math import pi
diff --git a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
index 90822c153a5..1cfe3b7193f 100644
--- a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
+++ b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesign.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
import pyomo.environ as pyo
diff --git a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
index a242c85fbc2..2bd9574b427 100644
--- a/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
+++ b/examples/pyomobook/nonlinear-ch/react_design/ReactorDesignTable.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 ReactorDesign import create_model
diff --git a/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py b/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
index e1633e2df69..bec1d04c12c 100644
--- a/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
+++ b/examples/pyomobook/nonlinear-ch/rosen/rosenbrock.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# rosenbrock.py
# A Pyomo model for the Rosenbrock problem
import pyomo.environ as pyo
diff --git a/examples/pyomobook/optimization-ch/ConcHLinScript.py b/examples/pyomobook/optimization-ch/ConcHLinScript.py
index 8481a83afbf..b94903585dc 100644
--- a/examples/pyomobook/optimization-ch/ConcHLinScript.py
+++ b/examples/pyomobook/optimization-ch/ConcHLinScript.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ConcHLinScript.py - Linear (H) as a script
import pyomo.environ as pyo
diff --git a/examples/pyomobook/optimization-ch/ConcHLinScript.txt b/examples/pyomobook/optimization-ch/ConcHLinScript.txt
index c04591c94dc..0d34868ed99 100644
--- a/examples/pyomobook/optimization-ch/ConcHLinScript.txt
+++ b/examples/pyomobook/optimization-ch/ConcHLinScript.txt
@@ -1,7 +1,7 @@
Model 'Linear (H)'
Variables:
- x : Size=2, Index=x_index
+ x : Size=2, Index={I_C_Scoops, Peanuts}
Key : Lower : Value : Upper : Fixed : Stale : Domain
I_C_Scoops : 0 : 0.0 : 100 : False : False : Reals
Peanuts : 0 : 40.6 : 40.6 : False : False : Reals
@@ -9,7 +9,7 @@ Model 'Linear (H)'
Objectives:
z : Size=1, Index=None, Active=True
Key : Active : Value
- None : True : 3.83388751715
+ None : True : 3.8338875171467763
Constraints:
budgetconstr : Size=1
diff --git a/examples/pyomobook/optimization-ch/ConcreteH.py b/examples/pyomobook/optimization-ch/ConcreteH.py
index 1bf2a9446c1..d7474291d0d 100644
--- a/examples/pyomobook/optimization-ch/ConcreteH.py
+++ b/examples/pyomobook/optimization-ch/ConcreteH.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ConcreteH.py - Implement a particular instance of (H)
# @fct:
diff --git a/examples/pyomobook/optimization-ch/ConcreteH.txt b/examples/pyomobook/optimization-ch/ConcreteH.txt
index 5e669ff71e0..04bbbdab857 100644
--- a/examples/pyomobook/optimization-ch/ConcreteH.txt
+++ b/examples/pyomobook/optimization-ch/ConcreteH.txt
@@ -1,10 +1,5 @@
-1 Set Declarations
- x_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {'I_C_Scoops', 'Peanuts'}
-
1 Var Declarations
- x : Size=2, Index=x_index
+ x : Size=2, Index={I_C_Scoops, Peanuts}
Key : Lower : Value : Upper : Fixed : Stale : Domain
I_C_Scoops : 0 : None : 100 : False : True : Reals
Peanuts : 0 : None : 40.6 : False : True : Reals
@@ -19,4 +14,4 @@
Key : Lower : Body : Upper : Active
None : -Inf : 3.14*x[I_C_Scoops] + 0.2718*x[Peanuts] : 12.0 : True
-4 Declarations: x_index x z budgetconstr
+3 Declarations: x z budgetconstr
diff --git a/examples/pyomobook/optimization-ch/ConcreteHLinear.py b/examples/pyomobook/optimization-ch/ConcreteHLinear.py
index 0b42d5e2187..772c18cb6d5 100644
--- a/examples/pyomobook/optimization-ch/ConcreteHLinear.py
+++ b/examples/pyomobook/optimization-ch/ConcreteHLinear.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# ConcreteHLinear.py - Linear (H)
import pyomo.environ as pyo
diff --git a/examples/pyomobook/optimization-ch/ConcreteHLinear.txt b/examples/pyomobook/optimization-ch/ConcreteHLinear.txt
index 2e778c2bd1b..7f19aca87ec 100644
--- a/examples/pyomobook/optimization-ch/ConcreteHLinear.txt
+++ b/examples/pyomobook/optimization-ch/ConcreteHLinear.txt
@@ -1,10 +1,5 @@
-1 Set Declarations
- x_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {'I_C_Scoops', 'Peanuts'}
-
1 Var Declarations
- x : Size=2, Index=x_index
+ x : Size=2, Index={I_C_Scoops, Peanuts}
Key : Lower : Value : Upper : Fixed : Stale : Domain
I_C_Scoops : 0 : None : 100 : False : True : Reals
Peanuts : 0 : None : 40.6 : False : True : Reals
@@ -19,4 +14,4 @@
Key : Lower : Body : Upper : Active
None : -Inf : 3.14*x[I_C_Scoops] + 0.2718*x[Peanuts] : 12.0 : True
-4 Declarations: x_index x z budgetconstr
+3 Declarations: x z budgetconstr
diff --git a/examples/pyomobook/optimization-ch/IC_model_dict.py b/examples/pyomobook/optimization-ch/IC_model_dict.py
index 4c54ef83701..b7e359777c7 100644
--- a/examples/pyomobook/optimization-ch/IC_model_dict.py
+++ b/examples/pyomobook/optimization-ch/IC_model_dict.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# IC_model_dict.py - Implement a particular instance of (H)
# @fct:
diff --git a/examples/pyomobook/overview-ch/var_obj_con_snippet.py b/examples/pyomobook/overview-ch/var_obj_con_snippet.py
index 49bb7c1276b..22524b5815a 100644
--- a/examples/pyomobook/overview-ch/var_obj_con_snippet.py
+++ b/examples/pyomobook/overview-ch/var_obj_con_snippet.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/overview-ch/wl_abstract.py b/examples/pyomobook/overview-ch/wl_abstract.py
index f35a5327bfb..61eeed6b506 100644
--- a/examples/pyomobook/overview-ch/wl_abstract.py
+++ b/examples/pyomobook/overview-ch/wl_abstract.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_abstract.py: AbstractModel version of warehouse location determination problem
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_abstract_script.py b/examples/pyomobook/overview-ch/wl_abstract_script.py
index 0b042405714..7f0871350fc 100644
--- a/examples/pyomobook/overview-ch/wl_abstract_script.py
+++ b/examples/pyomobook/overview-ch/wl_abstract_script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_abstract_script.py: Scripting using an AbstractModel
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_concrete.py b/examples/pyomobook/overview-ch/wl_concrete.py
index 29316304f0a..c1bf70b07f1 100644
--- a/examples/pyomobook/overview-ch/wl_concrete.py
+++ b/examples/pyomobook/overview-ch/wl_concrete.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_concrete.py
# ConcreteModel version of warehouse location problem
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_concrete_script.py b/examples/pyomobook/overview-ch/wl_concrete_script.py
index 278937f5aed..b369521994c 100644
--- a/examples/pyomobook/overview-ch/wl_concrete_script.py
+++ b/examples/pyomobook/overview-ch/wl_concrete_script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_concrete_script.py
# Solve an instance of the warehouse location problem
diff --git a/examples/pyomobook/overview-ch/wl_concrete_script.txt b/examples/pyomobook/overview-ch/wl_concrete_script.txt
index dae31e1a035..165289552d3 100644
--- a/examples/pyomobook/overview-ch/wl_concrete_script.txt
+++ b/examples/pyomobook/overview-ch/wl_concrete_script.txt
@@ -1,4 +1,4 @@
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
diff --git a/examples/pyomobook/overview-ch/wl_excel.py b/examples/pyomobook/overview-ch/wl_excel.py
index 1c4ad997225..180e36422fe 100644
--- a/examples/pyomobook/overview-ch/wl_excel.py
+++ b/examples/pyomobook/overview-ch/wl_excel.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_excel.py: Loading Excel data using Pandas
import pandas
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_excel.txt b/examples/pyomobook/overview-ch/wl_excel.txt
index dae31e1a035..165289552d3 100644
--- a/examples/pyomobook/overview-ch/wl_excel.txt
+++ b/examples/pyomobook/overview-ch/wl_excel.txt
@@ -1,4 +1,4 @@
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
diff --git a/examples/pyomobook/overview-ch/wl_list.py b/examples/pyomobook/overview-ch/wl_list.py
index 64db76be548..37cba5a9595 100644
--- a/examples/pyomobook/overview-ch/wl_list.py
+++ b/examples/pyomobook/overview-ch/wl_list.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_list.py: Warehouse location problem using constraint lists
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_list.txt b/examples/pyomobook/overview-ch/wl_list.txt
index 2054efe153d..c0d44f1a0c9 100644
--- a/examples/pyomobook/overview-ch/wl_list.txt
+++ b/examples/pyomobook/overview-ch/wl_list.txt
@@ -1,25 +1,5 @@
-6 Set Declarations
- demand_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {1, 2, 3, 4}
- warehouse_active_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 12 : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
- x_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : x_index_0*x_index_1 : 12 : {('Harlingen', 'NYC'), ('Harlingen', 'LA'), ('Harlingen', 'Chicago'), ('Harlingen', 'Houston'), ('Memphis', 'NYC'), ('Memphis', 'LA'), ('Memphis', 'Chicago'), ('Memphis', 'Houston'), ('Ashland', 'NYC'), ('Ashland', 'LA'), ('Ashland', 'Chicago'), ('Ashland', 'Houston')}
- x_index_0 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'Harlingen', 'Memphis', 'Ashland'}
- x_index_1 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {'NYC', 'LA', 'Chicago', 'Houston'}
- y_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'Harlingen', 'Memphis', 'Ashland'}
-
2 Var Declarations
- x : Size=12, Index=x_index
+ x : Size=12, Index={Harlingen, Memphis, Ashland}*{NYC, LA, Chicago, Houston}
Key : Lower : Value : Upper : Fixed : Stale : Domain
('Ashland', 'Chicago') : 0 : None : 1 : False : True : Reals
('Ashland', 'Houston') : 0 : None : 1 : False : True : Reals
@@ -33,7 +13,7 @@
('Memphis', 'Houston') : 0 : None : 1 : False : True : Reals
('Memphis', 'LA') : 0 : None : 1 : False : True : Reals
('Memphis', 'NYC') : 0 : None : 1 : False : True : Reals
- y : Size=3, Index=y_index
+ y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : None : 1 : False : True : Binary
Harlingen : 0 : None : 1 : False : True : Binary
@@ -45,7 +25,7 @@
None : True : minimize : 1956*x[Harlingen,NYC] + 1606*x[Harlingen,LA] + 1410*x[Harlingen,Chicago] + 330*x[Harlingen,Houston] + 1096*x[Memphis,NYC] + 1792*x[Memphis,LA] + 531*x[Memphis,Chicago] + 567*x[Memphis,Houston] + 485*x[Ashland,NYC] + 2322*x[Ashland,LA] + 324*x[Ashland,Chicago] + 1236*x[Ashland,Houston]
3 Constraint Declarations
- demand : Size=4, Index=demand_index, Active=True
+ demand : Size=4, Index={1, 2, 3, 4}, Active=True
Key : Lower : Body : Upper : Active
1 : 1.0 : x[Harlingen,NYC] + x[Memphis,NYC] + x[Ashland,NYC] : 1.0 : True
2 : 1.0 : x[Harlingen,LA] + x[Memphis,LA] + x[Ashland,LA] : 1.0 : True
@@ -54,7 +34,7 @@
num_warehouses : Size=1, Index=None, Active=True
Key : Lower : Body : Upper : Active
None : -Inf : y[Harlingen] + y[Memphis] + y[Ashland] : 2.0 : True
- warehouse_active : Size=12, Index=warehouse_active_index, Active=True
+ warehouse_active : Size=12, Index={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, Active=True
Key : Lower : Body : Upper : Active
1 : -Inf : x[Harlingen,NYC] - y[Harlingen] : 0.0 : True
2 : -Inf : x[Harlingen,LA] - y[Harlingen] : 0.0 : True
@@ -69,4 +49,4 @@
11 : -Inf : x[Ashland,Chicago] - y[Ashland] : 0.0 : True
12 : -Inf : x[Ashland,Houston] - y[Ashland] : 0.0 : True
-12 Declarations: x_index_0 x_index_1 x_index x y_index y obj demand_index demand warehouse_active_index warehouse_active num_warehouses
+6 Declarations: x y obj demand warehouse_active num_warehouses
diff --git a/examples/pyomobook/overview-ch/wl_mutable.py b/examples/pyomobook/overview-ch/wl_mutable.py
index e5c4f5e9dbb..8e129dd3c49 100644
--- a/examples/pyomobook/overview-ch/wl_mutable.py
+++ b/examples/pyomobook/overview-ch/wl_mutable.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_mutable.py: warehouse location problem with mutable param
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_mutable_excel.py b/examples/pyomobook/overview-ch/wl_mutable_excel.py
index 0906fbb25b3..935fa4963e5 100644
--- a/examples/pyomobook/overview-ch/wl_mutable_excel.py
+++ b/examples/pyomobook/overview-ch/wl_mutable_excel.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_mutable_excel.py: solve problem with different values for P
import pandas
import pyomo.environ as pyo
diff --git a/examples/pyomobook/overview-ch/wl_scalar.py b/examples/pyomobook/overview-ch/wl_scalar.py
index ac10fbe8265..6f538baedb8 100644
--- a/examples/pyomobook/overview-ch/wl_scalar.py
+++ b/examples/pyomobook/overview-ch/wl_scalar.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl_scalar.py: snippets that show the warehouse location problem implemented as scalar quantities
import pyomo.environ as pyo
diff --git a/examples/pyomobook/performance-ch/SparseSets.py b/examples/pyomobook/performance-ch/SparseSets.py
index 90d097b53aa..519808306de 100644
--- a/examples/pyomobook/performance-ch/SparseSets.py
+++ b/examples/pyomobook/performance-ch/SparseSets.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/performance-ch/lin_expr.py b/examples/pyomobook/performance-ch/lin_expr.py
index 75f4e70ec2a..af50ddd6228 100644
--- a/examples/pyomobook/performance-ch/lin_expr.py
+++ b/examples/pyomobook/performance-ch/lin_expr.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.timing import TicTocTimer
from pyomo.core.expr.numeric_expr import LinearExpression
diff --git a/examples/pyomobook/performance-ch/persistent.py b/examples/pyomobook/performance-ch/persistent.py
index 98207909cb6..67f8c656cfe 100644
--- a/examples/pyomobook/performance-ch/persistent.py
+++ b/examples/pyomobook/performance-ch/persistent.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# @model:
import pyomo.environ as pyo
diff --git a/examples/pyomobook/performance-ch/wl.py b/examples/pyomobook/performance-ch/wl.py
index 34c8a73f36e..000f81272a1 100644
--- a/examples/pyomobook/performance-ch/wl.py
+++ b/examples/pyomobook/performance-ch/wl.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# wl.py # define a script to demonstrate performance profiling and improvements
# @imports:
import pyomo.environ as pyo # import pyomo environment
diff --git a/examples/pyomobook/performance-ch/wl.txt b/examples/pyomobook/performance-ch/wl.txt
index f7d2e0ada19..b762acf55cf 100644
--- a/examples/pyomobook/performance-ch/wl.txt
+++ b/examples/pyomobook/performance-ch/wl.txt
@@ -3,94 +3,102 @@ Building model
0 seconds to construct Block ConcreteModel; 1 index total
0 seconds to construct Set Any; 1 index total
0 seconds to construct Param P; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0 seconds to construct Set SetProduct_OrderedSet; 1 index total
0.02 seconds to construct Var x; 40000 indices total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Var y; 200 indices total
- 0.13 seconds to construct Objective obj; 1 index total
+ 0.14 seconds to construct Objective obj; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0.13 seconds to construct Constraint demand; 200 indices total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0.48 seconds to construct Constraint warehouse_active; 40000 indices total
+ 0.50 seconds to construct Constraint warehouse_active; 40000 indices total
0 seconds to construct Constraint num_warehouses; 1 index total
Building model with LinearExpression
------------------------------------
0 seconds to construct Block ConcreteModel; 1 index total
0 seconds to construct Set Any; 1 index total
0 seconds to construct Param P; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0 seconds to construct Set SetProduct_OrderedSet; 1 index total
0.02 seconds to construct Var x; 40000 indices total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Var y; 200 indices total
- 0.06 seconds to construct Objective obj; 1 index total
+ 0.20 seconds to construct Objective obj; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
- 0.18 seconds to construct Constraint demand; 200 indices total
+ 0.05 seconds to construct Constraint demand; 200 indices total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
+ 0 seconds to construct SetOf OrderedSetOf
0 seconds to construct Set OrderedScalarSet; 1 index total
0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0 seconds to construct Set SetProduct_OrderedSet; 1 index total
- 0.33 seconds to construct Constraint warehouse_active; 40000 indices total
+ 0.34 seconds to construct Constraint warehouse_active; 40000 indices total
0 seconds to construct Constraint num_warehouses; 1 index total
[ 0.00] start
-[+ 0.79] Built model
-[+ 2.56] Wrote LP file and solved
-[+ 10.96] Finished parameter sweep
- 7372057 function calls (7368345 primitive calls) in 13.627 seconds
+[+ 1.00] Built model
+[+ 2.28] Wrote LP file and solved
+[+ 9.06] Finished parameter sweep
+ 7294708 function calls (7291012 primitive calls) in 10.989 seconds
Ordered by: cumulative time
List reduced from 673 to 15 due to restriction <15>
ncalls tottime percall cumtime percall filename:lineno(function)
- 1 0.001 0.001 13.627 13.627 /home/jdsiiro/Research/pyomo/examples/pyomobook/performance-ch/wl.py:132(solve_parametric)
- 30 0.002 0.000 13.551 0.452 /home/jdsiiro/Research/pyomo/pyomo/opt/base/solvers.py:530(solve)
- 30 0.001 0.000 10.383 0.346 /home/jdsiiro/Research/pyomo/pyomo/opt/solver/shellcmd.py:247(_apply_solver)
- 30 0.002 0.000 10.381 0.346 /home/jdsiiro/Research/pyomo/pyomo/opt/solver/shellcmd.py:310(_execute_command)
- 30 0.001 0.000 10.360 0.345 /projects/sems/install/rhel7-x86_64/pyomo/compiler/python/3.11.6/lib/python3.11/subprocess.py:506(run)
- 30 0.000 0.000 10.288 0.343 /projects/sems/install/rhel7-x86_64/pyomo/compiler/python/3.11.6/lib/python3.11/subprocess.py:1165(communicate)
- 60 0.000 0.000 10.287 0.171 /projects/sems/install/rhel7-x86_64/pyomo/compiler/python/3.11.6/lib/python3.11/subprocess.py:1259(wait)
- 60 0.001 0.000 10.287 0.171 /projects/sems/install/rhel7-x86_64/pyomo/compiler/python/3.11.6/lib/python3.11/subprocess.py:2014(_wait)
- 30 0.000 0.000 10.286 0.343 /projects/sems/install/rhel7-x86_64/pyomo/compiler/python/3.11.6/lib/python3.11/subprocess.py:2001(_try_wait)
- 30 10.286 0.343 10.286 0.343 {built-in method posix.waitpid}
- 30 0.000 0.000 2.123 0.071 /home/jdsiiro/Research/pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:214(_presolve)
- 30 0.000 0.000 2.122 0.071 /home/jdsiiro/Research/pyomo/pyomo/opt/solver/shellcmd.py:215(_presolve)
- 30 0.000 0.000 2.114 0.070 /home/jdsiiro/Research/pyomo/pyomo/opt/base/solvers.py:687(_presolve)
- 30 0.000 0.000 2.114 0.070 /home/jdsiiro/Research/pyomo/pyomo/opt/base/solvers.py:756(_convert_problem)
- 30 0.001 0.000 2.114 0.070 /home/jdsiiro/Research/pyomo/pyomo/opt/base/convert.py:27(convert_problem)
+ 1 0.001 0.001 10.989 10.989 pyomo/examples/pyomobook/performance-ch/wl.py:132(solve_parametric)
+ 30 0.002 0.000 10.913 0.364 pyomo/pyomo/opt/base/solvers.py:530(solve)
+ 30 0.001 0.000 7.816 0.261 pyomo/pyomo/opt/solver/shellcmd.py:247(_apply_solver)
+ 30 0.002 0.000 7.814 0.260 pyomo/pyomo/opt/solver/shellcmd.py:310(_execute_command)
+ 30 0.001 0.000 7.793 0.260 /lib/python3.11/subprocess.py:506(run)
+ 30 0.000 0.000 7.609 0.254 /lib/python3.11/subprocess.py:1165(communicate)
+ 60 0.000 0.000 7.608 0.127 /lib/python3.11/subprocess.py:1259(wait)
+ 60 0.000 0.000 7.608 0.127 /lib/python3.11/subprocess.py:2014(_wait)
+ 30 0.000 0.000 7.608 0.254 /lib/python3.11/subprocess.py:2001(_try_wait)
+ 30 7.607 0.254 7.607 0.254 {built-in method posix.waitpid}
+ 30 0.000 0.000 2.166 0.072 pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:214(_presolve)
+ 30 0.000 0.000 2.166 0.072 pyomo/pyomo/opt/solver/shellcmd.py:215(_presolve)
+ 30 0.000 0.000 2.156 0.072 pyomo/pyomo/opt/base/solvers.py:687(_presolve)
+ 30 0.000 0.000 2.156 0.072 pyomo/pyomo/opt/base/solvers.py:754(_convert_problem)
+ 30 0.001 0.000 2.156 0.072 pyomo/pyomo/opt/base/convert.py:27(convert_problem)
- 7372057 function calls (7368345 primitive calls) in 13.627 seconds
+ 7294708 function calls (7291012 primitive calls) in 10.989 seconds
Ordered by: internal time
List reduced from 673 to 15 due to restriction <15>
ncalls tottime percall cumtime percall filename:lineno(function)
- 30 10.286 0.343 10.286 0.343 {built-in method posix.waitpid}
- 30 0.325 0.011 2.078 0.069 /home/jdsiiro/Research/pyomo/pyomo/repn/plugins/lp_writer.py:250(write)
- 76560 0.278 0.000 0.668 0.000 /home/jdsiiro/Research/pyomo/pyomo/repn/plugins/lp_writer.py:576(write_expression)
- 30 0.248 0.008 0.508 0.017 /home/jdsiiro/Research/pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:394(process_soln_file)
- 76560 0.221 0.000 0.395 0.000 /home/jdsiiro/Research/pyomo/pyomo/repn/linear.py:664(_before_linear)
- 301530 0.131 0.000 0.178 0.000 /home/jdsiiro/Research/pyomo/pyomo/core/expr/symbol_map.py:133(getSymbol)
- 30 0.119 0.004 0.192 0.006 /home/jdsiiro/Research/pyomo/pyomo/core/base/PyomoModel.py:461(select)
- 77190 0.117 0.000 0.161 0.000 /home/jdsiiro/Research/pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:451()
- 30 0.116 0.004 0.285 0.010 /home/jdsiiro/Research/pyomo/pyomo/core/base/PyomoModel.py:337(add_solution)
- 76530 0.080 0.000 0.106 0.000 /home/jdsiiro/Research/pyomo/pyomo/core/expr/symbol_map.py:63(addSymbol)
- 239550 0.079 0.000 0.079 0.000 /home/jdsiiro/Research/pyomo/pyomo/core/base/indexed_component.py:611(__getitem__)
- 1062450 0.078 0.000 0.078 0.000 {built-in method builtins.id}
- 163050 0.074 0.000 0.128 0.000 /home/jdsiiro/Research/pyomo/pyomo/core/base/var.py:1045(__getitem__)
- 76560 0.074 0.000 0.080 0.000 /home/jdsiiro/Research/pyomo/pyomo/repn/linear.py:834(finalizeResult)
- 153150 0.073 0.000 0.191 0.000 /home/jdsiiro/Research/pyomo/pyomo/core/base/block.py:1505(_component_data_itervalues)
+ 30 7.607 0.254 7.607 0.254 {built-in method posix.waitpid}
+ 30 0.328 0.011 2.101 0.070 pyomo/pyomo/repn/plugins/lp_writer.py:250(write)
+ 76560 0.284 0.000 0.680 0.000 pyomo/pyomo/repn/plugins/lp_writer.py:576(write_expression)
+ 76560 0.220 0.000 0.388 0.000 pyomo/pyomo/repn/linear.py:664(_before_linear)
+ 30 0.209 0.007 0.438 0.015 pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:394(process_soln_file)
+ 30 0.175 0.006 0.175 0.006 {built-in method _posixsubprocess.fork_exec}
+ 301530 0.134 0.000 0.181 0.000 pyomo/pyomo/core/expr/symbol_map.py:133(getSymbol)
+ 30 0.109 0.004 0.178 0.006 pyomo/pyomo/core/base/PyomoModel.py:461(select)
+ 77190 0.105 0.000 0.145 0.000 pyomo/pyomo/solvers/plugins/solvers/GUROBI.py:451()
+ 30 0.104 0.003 0.257 0.009 pyomo/pyomo/core/base/PyomoModel.py:337(add_solution)
+ 76530 0.081 0.000 0.109 0.000 pyomo/pyomo/core/expr/symbol_map.py:63(addSymbol)
+ 1062470 0.079 0.000 0.079 0.000 {built-in method builtins.id}
+ 76560 0.073 0.000 0.079 0.000 pyomo/pyomo/repn/linear.py:834(finalizeResult)
+ 239550 0.073 0.000 0.073 0.000 pyomo/pyomo/core/base/indexed_component.py:612(__getitem__)
+ 153150 0.070 0.000 0.179 0.000 pyomo/pyomo/core/base/block.py:1463(_component_data_itervalues)
[ 0.00] Resetting the tic/toc delta timer
-[+ 0.66] Finished parameter sweep with persistent interface
+[+ 0.49] Finished parameter sweep with persistent interface
diff --git a/examples/pyomobook/pyomo-components-ch/con_declaration.py b/examples/pyomobook/pyomo-components-ch/con_declaration.py
index 7775c1b26a0..0890ba4771b 100644
--- a/examples/pyomobook/pyomo-components-ch/con_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/con_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/con_declaration.txt b/examples/pyomobook/pyomo-components-ch/con_declaration.txt
index 019cd448eb0..b4709bd5490 100644
--- a/examples/pyomobook/pyomo-components-ch/con_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/con_declaration.txt
@@ -1,10 +1,5 @@
-1 Set Declarations
- x_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
1 Var Declarations
- x : Size=2, Index=x_index
+ x : Size=2, Index={1, 2}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : 1.0 : None : False : False : Reals
2 : None : 1.0 : None : False : False : Reals
@@ -14,14 +9,9 @@
Key : Lower : Body : Upper : Active
None : -Inf : x[2] - x[1] : 7.5 : True
-3 Declarations: x_index x diff
-1 Set Declarations
- x_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 2 : {1, 2}
-
+2 Declarations: x diff
1 Var Declarations
- x : Size=2, Index=x_index
+ x : Size=2, Index={1, 2}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : 1.0 : None : False : False : Reals
2 : None : 1.0 : None : False : False : Reals
@@ -31,40 +21,24 @@
Key : Lower : Body : Upper : Active
None : -Inf : x[2] - x[1] : 7.5 : True
-3 Declarations: x_index x diff
-2 Set Declarations
- CoverConstr_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- y_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
-
+2 Declarations: x diff
1 Var Declarations
- y : Size=3, Index=y_index
+ y : Size=3, Index={1, 2, 3}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : 0 : 0.0 : None : False : False : NonNegativeReals
2 : 0 : 0.0 : None : False : False : NonNegativeReals
3 : 0 : 0.0 : None : False : False : NonNegativeReals
1 Constraint Declarations
- CoverConstr : Size=3, Index=CoverConstr_index, Active=True
+ CoverConstr : Size=3, Index={1, 2, 3}, Active=True
Key : Lower : Body : Upper : Active
1 : 1.0 : y[1] : +Inf : True
2 : 2.9 : 3.1*y[2] : +Inf : True
3 : 3.1 : 4.5*y[3] : +Inf : True
-4 Declarations: y_index y CoverConstr_index CoverConstr
-2 Set Declarations
- Pred_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 5 : {1, 2, 3, 4, 5}
- StartTime_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 5 : {1, 2, 3, 4, 5}
-
+2 Declarations: y CoverConstr
1 Var Declarations
- StartTime : Size=5, Index=StartTime_index
+ StartTime : Size=5, Index={1, 2, 3, 4, 5}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : 1.0 : None : False : False : Reals
2 : None : 1.0 : None : False : False : Reals
@@ -73,14 +47,14 @@
5 : None : 1.0 : None : False : False : Reals
1 Constraint Declarations
- Pred : Size=4, Index=Pred_index, Active=True
+ Pred : Size=4, Index={1, 2, 3, 4, 5}, Active=True
Key : Lower : Body : Upper : Active
1 : -Inf : StartTime[1] - StartTime[2] : 0.0 : True
2 : -Inf : StartTime[2] - StartTime[3] : 0.0 : True
3 : -Inf : StartTime[3] - StartTime[4] : 0.0 : True
4 : -Inf : StartTime[4] - StartTime[5] : 0.0 : True
-4 Declarations: StartTime_index StartTime Pred_index Pred
+2 Declarations: StartTime Pred
0.0
inf
7.5
diff --git a/examples/pyomobook/pyomo-components-ch/examples.py b/examples/pyomobook/pyomo-components-ch/examples.py
index 6ba96792e28..1a59e9e308e 100644
--- a/examples/pyomobook/pyomo-components-ch/examples.py
+++ b/examples/pyomobook/pyomo-components-ch/examples.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
print("indexed1")
diff --git a/examples/pyomobook/pyomo-components-ch/examples.txt b/examples/pyomobook/pyomo-components-ch/examples.txt
index 635b988cbcd..27ea1ba130b 100644
--- a/examples/pyomobook/pyomo-components-ch/examples.txt
+++ b/examples/pyomobook/pyomo-components-ch/examples.txt
@@ -1,20 +1,17 @@
indexed1
-3 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 2 : {'Q', 'R'}
- y_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 6 : {(1, 'Q'), (1, 'R'), (2, 'Q'), (2, 'R'), (3, 'Q'), (3, 'R')}
2 Var Declarations
x : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : None : None : None : False : True : Reals
- y : Size=6, Index=y_index
+ y : Size=6, Index=A*B
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 'Q') : None : None : None : False : True : Reals
(1, 'R') : None : None : None : False : True : Reals
@@ -38,4 +35,4 @@ indexed1
2 : -Inf : 2*x : 0.0 : True
3 : -Inf : 3*x : 0.0 : True
-8 Declarations: A B x y_index y o c d
+7 Declarations: A B x y o c d
diff --git a/examples/pyomobook/pyomo-components-ch/expr_declaration.py b/examples/pyomobook/pyomo-components-ch/expr_declaration.py
index 8974a4d406a..da0d854e513 100644
--- a/examples/pyomobook/pyomo-components-ch/expr_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/expr_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/expr_declaration.txt b/examples/pyomobook/pyomo-components-ch/expr_declaration.txt
index 66c99f6502a..86e0feac27f 100644
--- a/examples/pyomobook/pyomo-components-ch/expr_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/expr_declaration.txt
@@ -18,28 +18,20 @@
None : x + 2
3 Declarations: x e1 e2
-2 Set Declarations
- e_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- x_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
-
1 Var Declarations
- x : Size=3, Index=x_index
+ x : Size=3, Index={1, 2, 3}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : None : None : False : True : Reals
2 : None : None : None : False : True : Reals
3 : None : None : None : False : True : Reals
1 Expression Declarations
- e : Size=2, Index=e_index
+ e : Size=2, Index={1, 2, 3}
Key : Expression
2 : x[2]**2
3 : x[3]**2
-4 Declarations: x_index x e_index e
+2 Declarations: x e
1 Var Declarations
x : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
diff --git a/examples/pyomobook/pyomo-components-ch/obj_declaration.py b/examples/pyomobook/pyomo-components-ch/obj_declaration.py
index 2c26c2b3363..a63fc441206 100644
--- a/examples/pyomobook/pyomo-components-ch/obj_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/obj_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/obj_declaration.txt b/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
index e43134b8d92..e4d4b02a252 100644
--- a/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/obj_declaration.txt
@@ -14,7 +14,7 @@ declexprrule
Model unknown
Variables:
- x : Size=2, Index=x_index
+ x : Size=2, Index={1, 2}
Key : Lower : Value : Upper : Fixed : Stale : Domain
1 : None : 1.0 : None : False : False : Reals
2 : None : 1.0 : None : False : False : Reals
@@ -34,19 +34,19 @@ declskip
Model unknown
Variables:
- x : Size=3, Index=x_index
+ x : Size=3, Index={Q, R, S}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Q : None : 1.0 : None : False : False : Reals
R : None : 1.0 : None : False : False : Reals
S : None : 1.0 : None : False : False : Reals
Objectives:
- d : Size=3, Index=d_index, Active=True
+ d : Size=3, Index={Q, R, S}, Active=True
Key : Active : Value
Q : True : 1.0
R : True : 1.0
S : True : 1.0
- e : Size=2, Index=e_index, Active=True
+ e : Size=2, Index={Q, R, S}, Active=True
Key : Active : Value
Q : True : 1.0
S : True : 1.0
@@ -55,12 +55,12 @@ Model unknown
None
value
x[Q] + 2*x[R]
-1
+minimize
6.5
Model unknown
Variables:
- x : Size=2, Index=x_index
+ x : Size=2, Index={Q, R}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Q : None : 1.5 : None : False : False : Reals
R : None : 2.5 : None : False : False : Reals
diff --git a/examples/pyomobook/pyomo-components-ch/param_declaration.py b/examples/pyomobook/pyomo-components-ch/param_declaration.py
index a9d3256abfe..98b16548c28 100644
--- a/examples/pyomobook/pyomo-components-ch/param_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/param_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/param_declaration.txt b/examples/pyomobook/pyomo-components-ch/param_declaration.txt
index 9b8ce9cacdb..8c8a49eedc6 100644
--- a/examples/pyomobook/pyomo-components-ch/param_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/param_declaration.txt
@@ -1,16 +1,13 @@
-3 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 2 : {'A', 'B'}
- T_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 6 : {(1, 'A'), (1, 'B'), (2, 'A'), (2, 'B'), (3, 'A'), (3, 'B')}
3 Param Declarations
- T : Size=3, Index=T_index, Domain=Any, Default=None, Mutable=False
+ T : Size=3, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
(1, 'A') : 10
(2, 'B') : 20
@@ -24,4 +21,4 @@
Key : Value
None : 32
-6 Declarations: Z A B U T_index T
+5 Declarations: Z A B U T
diff --git a/examples/pyomobook/pyomo-components-ch/param_initialization.py b/examples/pyomobook/pyomo-components-ch/param_initialization.py
index 11c257d2c31..88da8a68354 100644
--- a/examples/pyomobook/pyomo-components-ch/param_initialization.py
+++ b/examples/pyomobook/pyomo-components-ch/param_initialization.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/param_initialization.txt b/examples/pyomobook/pyomo-components-ch/param_initialization.txt
index d1ac6aba989..e0bcdf11a71 100644
--- a/examples/pyomobook/pyomo-components-ch/param_initialization.txt
+++ b/examples/pyomobook/pyomo-components-ch/param_initialization.txt
@@ -1,27 +1,15 @@
-6 Set Declarations
+2 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {1, 2, 3}
- T_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*B : 9 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}
- U_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*A : 9 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}
- XX_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*A : 9 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}
- X_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : A*A : 9 : {(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)}
5 Param Declarations
- T : Size=0, Index=T_index, Domain=Any, Default=None, Mutable=False
+ T : Size=0, Index=A*B, Domain=Any, Default=None, Mutable=False
Key : Value
- U : Size=9, Index=U_index, Domain=Any, Default=0, Mutable=False
+ U : Size=9, Index=A*A, Domain=Any, Default=0, Mutable=False
Key : Value
(1, 1) : 10
(2, 2) : 20
@@ -30,7 +18,7 @@
Key : Value
1 : 10
3 : 30
- X : Size=9, Index=X_index, Domain=Any, Default=None, Mutable=False
+ X : Size=9, Index=A*A, Domain=Any, Default=None, Mutable=False
Key : Value
(1, 1) : 1
(1, 2) : 2
@@ -41,7 +29,7 @@
(3, 1) : 3
(3, 2) : 6
(3, 3) : 9
- XX : Size=9, Index=XX_index, Domain=Any, Default=None, Mutable=False
+ XX : Size=9, Index=A*A, Domain=Any, Default=None, Mutable=False
Key : Value
(1, 1) : 1
(1, 2) : 2
@@ -53,7 +41,7 @@
(3, 2) : 8
(3, 3) : 14
-11 Declarations: A X_index X XX_index XX B W U_index U T_index T
+7 Declarations: A X XX B W U T
2
3
False
diff --git a/examples/pyomobook/pyomo-components-ch/param_misc.py b/examples/pyomobook/pyomo-components-ch/param_misc.py
index baf76cc7c03..72fca60f787 100644
--- a/examples/pyomobook/pyomo-components-ch/param_misc.py
+++ b/examples/pyomobook/pyomo-components-ch/param_misc.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
# @mutable1:
diff --git a/examples/pyomobook/pyomo-components-ch/param_validation.py b/examples/pyomobook/pyomo-components-ch/param_validation.py
index c82657c8d0f..baf5f0ac1e2 100644
--- a/examples/pyomobook/pyomo-components-ch/param_validation.py
+++ b/examples/pyomobook/pyomo-components-ch/param_validation.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/pyomo-components-ch/rangeset.py b/examples/pyomobook/pyomo-components-ch/rangeset.py
index d5e1015064c..169060e9ab2 100644
--- a/examples/pyomobook/pyomo-components-ch/rangeset.py
+++ b/examples/pyomobook/pyomo-components-ch/rangeset.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/pyomo-components-ch/set_declaration.py b/examples/pyomobook/pyomo-components-ch/set_declaration.py
index 1a507d4f588..bf3cfa1be15 100644
--- a/examples/pyomobook/pyomo-components-ch/set_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/set_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/pyomo-components-ch/set_declaration.txt b/examples/pyomobook/pyomo-components-ch/set_declaration.txt
index bdbb7376de4..a588e5601b6 100644
--- a/examples/pyomobook/pyomo-components-ch/set_declaration.txt
+++ b/examples/pyomobook/pyomo-components-ch/set_declaration.txt
@@ -5,22 +5,16 @@
1 Declarations: A
0 Declarations:
-4 Set Declarations
- E : Size=1, Index=E_index, Ordered=Insertion
+2 Set Declarations
+ E : Size=1, Index={1, 2, 3}, Ordered=Insertion
Key : Dimen : Domain : Size : Members
2 : 1 : Any : 3 : {21, 22, 23}
- E_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
- F : Size=2, Index=F_index, Ordered=Insertion
+ F : Size=2, Index={1, 2, 3}, Ordered=Insertion
Key : Dimen : Domain : Size : Members
1 : 1 : Any : 3 : {11, 12, 13}
3 : 1 : Any : 3 : {31, 32, 33}
- F_index : Size=1, Index=None, Ordered=False
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
-4 Declarations: E_index E F_index F
+2 Declarations: E F
6 Set Declarations
A : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
diff --git a/examples/pyomobook/pyomo-components-ch/set_initialization.py b/examples/pyomobook/pyomo-components-ch/set_initialization.py
index 89dbaa713db..bdfd662c985 100644
--- a/examples/pyomobook/pyomo-components-ch/set_initialization.py
+++ b/examples/pyomobook/pyomo-components-ch/set_initialization.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/set_initialization.txt b/examples/pyomobook/pyomo-components-ch/set_initialization.txt
index af2ba54a8d2..29900ccb7b2 100644
--- a/examples/pyomobook/pyomo-components-ch/set_initialization.txt
+++ b/examples/pyomobook/pyomo-components-ch/set_initialization.txt
@@ -1,19 +1,16 @@
-10 Set Declarations
+7 Set Declarations
B : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 3 : {2, 3, 4}
C : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 2 : Any : 2 : {(1, 4), (9, 16)}
- F : Size=3, Index=F_index, Ordered=Insertion
+ F : Size=3, Index={2, 3, 4}, Ordered=Insertion
Key : Dimen : Domain : Size : Members
2 : 1 : Any : 3 : {1, 3, 5}
3 : 1 : Any : 3 : {2, 4, 6}
4 : 1 : Any : 3 : {3, 5, 7}
- F_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {2, 3, 4}
- J : Size=9, Index=J_index, Ordered=Insertion
+ J : Size=9, Index=B*B, Ordered=Insertion
Key : Dimen : Domain : Size : Members
(2, 2) : 1 : Any : 4 : {0, 1, 2, 3}
(2, 3) : 1 : Any : 6 : {0, 1, 2, 3, 4, 5}
@@ -24,21 +21,15 @@
(4, 2) : 1 : Any : 8 : {0, 1, 2, 3, 4, 5, 6, 7}
(4, 3) : 1 : Any : 12 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
(4, 4) : 1 : Any : 16 : {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
- J_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : B*B : 9 : {(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)}
P : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 5 : {1, 2, 3, 5, 7}
Q : Size=1, Index=None, Ordered=Insertion
Key : Dimen : Domain : Size : Members
None : 1 : Any : 4 : {4, 6, 8, 9}
- R : Size=2, Index=R_index, Ordered=Insertion
+ R : Size=2, Index={1, 2, 3}, Ordered=Insertion
Key : Dimen : Domain : Size : Members
1 : 1 : Any : 1 : {1,}
2 : 1 : Any : 2 : {1, 2}
- R_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {1, 2, 3}
-10 Declarations: B C F_index F J_index J P Q R_index R
+7 Declarations: B C F J P Q R
diff --git a/examples/pyomobook/pyomo-components-ch/set_misc.py b/examples/pyomobook/pyomo-components-ch/set_misc.py
index 9a795b196b8..20ed9518f52 100644
--- a/examples/pyomobook/pyomo-components-ch/set_misc.py
+++ b/examples/pyomobook/pyomo-components-ch/set_misc.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/pyomo-components-ch/set_options.py b/examples/pyomobook/pyomo-components-ch/set_options.py
index 8d49882de2f..30c0b49706d 100644
--- a/examples/pyomobook/pyomo-components-ch/set_options.py
+++ b/examples/pyomobook/pyomo-components-ch/set_options.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/pyomo-components-ch/set_validation.py b/examples/pyomobook/pyomo-components-ch/set_validation.py
index a55dfc9ab7c..2300c0be693 100644
--- a/examples/pyomobook/pyomo-components-ch/set_validation.py
+++ b/examples/pyomobook/pyomo-components-ch/set_validation.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.AbstractModel()
diff --git a/examples/pyomobook/pyomo-components-ch/suffix_declaration.py b/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
index 650669ef5a6..619093712f1 100644
--- a/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/suffix_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
print('')
diff --git a/examples/pyomobook/pyomo-components-ch/var_declaration.py b/examples/pyomobook/pyomo-components-ch/var_declaration.py
index 60d3b00756a..2ee5d7fb749 100644
--- a/examples/pyomobook/pyomo-components-ch/var_declaration.py
+++ b/examples/pyomobook/pyomo-components-ch/var_declaration.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/python-ch/BadIndent.py b/examples/pyomobook/python-ch/BadIndent.py
index 6ab545a6f46..4a00cae12ef 100644
--- a/examples/pyomobook/python-ch/BadIndent.py
+++ b/examples/pyomobook/python-ch/BadIndent.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 comment is the first line of BadIndent.py,
# which will cause Python to give an error message
# concerning indentation.
diff --git a/examples/pyomobook/python-ch/LineExample.py b/examples/pyomobook/python-ch/LineExample.py
index 0109a64167e..31cface5760 100644
--- a/examples/pyomobook/python-ch/LineExample.py
+++ b/examples/pyomobook/python-ch/LineExample.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 comment is the first line of LineExample.py
# all characters on a line after the #-character are
# ignored by Python
diff --git a/examples/pyomobook/python-ch/class.py b/examples/pyomobook/python-ch/class.py
index 562cef07ea7..a09f991d37b 100644
--- a/examples/pyomobook/python-ch/class.py
+++ b/examples/pyomobook/python-ch/class.py
@@ -1,25 +1,36 @@
-# class.py
-
-
-# @all:
-class IntLocker:
- sint = None
-
- def __init__(self, i):
- self.set_value(i)
-
- def set_value(self, i):
- if type(i) is not int:
- print("Error: %d is not integer." % i)
- else:
- self.sint = i
-
- def pprint(self):
- print("The Int Locker has " + str(self.sint))
-
-
-a = IntLocker(3)
-a.pprint() # prints: The Int Locker has 3
-a.set_value(5)
-a.pprint() # prints: The Int Locker has 5
-# @:all
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+# class.py
+
+
+# @all:
+class IntLocker:
+ sint = None
+
+ def __init__(self, i):
+ self.set_value(i)
+
+ def set_value(self, i):
+ if type(i) is not int:
+ print("Error: %d is not integer." % i)
+ else:
+ self.sint = i
+
+ def pprint(self):
+ print("The Int Locker has " + str(self.sint))
+
+
+a = IntLocker(3)
+a.pprint() # prints: The Int Locker has 3
+a.set_value(5)
+a.pprint() # prints: The Int Locker has 5
+# @:all
diff --git a/examples/pyomobook/python-ch/ctob.py b/examples/pyomobook/python-ch/ctob.py
index e418d27f103..8945e4863de 100644
--- a/examples/pyomobook/python-ch/ctob.py
+++ b/examples/pyomobook/python-ch/ctob.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# An example of a silly decorator to change 'c' to 'b'
# in the return value of a function.
diff --git a/examples/pyomobook/python-ch/example.py b/examples/pyomobook/python-ch/example.py
index 0a404add58d..184153545a3 100644
--- a/examples/pyomobook/python-ch/example.py
+++ b/examples/pyomobook/python-ch/example.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 comment line, which is ignored by Python
print("Hello World")
diff --git a/examples/pyomobook/python-ch/example2.py b/examples/pyomobook/python-ch/example2.py
index da7d14e24ae..9a6a28bedbd 100644
--- a/examples/pyomobook/python-ch/example2.py
+++ b/examples/pyomobook/python-ch/example2.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# A modified example.py program
print("Hello World")
diff --git a/examples/pyomobook/python-ch/functions.py b/examples/pyomobook/python-ch/functions.py
index 7948c5e55df..97fb77edbe4 100644
--- a/examples/pyomobook/python-ch/functions.py
+++ b/examples/pyomobook/python-ch/functions.py
@@ -1,24 +1,35 @@
-# functions.py
-
-
-# @all:
-def Apply(f, a):
- r = []
- for i in range(len(a)):
- r.append(f(a[i]))
- return r
-
-
-def SqifOdd(x):
- # if x is odd, 2*int(x/2) is not x
- # due to integer divide of x/2
- if 2 * int(x / 2) == x:
- return x
- else:
- return x * x
-
-
-ShortList = range(4)
-B = Apply(SqifOdd, ShortList)
-print(B)
-# @:all
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+# functions.py
+
+
+# @all:
+def Apply(f, a):
+ r = []
+ for i in range(len(a)):
+ r.append(f(a[i]))
+ return r
+
+
+def SqifOdd(x):
+ # if x is odd, 2*int(x/2) is not x
+ # due to integer divide of x/2
+ if 2 * int(x / 2) == x:
+ return x
+ else:
+ return x * x
+
+
+ShortList = range(4)
+B = Apply(SqifOdd, ShortList)
+print(B)
+# @:all
diff --git a/examples/pyomobook/python-ch/iterate.py b/examples/pyomobook/python-ch/iterate.py
index 3a3422b2a09..50d74f93da7 100644
--- a/examples/pyomobook/python-ch/iterate.py
+++ b/examples/pyomobook/python-ch/iterate.py
@@ -1,18 +1,29 @@
-# iterate.py
-
-# @all:
-D = {'Mary': 231}
-D['Bob'] = 123
-D['Alice'] = 331
-D['Ted'] = 987
-
-for i in sorted(D):
- if i == 'Alice':
- continue
- if i == 'John':
- print("Loop ends. Cleese alert!")
- break
- print(i + " " + str(D[i]))
-else:
- print("Cleese is not in the list.")
-# @:all
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+# iterate.py
+
+# @all:
+D = {'Mary': 231}
+D['Bob'] = 123
+D['Alice'] = 331
+D['Ted'] = 987
+
+for i in sorted(D):
+ if i == 'Alice':
+ continue
+ if i == 'John':
+ print("Loop ends. Cleese alert!")
+ break
+ print(i + " " + str(D[i]))
+else:
+ print("Cleese is not in the list.")
+# @:all
diff --git a/examples/pyomobook/python-ch/pythonconditional.py b/examples/pyomobook/python-ch/pythonconditional.py
index 205428e5ad1..a39e148622b 100644
--- a/examples/pyomobook/python-ch/pythonconditional.py
+++ b/examples/pyomobook/python-ch/pythonconditional.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# pythonconditional.py
# @all:
diff --git a/examples/pyomobook/scripts-ch/attributes.py b/examples/pyomobook/scripts-ch/attributes.py
index 643162082b6..c406bbf3e1c 100644
--- a/examples/pyomobook/scripts-ch/attributes.py
+++ b/examples/pyomobook/scripts-ch/attributes.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 warehouse_model import create_wl_model
diff --git a/examples/pyomobook/scripts-ch/prob_mod_ex.py b/examples/pyomobook/scripts-ch/prob_mod_ex.py
index 6d610e9b44a..dceafe9d4f0 100644
--- a/examples/pyomobook/scripts-ch/prob_mod_ex.py
+++ b/examples/pyomobook/scripts-ch/prob_mod_ex.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/scripts-ch/sudoku/sudoku.py b/examples/pyomobook/scripts-ch/sudoku/sudoku.py
index ea0c0044e1d..8aa39f91203 100644
--- a/examples/pyomobook/scripts-ch/sudoku/sudoku.py
+++ b/examples/pyomobook/scripts-ch/sudoku/sudoku.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
# create a standard python dict for mapping subsquares to
diff --git a/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py b/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
index 266362308fa..b3f861f86b5 100644
--- a/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
+++ b/examples/pyomobook/scripts-ch/sudoku/sudoku_run.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.opt import SolverFactory, TerminationCondition
from sudoku import create_sudoku_model, print_solution, add_integer_cut
diff --git a/examples/pyomobook/scripts-ch/value_expression.py b/examples/pyomobook/scripts-ch/value_expression.py
index 51c07500ea8..00c79fec501 100644
--- a/examples/pyomobook/scripts-ch/value_expression.py
+++ b/examples/pyomobook/scripts-ch/value_expression.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
model = pyo.ConcreteModel()
diff --git a/examples/pyomobook/scripts-ch/warehouse_cuts.py b/examples/pyomobook/scripts-ch/warehouse_cuts.py
index c6516e796af..345dc5540cb 100644
--- a/examples/pyomobook/scripts-ch/warehouse_cuts.py
+++ b/examples/pyomobook/scripts-ch/warehouse_cuts.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 warnings
warnings.filterwarnings("ignore")
diff --git a/examples/pyomobook/scripts-ch/warehouse_cuts.txt b/examples/pyomobook/scripts-ch/warehouse_cuts.txt
index 9afe6c4e944..1f097e06cea 100644
--- a/examples/pyomobook/scripts-ch/warehouse_cuts.txt
+++ b/examples/pyomobook/scripts-ch/warehouse_cuts.txt
@@ -1,7 +1,7 @@
--- Solver Status: optimal ---
Optimal Obj. Value = 2745.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
@@ -9,7 +9,7 @@ y : Size=3, Index=y_index
--- Solver Status: optimal ---
Optimal Obj. Value = 3168.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 0.0 : 1 : False : False : Binary
@@ -17,7 +17,7 @@ y : Size=3, Index=y_index
--- Solver Status: optimal ---
Optimal Obj. Value = 3563.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 0.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
@@ -25,7 +25,7 @@ y : Size=3, Index=y_index
--- Solver Status: optimal ---
Optimal Obj. Value = 3986.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 0.0 : 1 : False : False : Binary
Harlingen : 0 : 0.0 : 1 : False : False : Binary
@@ -33,7 +33,7 @@ y : Size=3, Index=y_index
--- Solver Status: optimal ---
Optimal Obj. Value = 4367.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 0.0 : 1 : False : False : Binary
@@ -41,7 +41,7 @@ y : Size=3, Index=y_index
--- Solver Status: optimal ---
Optimal Obj. Value = 5302.0
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 0.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
diff --git a/examples/pyomobook/scripts-ch/warehouse_load_solutions.py b/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
index 790333a0e64..d38412f84df 100644
--- a/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
+++ b/examples/pyomobook/scripts-ch/warehouse_load_solutions.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 warehouse_model import create_wl_model
diff --git a/examples/pyomobook/scripts-ch/warehouse_model.py b/examples/pyomobook/scripts-ch/warehouse_model.py
index f5983d3cd89..149eb212759 100644
--- a/examples/pyomobook/scripts-ch/warehouse_model.py
+++ b/examples/pyomobook/scripts-ch/warehouse_model.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
diff --git a/examples/pyomobook/scripts-ch/warehouse_print.py b/examples/pyomobook/scripts-ch/warehouse_print.py
index e0e2f961345..8c862506bf0 100644
--- a/examples/pyomobook/scripts-ch/warehouse_print.py
+++ b/examples/pyomobook/scripts-ch/warehouse_print.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 warehouse_model import create_wl_model
diff --git a/examples/pyomobook/scripts-ch/warehouse_script.py b/examples/pyomobook/scripts-ch/warehouse_script.py
index f2635a45d3d..617b8036abf 100644
--- a/examples/pyomobook/scripts-ch/warehouse_script.py
+++ b/examples/pyomobook/scripts-ch/warehouse_script.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# @script:
import json
import pyomo.environ as pyo
diff --git a/examples/pyomobook/scripts-ch/warehouse_script.txt b/examples/pyomobook/scripts-ch/warehouse_script.txt
index b922643dd2b..fac3aef0880 100644
--- a/examples/pyomobook/scripts-ch/warehouse_script.txt
+++ b/examples/pyomobook/scripts-ch/warehouse_script.txt
@@ -1,36 +1,10 @@
-y : Size=3, Index=y_index
+y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
Memphis : 0 : 0.0 : 1 : False : False : Binary
-8 Set Declarations
- one_per_cust_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {'NYC', 'LA', 'Chicago', 'Houston'}
- warehouse_active_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : warehouse_active_index_0*warehouse_active_index_1 : 12 : {('Harlingen', 'NYC'), ('Harlingen', 'LA'), ('Harlingen', 'Chicago'), ('Harlingen', 'Houston'), ('Memphis', 'NYC'), ('Memphis', 'LA'), ('Memphis', 'Chicago'), ('Memphis', 'Houston'), ('Ashland', 'NYC'), ('Ashland', 'LA'), ('Ashland', 'Chicago'), ('Ashland', 'Houston')}
- warehouse_active_index_0 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'Harlingen', 'Memphis', 'Ashland'}
- warehouse_active_index_1 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {'NYC', 'LA', 'Chicago', 'Houston'}
- x_index : Size=1, Index=None, Ordered=True
- Key : Dimen : Domain : Size : Members
- None : 2 : x_index_0*x_index_1 : 12 : {('Harlingen', 'NYC'), ('Harlingen', 'LA'), ('Harlingen', 'Chicago'), ('Harlingen', 'Houston'), ('Memphis', 'NYC'), ('Memphis', 'LA'), ('Memphis', 'Chicago'), ('Memphis', 'Houston'), ('Ashland', 'NYC'), ('Ashland', 'LA'), ('Ashland', 'Chicago'), ('Ashland', 'Houston')}
- x_index_0 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'Harlingen', 'Memphis', 'Ashland'}
- x_index_1 : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 4 : {'NYC', 'LA', 'Chicago', 'Houston'}
- y_index : Size=1, Index=None, Ordered=Insertion
- Key : Dimen : Domain : Size : Members
- None : 1 : Any : 3 : {'Harlingen', 'Memphis', 'Ashland'}
-
2 Var Declarations
- x : Size=12, Index=x_index
+ x : Size=12, Index={Harlingen, Memphis, Ashland}*{NYC, LA, Chicago, Houston}
Key : Lower : Value : Upper : Fixed : Stale : Domain
('Ashland', 'Chicago') : 0 : 1.0 : 1 : False : False : Reals
('Ashland', 'Houston') : 0 : 0.0 : 1 : False : False : Reals
@@ -40,11 +14,11 @@ y : Size=3, Index=y_index
('Harlingen', 'Houston') : 0 : 1.0 : 1 : False : False : Reals
('Harlingen', 'LA') : 0 : 1.0 : 1 : False : False : Reals
('Harlingen', 'NYC') : 0 : 0.0 : 1 : False : False : Reals
- ('Memphis', 'Chicago') : 0 : -0.0 : 1 : False : False : Reals
+ ('Memphis', 'Chicago') : 0 : 0.0 : 1 : False : False : Reals
('Memphis', 'Houston') : 0 : 0.0 : 1 : False : False : Reals
('Memphis', 'LA') : 0 : 0.0 : 1 : False : False : Reals
('Memphis', 'NYC') : 0 : 0.0 : 1 : False : False : Reals
- y : Size=3, Index=y_index
+ y : Size=3, Index={Harlingen, Memphis, Ashland}
Key : Lower : Value : Upper : Fixed : Stale : Domain
Ashland : 0 : 1.0 : 1 : False : False : Binary
Harlingen : 0 : 1.0 : 1 : False : False : Binary
@@ -59,13 +33,13 @@ y : Size=3, Index=y_index
num_warehouses : Size=1, Index=None, Active=True
Key : Lower : Body : Upper : Active
None : -Inf : y[Harlingen] + y[Memphis] + y[Ashland] : 2.0 : True
- one_per_cust : Size=4, Index=one_per_cust_index, Active=True
+ one_per_cust : Size=4, Index={NYC, LA, Chicago, Houston}, Active=True
Key : Lower : Body : Upper : Active
Chicago : 1.0 : x[Harlingen,Chicago] + x[Memphis,Chicago] + x[Ashland,Chicago] : 1.0 : True
Houston : 1.0 : x[Harlingen,Houston] + x[Memphis,Houston] + x[Ashland,Houston] : 1.0 : True
LA : 1.0 : x[Harlingen,LA] + x[Memphis,LA] + x[Ashland,LA] : 1.0 : True
NYC : 1.0 : x[Harlingen,NYC] + x[Memphis,NYC] + x[Ashland,NYC] : 1.0 : True
- warehouse_active : Size=12, Index=warehouse_active_index, Active=True
+ warehouse_active : Size=12, Index={Harlingen, Memphis, Ashland}*{NYC, LA, Chicago, Houston}, Active=True
Key : Lower : Body : Upper : Active
('Ashland', 'Chicago') : -Inf : x[Ashland,Chicago] - y[Ashland] : 0.0 : True
('Ashland', 'Houston') : -Inf : x[Ashland,Houston] - y[Ashland] : 0.0 : True
@@ -80,4 +54,4 @@ y : Size=3, Index=y_index
('Memphis', 'LA') : -Inf : x[Memphis,LA] - y[Memphis] : 0.0 : True
('Memphis', 'NYC') : -Inf : x[Memphis,NYC] - y[Memphis] : 0.0 : True
-14 Declarations: x_index_0 x_index_1 x_index x y_index y obj one_per_cust_index one_per_cust warehouse_active_index_0 warehouse_active_index_1 warehouse_active_index warehouse_active num_warehouses
+6 Declarations: x y obj one_per_cust warehouse_active num_warehouses
diff --git a/examples/pyomobook/scripts-ch/warehouse_solver_options.py b/examples/pyomobook/scripts-ch/warehouse_solver_options.py
index c8eaf11a0f3..4e79e158d50 100644
--- a/examples/pyomobook/scripts-ch/warehouse_solver_options.py
+++ b/examples/pyomobook/scripts-ch/warehouse_solver_options.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
# @script:
import json
import pyomo.environ as pyo
diff --git a/examples/pyomobook/strip_examples.py b/examples/pyomobook/strip_examples.py
index 0a65eef7c04..84017299fb6 100644
--- a/examples/pyomobook/strip_examples.py
+++ b/examples/pyomobook/strip_examples.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 glob
import sys
import os
diff --git a/examples/pyomobook/test_book_examples.py b/examples/pyomobook/test_book_examples.py
index e946864c1aa..192330dc1bf 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 20ee59d48b2..1c7bea821ff 100644
--- a/pyomo/__init__.py
+++ b/pyomo/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..3fd82b33044
--- /dev/null
+++ b/pyomo/_archive/__init__.py
@@ -0,0 +1,18 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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/_archive/chull.py b/pyomo/_archive/chull.py
new file mode 100644
index 00000000000..0d31e484afb
--- /dev/null
+++ b/pyomo/_archive/chull.py
@@ -0,0 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.gdp.plugins.chull module"
+
+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 b48fa96a483..fbccc171689 100644
--- a/pyomo/common/plugin.py
+++ b/pyomo/_archive/component_map.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ecac3967dfe..b2efe88afd8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 0a2ff01c82a..aca46f2aa69 100644
--- a/pyomo/core/expr/current.py
+++ b/pyomo/_archive/current.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 57%
rename from pyomo/core/base/plugin.py
rename to pyomo/_archive/plugin.py
index 4ecb12d86a6..64352f58509 100644
--- a/pyomo/core/base/plugin.py
+++ b/pyomo/_archive/plugin.py
@@ -1,49 +1,15 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,
-)
-
-__all__ = [
- 'pyomo_callback',
- 'IPyomoExpression',
- 'ExpressionFactory',
- 'ExpressionRegistration',
- 'IPyomoPresolver',
- 'IPyomoPresolveAction',
- 'IParamRepresentation',
- 'ParamRepresentationFactory',
- 'IPyomoScriptPreprocess',
- 'IPyomoScriptCreateModel',
- 'IPyomoScriptCreateDataPortal',
- 'IPyomoScriptModifyInstance',
- 'IPyomoScriptPrintModel',
- 'IPyomoScriptPrintInstance',
- 'IPyomoScriptSaveInstance',
- 'IPyomoScriptPrintResults',
- 'IPyomoScriptSaveResults',
- 'IPyomoScriptPostprocess',
- 'ModelComponentFactory',
- 'Transformation',
- 'TransformationFactory',
-]
+"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 e8b2507ab81..2c313ecb79a 100644
--- a/pyomo/common/getGSL.py
+++ b/pyomo/_archive/rangeset.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 5f7812354d9..a8c67a53c17 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..8e2eb6bd7c9
--- /dev/null
+++ b/pyomo/_archive/sets.py
@@ -0,0 +1,23 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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..eda4033d09a
--- /dev/null
+++ b/pyomo/_archive/template_expr.py
@@ -0,0 +1,18 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 563974b5617..c2299bdcea8 100644
--- a/pyomo/common/__init__.py
+++ b/pyomo/common/__init__.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ae633648ace..ad521659aa7 100644
--- a/pyomo/common/_command.py
+++ b/pyomo/common/_command.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,6 @@
Management of Pyomo commands
"""
-__all__ = ['pyomo_command', 'get_pyomo_commands']
-
import logging
logger = logging.getLogger('pyomo.common')
diff --git a/pyomo/common/_common.py b/pyomo/common/_common.py
index 21a5ddcc7bc..0d50f74537a 100644
--- a/pyomo/common/_common.py
+++ b/pyomo/common/_common.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 1b55a818b83..a5ba44818c3 100644
--- a/pyomo/common/autoslots.py
+++ b/pyomo/common/autoslots.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,28 @@
# 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:
# Python does not duplicate "unchanged" tuples (i.e. allows the
- # original objecct to be returned from deepcopy()). We will
+ # original object to be returned from deepcopy()). We will
# preserve that behavior here.
#
# It also appears to be faster *not* to cache the fact that this
@@ -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 36f2dac87ab..e70b0f6d267 100644
--- a/pyomo/common/backports.py
+++ b/pyomo/common/backports.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 bb612b43b72..523dbf64c91 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 9ffd1e931f6..717caf87b2c 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,6 +14,6 @@
from collections import UserDict
from .orderedset import OrderedDict, OrderedSet
-from .component_map import ComponentMap
+from .component_map import ComponentMap, DefaultComponentMap
from .component_set import ComponentSet
from .bunch import Bunch
diff --git a/pyomo/common/collections/bunch.py b/pyomo/common/collections/bunch.py
index f19e4ad64e3..2ae9cf8c517 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 41796876d7c..a9248dfba60 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,61 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from collections.abc import MutableMapping as collections_MutableMapping
+import collections
from collections.abc import Mapping as collections_Mapping
from pyomo.common.autoslots import AutoSlots
-def _rebuild_ids(encode, val):
+def _rehash_keys(encode, val):
if encode:
return val
else:
# object id() may have changed after unpickling,
# so we rebuild the dictionary keys
- return {id(obj): (obj, v) for obj, v in val.values()}
+ return {_hasher[obj.__class__](obj): (obj, v) for obj, v in val.values()}
-class ComponentMap(AutoSlots.Mixin, collections_MutableMapping):
+class _Hasher(collections.defaultdict):
+ def __init__(self, *args, **kwargs):
+ super().__init__(lambda: self._missing_impl, *args, **kwargs)
+ self[tuple] = self._tuple
+
+ def _missing_impl(self, val):
+ try:
+ hash(val)
+ self[val.__class__] = self._hashable
+ except:
+ self[val.__class__] = self._unhashable
+ return self[val.__class__](val)
+
+ @staticmethod
+ def _hashable(val):
+ return val
+
+ @staticmethod
+ def _unhashable(val):
+ return id(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()
+
+
+class ComponentMap(AutoSlots.Mixin, collections.abc.MutableMapping):
"""
This class is a replacement for dict that allows Pyomo
modeling components to be used as entry keys. The
@@ -49,18 +89,20 @@ class ComponentMap(AutoSlots.Mixin, collections_MutableMapping):
"""
__slots__ = ("_dict",)
- __autoslot_mappers__ = {'_dict': _rebuild_ids}
+ __autoslot_mappers__ = {'_dict': _rehash_keys}
+ # Expose a "public" interface to the global _hasher dict
+ hasher = _hasher
def __init__(self, *args, **kwds):
- # maps id(obj) -> (obj,val)
+ # maps id_hash(obj) -> (obj,val)
self._dict = {}
# handle the dict-style initialization scenarios
self.update(*args, **kwds)
def __str__(self):
"""String representation of the mapping."""
- tmp = {str(c) + " (id=" + str(id(c)) + ")": v for c, v in self.items()}
- return "ComponentMap(" + str(tmp) + ")"
+ tmp = {f"{v[0]} (key={k})": v[1] for k, v in self._dict.items()}
+ return f"ComponentMap({tmp})"
#
# Implement MutableMapping abstract methods
@@ -68,18 +110,20 @@ def __str__(self):
def __getitem__(self, obj):
try:
- return self._dict[id(obj)][1]
+ return self._dict[_hasher[obj.__class__](obj)][1]
except KeyError:
- raise KeyError("Component with id '%s': %s" % (id(obj), str(obj)))
+ _id = _hasher[obj.__class__](obj)
+ raise KeyError(f"{obj} (key={_id})") from None
def __setitem__(self, obj, val):
- self._dict[id(obj)] = (obj, val)
+ self._dict[_hasher[obj.__class__](obj)] = (obj, val)
def __delitem__(self, obj):
try:
- del self._dict[id(obj)]
+ del self._dict[_hasher[obj.__class__](obj)]
except KeyError:
- raise KeyError("Component with id '%s': %s" % (id(obj), str(obj)))
+ _id = _hasher[obj.__class__](obj)
+ raise KeyError(f"{obj} (key={_id})") from None
def __iter__(self):
return (obj for obj, val in self._dict.values())
@@ -107,7 +151,7 @@ def __eq__(self, other):
return False
# Note we have already verified the dicts are the same size
for key, val in other.items():
- other_id = id(key)
+ other_id = _hasher[key.__class__](key)
if other_id not in self._dict:
return False
self_val = self._dict[other_id][1]
@@ -130,7 +174,7 @@ def __ne__(self, other):
#
def __contains__(self, obj):
- return id(obj) in self._dict
+ return _hasher[obj.__class__](obj) in self._dict
def clear(self):
'D.clear() -> None. Remove all items from D.'
@@ -149,3 +193,32 @@ def setdefault(self, key, default=None):
else:
self[key] = default
return default
+
+
+class DefaultComponentMap(ComponentMap):
+ """A :py:class:`defaultdict` admitting Pyomo Components as keys
+
+ This class is a replacement for defaultdict that allows Pyomo
+ modeling components to be used as entry keys. The base
+ implementation builds on :py:class:`ComponentMap`.
+
+ """
+
+ __slots__ = ('default_factory',)
+
+ def __init__(self, default_factory=None, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.default_factory = default_factory
+
+ def __missing__(self, key):
+ if self.default_factory is None:
+ raise KeyError(key)
+ self[key] = ans = self.default_factory()
+ return ans
+
+ def __getitem__(self, obj):
+ _key = _hasher[obj.__class__](obj)
+ if _key in self._dict:
+ return self._dict[_key][1]
+ else:
+ return self.__missing__(obj)
diff --git a/pyomo/common/collections/component_set.py b/pyomo/common/collections/component_set.py
index e205773220f..bbfee062436 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,8 +12,30 @@
from collections.abc import MutableSet as collections_MutableSet
from collections.abc import Set as collections_Set
+from pyomo.common.autoslots import AutoSlots
+from pyomo.common.collections.component_map import _hasher
+
+
+def _rehash_keys(encode, val):
+ if encode:
+ # TBD [JDS 2/2024]: if we
+ #
+ # return list(val.values())
+ #
+ # here, then we get a strange failure when deepcopying
+ # ComponentSets containing an _ImplicitAny domain. We could
+ # track it down to the implementation of
+ # autoslots.fast_deepcopy, but couldn't find an obvious bug.
+ # There is no error if we just return the original dict, or if
+ # we return a tuple(val.values)
+ return val
+ else:
+ # object id() may have changed after unpickling,
+ # so we rebuild the dictionary keys
+ return {_hasher[obj.__class__](obj): obj for obj in val.values()}
+
-class ComponentSet(collections_MutableSet):
+class ComponentSet(AutoSlots.Mixin, collections_MutableSet):
"""
This class is a replacement for set that allows Pyomo
modeling components to be used as entries. The
@@ -38,47 +60,34 @@ class ComponentSet(collections_MutableSet):
"""
__slots__ = ("_data",)
+ __autoslot_mappers__ = {'_data': _rehash_keys}
+ # Expose a "public" interface to the global _hasher dict
+ hasher = _hasher
- def __init__(self, *args):
- self._data = dict()
- if len(args) > 0:
- if len(args) > 1:
- raise TypeError(
- "%s expected at most 1 arguments, "
- "got %s" % (self.__class__.__name__, len(args))
- )
- self.update(args[0])
+ def __init__(self, iterable=None):
+ # maps id_hash(obj) -> obj
+ self._data = {}
+ if iterable is not None:
+ self.update(iterable)
def __str__(self):
"""String representation of the mapping."""
- tmp = []
- for objid, obj in self._data.items():
- tmp.append(str(obj) + " (id=" + str(objid) + ")")
- return "ComponentSet(" + str(tmp) + ")"
+ tmp = [f"{v} (key={k})" for k, v in self._data.items()]
+ return f"ComponentSet({tmp})"
- def update(self, args):
+ def update(self, iterable):
"""Update a set with the union of itself and others."""
- self._data.update((id(obj), obj) for obj in args)
-
- #
- # This method must be defined for deepcopy/pickling
- # because this class relies on Python ids.
- #
- def __setstate__(self, state):
- # object id() may have changed after unpickling,
- # so we rebuild the dictionary keys
- assert len(state) == 1
- self._data = {id(obj): obj for obj in state['_data']}
-
- def __getstate__(self):
- return {'_data': tuple(self._data.values())}
+ if isinstance(iterable, ComponentSet):
+ self._data.update(iterable._data)
+ else:
+ self._data.update((_hasher[val.__class__](val), val) for val in iterable)
#
# Implement MutableSet abstract methods
#
def __contains__(self, val):
- return self._data.__contains__(id(val))
+ return _hasher[val.__class__](val) in self._data
def __iter__(self):
return iter(self._data.values())
@@ -88,27 +97,26 @@ def __len__(self):
def add(self, val):
"""Add an element."""
- self._data[id(val)] = val
+ self._data[_hasher[val.__class__](val)] = val
def discard(self, val):
"""Remove an element. Do not raise an exception if absent."""
- if id(val) in self._data:
- del self._data[id(val)]
+ _id = _hasher[val.__class__](val)
+ if _id in self._data:
+ del self._data[_id]
#
# Overload MutableSet default implementations
#
- # We want to avoid generating Pyomo expressions due to
- # comparison of values, so we convert both objects to a
- # plain dictionary mapping key->(type(val), id(val)) and
- # compare that instead.
def __eq__(self, other):
if self is other:
return True
if not isinstance(other, collections_Set):
return False
- return len(self) == len(other) and all(id(key) in self._data for key in other)
+ return len(self) == len(other) and all(
+ _hasher[val.__class__](val) in self._data for val in other
+ )
def __ne__(self, other):
return not (self == other)
@@ -125,6 +133,7 @@ def clear(self):
def remove(self, val):
"""Remove an element. If not a member, raise a KeyError."""
try:
- del self._data[id(val)]
+ del self._data[_hasher[val.__class__](val)]
except KeyError:
- raise KeyError("Component with id '%s': %s" % (id(val), str(val)))
+ _id = _hasher[val.__class__](val)
+ raise KeyError(f"{val} (key={_id})") from None
diff --git a/pyomo/common/collections/orderedset.py b/pyomo/common/collections/orderedset.py
index 448939c8822..834101e3896 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,42 +9,30 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
-from collections.abc import MutableSet
from collections import OrderedDict
+from collections.abc import MutableSet
+from pyomo.common.autoslots import AutoSlots
-class OrderedSet(MutableSet):
+class OrderedSet(AutoSlots.Mixin, MutableSet):
__slots__ = ('_dict',)
def __init__(self, iterable=None):
- # TODO: Starting in Python 3.7, dict is ordered (and is faster
- # than OrderedDict). dict began supporting reversed() in 3.8.
- # We should consider changing the underlying data type here from
- # OrderedDict to dict.
- self._dict = OrderedDict()
+ # Starting in Python 3.7, dict is ordered (and is faster than
+ # OrderedDict). dict began supporting reversed() in 3.8.
+ self._dict = {}
if iterable is not None:
- if iterable.__class__ is OrderedSet:
- self._dict.update(iterable._dict)
- else:
- self.update(iterable)
+ self.update(iterable)
def __str__(self):
"""String representation of the mapping."""
return "OrderedSet(%s)" % (', '.join(repr(x) for x in self))
def update(self, iterable):
- for val in iterable:
- self.add(val)
-
- #
- # This method must be defined for deepcopy/pickling
- # because this class is slotized.
- #
- def __setstate__(self, state):
- self._dict = state
-
- def __getstate__(self):
- return self._dict
+ if isinstance(iterable, OrderedSet):
+ self._dict.update(iterable._dict)
+ else:
+ self._dict.update((val, None) for val in iterable)
#
# Implement MutableSet abstract methods
diff --git a/pyomo/common/config.py b/pyomo/common/config.py
index 15f15872fc6..ddeac28e521 100644
--- a/pyomo/common/config.py
+++ b/pyomo/common/config.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
@@ -39,10 +39,9 @@
deprecation_warning,
relocated_module_attribute,
)
-from pyomo.common.errors import DeveloperError
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__)
@@ -299,7 +298,71 @@ 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):
+ """
+ Domain validator for type checking.
+
+ Parameters
+ ----------
+ *bases : tuple of type
+ Valid types.
+ document_full_base_names : bool, optional
+ True to prepend full module qualifier to the name of each
+ member of `bases` in ``self.domain_name()`` and/or any
+ error messages generated by this object, False otherwise.
+ """
+
+ def __init__(self, *bases, document_full_base_names=False):
+ assert bases
+ self.baseClasses = bases
+ self.document_full_base_names = document_full_base_names
+
+ @staticmethod
+ def _fullname(klass):
+ """
+ Get full name of class, including appropriate module qualifier.
+ """
+ module_name = klass.__module__
+ module_qual = "" if module_name == "builtins" else f"{module_name}."
+ return f"{module_qual}{klass.__name__}"
+
+ def _get_class_name(self, klass):
+ """
+ Get name of class. Module qualifier may be included,
+ depending on value of `self.document_full_base_names`.
+ """
+ if self.document_full_base_names:
+ return self._fullname(klass)
+ else:
+ return klass.__name__
+
+ def __call__(self, obj):
+ if isinstance(obj, self.baseClasses):
+ return obj
+ if len(self.baseClasses) > 1:
+ class_names = ", ".join(
+ f"{self._get_class_name(kls)!r}" for kls in self.baseClasses
+ )
+ msg = (
+ "Expected an instance of one of these types: "
+ f"{class_names}, but received value {obj!r} of type "
+ f"{self._get_class_name(type(obj))!r}"
+ )
+ else:
+ msg = (
+ f"Expected an instance of "
+ f"{self._get_class_name(self.baseClasses[0])!r}, "
+ f"but received value {obj!r} of type "
+ f"{self._get_class_name(type(obj))!r}"
+ )
+ raise ValueError(msg)
+
+ def domain_name(self):
+ class_names = (_domain_name(kls) for kls in self.baseClasses)
+ return f"IsInstance[{', '.join(class_names)}]"
class ListOf(object):
@@ -379,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
"""
@@ -424,9 +486,14 @@ def __call__(self, module_id):
class Path(object):
- """Domain validator for path-like options.
+ """
+ Domain validator for a
+ :py:term:`path-like object `.
- This will admit any object and convert it to a string. It will then
+ This will admit a path-like object
+ and get the object's file system representation
+ through :py:obj:`os.fsdecode`.
+ It will then
expand any environment variables and leading usernames (e.g.,
"~myuser" or "~/") appearing in either the value or the base path
before concatenating the base path and value, expanding the path to
@@ -454,7 +521,7 @@ def __init__(self, basePath=None, expandPath=None):
self.expandPath = expandPath
def __call__(self, path):
- path = str(path)
+ path = os.fsdecode(path)
_expand = self.expandPath
if _expand is None:
_expand = not Path.SuppressPathExpansion
@@ -465,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 = ""
@@ -489,14 +556,21 @@ def __call__(self, path):
)
return ans
+ def domain_name(self):
+ return _domain_name(type(self))
+
class PathList(Path):
- """Domain validator for a list of path-like objects.
+ """
+ Domain validator for a list of
+ :py:term:`path-like objects `.
- This will admit any iterable or object convertible to a string.
- Iterable objects (other than strings) will have each member
- normalized using :py:class:`Path`. Other types will be passed to
- :py:class:`Path`, returning a list with the single resulting path.
+ This admits a path-like object or iterable of such.
+ If a path-like object is passed, then
+ a singleton list containing the object normalized through
+ :py:class:`Path` is returned.
+ An iterable of path-like objects is cast to a list, each
+ entry of which is normalized through :py:class:`Path`.
Parameters
----------
@@ -513,7 +587,8 @@ class PathList(Path):
"""
def __call__(self, data):
- if hasattr(data, "__iter__") and not isinstance(data, str):
+ is_path_like = isinstance(data, (str, bytes)) or hasattr(data, "__fspath__")
+ if hasattr(data, "__iter__") and not is_path_like:
return [super(PathList, self).__call__(i) for i in data]
else:
return [super(PathList, self).__call__(data)]
@@ -537,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
@@ -623,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
@@ -709,6 +792,7 @@ def from_enum_or_string(cls, arg):
NonNegativeFloat
In
InEnum
+ IsInstance
ListOf
Module
Path
@@ -805,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
@@ -868,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::
@@ -919,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
@@ -1028,14 +1105,19 @@ class will still create ``c`` instances that only have the single
def _dump(*args, **kwds):
+ # TODO: Change the default behavior to no longer be YAML.
+ # This was a legacy decision that may no longer be the best
+ # decision, given changes to technology over the years.
try:
- from yaml import dump
+ from yaml import safe_dump as dump
except ImportError:
# dump = lambda x,**y: str(x)
# YAML uses lowercase True/False
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()
@@ -1053,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
@@ -1088,15 +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:
- _str += _dump(_data, default_flow_style=True).rstrip()
+ 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
+ ).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()
@@ -1104,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()
@@ -1119,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
@@ -1401,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}'
),
],
)
@@ -1434,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())
@@ -1578,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',
@@ -1608,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:
@@ -1632,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.
@@ -1670,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:
@@ -1686,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:
@@ -1754,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
@@ -2085,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):
@@ -2107,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):
@@ -2132,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
+
+ 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:
- Now, config.a and config.b cannot be changed. To make them mutable again,
+ .. 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):
@@ -2151,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:
@@ -2213,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)
@@ -2270,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
@@ -2349,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.
@@ -2383,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,
@@ -2411,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
@@ -2463,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
@@ -2484,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)
@@ -2682,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 0a179b5c2de..68a6ed79d59 100644
--- a/pyomo/common/dependencies.py
+++ b/pyomo/common/dependencies.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,49 @@ 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')
+ 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 2e39083770d..50ad43ff1f8 100644
--- a/pyomo/common/deprecation.py
+++ b/pyomo/common/deprecation.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 79d5302a58e..30e048f37fc 100644
--- a/pyomo/common/download.py
+++ b/pyomo/common/download.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..cb9f2b6d9c6
--- /dev/null
+++ b/pyomo/common/enums.py
@@ -0,0 +1,212 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 __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 2ce0f368b9e..a6b94a48622 100644
--- a/pyomo/common/env.py
+++ b/pyomo/common/env.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 d74cb764641..1f933d4b08c 100644
--- a/pyomo/common/envvar.py
+++ b/pyomo/common/envvar.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 17013ce4dca..3c82f2b07c1 100644
--- a/pyomo/common/errors.py
+++ b/pyomo/common/errors.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e4f7b047bb3..0ac27f125a7 100644
--- a/pyomo/common/extensions.py
+++ b/pyomo/common/extensions.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 6a97759c714..c449cf826b4 100644
--- a/pyomo/common/factory.py
+++ b/pyomo/common/factory.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 557901c401e..d6d20a53950 100644
--- a/pyomo/common/fileutils.py
+++ b/pyomo/common/fileutils.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..6a3b0a98c93
--- /dev/null
+++ b/pyomo/common/flags.py
@@ -0,0 +1,139 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 5c2b329ce21..430ec96ca09 100644
--- a/pyomo/common/formatting.py
+++ b/pyomo/common/formatting.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 54fbca32736..751eb95cf18 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 5243758a0de..96fab8623b3 100644
--- a/pyomo/common/gsl.py
+++ b/pyomo/common/gsl.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 3097fe1c6de..6810c1ee123 100644
--- a/pyomo/common/log.py
+++ b/pyomo/common/log.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,21 +28,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 +234,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 +272,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.
@@ -289,13 +294,15 @@ class LoggingIntercept(object):
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()
+ 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'
"""
@@ -333,8 +340,8 @@ def __exit__(self, et, ev, tb):
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])
class LogStream(io.TextIOBase):
diff --git a/pyomo/common/modeling.py b/pyomo/common/modeling.py
index 5ecc56cce9b..5839e97544d 100644
--- a/pyomo/common/modeling.py
+++ b/pyomo/common/modeling.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 415d8aaba7e..a2dace2be0f 100644
--- a/pyomo/common/multithread.py
+++ b/pyomo/common/multithread.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 defaultdict
from threading import get_ident, main_thread
diff --git a/pyomo/common/numeric_types.py b/pyomo/common/numeric_types.py
index 19718b308b6..52dd9ec7f5c 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 67960ebbb12..75b8657d1a9 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 7db8077855a..ed44f8bf776 100644
--- a/pyomo/common/plugins.py
+++ b/pyomo/common/plugins.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 64ab2ddafc9..22ec3480842 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 5054fd21279..a96a6bc04fc 100644
--- a/pyomo/common/shutdown.py
+++ b/pyomo/common/shutdown.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 atexit
diff --git a/pyomo/common/sorting.py b/pyomo/common/sorting.py
index 31e796c6a9e..4f78a7892b8 100644
--- a/pyomo/common/sorting.py
+++ b/pyomo/common/sorting.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 029d66f5767..db3ab9ea2f8 100644
--- a/pyomo/common/tee.py
+++ b/pyomo/common/tee.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
@@ -50,6 +50,32 @@
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 redirect_fd(object):
"""Redirect a file descriptor to a new file or file descriptor.
@@ -90,9 +116,9 @@ 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()
self.original_file = getattr(sys, self.std)
+ # important: flush the current file buffer when redirecting
+ self.original_file.flush()
# Duplicate the original standard file descriptor(file
# descriptor 1 or 2) to a different file descriptor number
self.original_fd = os.dup(self.fd)
@@ -109,7 +135,7 @@ def __enter__(self):
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:
@@ -152,10 +178,33 @@ 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, 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 low-level file descriptors
+ associated with stdout (1) and stderr (2) to the ``output``.
+ This is useful for capturing output emitted directly to the
+ process stdout / stderr by external compiled modules.
+
+ Returns
+ -------
+ io.TextIOBase
+
+ This is the output stream object where all data is sent.
+
"""
def __init__(self, output=None, capture_fd=False):
@@ -169,19 +218,22 @@ def __init__(self, output=None, capture_fd=False):
self.fd_redirect = None
def __enter__(self):
+ self.old = (sys.stdout, sys.stderr)
if isinstance(self.output, str):
self.output_stream = open(self.output, 'w')
else:
self.output_stream = self.output
- self.old = (sys.stdout, sys.stderr)
- self.tee = TeeStream(self.output_stream)
+ if isinstance(self.output, TeeStream):
+ self.tee = self.output
+ else:
+ self.tee = TeeStream(self.output_stream)
self.tee.__enter__()
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()),
+ redirect_fd(1, self.tee.STDOUT.fileno(), synchronize=False),
+ redirect_fd(2, self.tee.STDERR.fileno(), synchronize=False),
)
self.fd_redirect[0].__enter__()
self.fd_redirect[1].__enter__()
@@ -220,6 +272,7 @@ class _StreamHandle(object):
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 +286,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
@@ -268,9 +328,7 @@ def close(self):
def finalize(self, ostreams):
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:
@@ -307,10 +365,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:]
@@ -320,13 +378,15 @@ def writeOutputBuffer(self, ostreams):
if not ostring:
return
- for stream in ostreams:
+ for local_stream, user_stream in ostreams:
try:
- written = stream.write(ostring)
+ written = local_stream.write(ostring)
except:
written = 0
- if written and not self.buffering:
- stream.flush()
+ if flush or (written and not self.buffering):
+ local_stream.flush()
+ if local_stream is not user_stream:
+ user_stream.flush()
# 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
@@ -335,30 +395,47 @@ def writeOutputBuffer(self, ostreams):
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:])
+ "the output buffer:\n\t%r" % (local_stream, ostring[written:])
)
class TeeStream(object):
- def __init__(self, *ostreams, encoding=None):
- self.ostreams = ostreams
+ def __init__(self, *ostreams, encoding=None, buffering=-1):
+ self.ostreams = []
self.encoding = encoding
+ self.buffering = buffering
self._stdout = None
self._stderr = None
self._handles = []
self._active_handles = []
self._threads = []
+ for user_stream in ostreams:
+ try:
+ fileno = user_stream.fileno()
+ except:
+ self.ostreams.append((user_stream, user_stream))
+ continue
+ local_stream = os.fdopen(
+ os.dup(fileno), mode=getattr(user_stream, 'mode', None), closefd=True
+ )
+ self.ostreams.append((local_stream, user_stream))
@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):
@@ -422,6 +499,9 @@ def close(self, in_exception=False):
self._active_handles.clear()
self._stdout = None
self._stderr = None
+ for local, orig in self.ostreams:
+ if orig is not local:
+ local.close()
def __enter__(self):
return self
@@ -454,15 +534,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 +559,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 +579,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 +590,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 +605,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 f51fad3f3ac..bd49bf21777 100644
--- a/pyomo/common/tempfiles.py
+++ b/pyomo/common/tempfiles.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 bc8dfa27c9c..d8d8856e52f 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ada788fd7d4..6aebc40806a 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 54530393783..34c7219c6eb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 8132e8a08ac..16936996eeb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e5236d0f7ec..5f8c1fffdf8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e19ad956044..73375bdc819 100644
--- a/pyomo/common/tests/import_ex.py
+++ b/pyomo/common/tests/import_ex.py
@@ -1,3 +1,15 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
+
+
def a():
pass
diff --git a/pyomo/contrib/parmest/ipopt_solver_wrapper.py b/pyomo/common/tests/mod.py
similarity index 75%
rename from pyomo/contrib/parmest/ipopt_solver_wrapper.py
rename to pyomo/common/tests/mod.py
index a6d5e0506fb..8e34e3dea54 100644
--- a/pyomo/contrib/parmest/ipopt_solver_wrapper.py
+++ b/pyomo/common/tests/mod.py
@@ -1,14 +1,17 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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
-from pyomo.common.deprecation import relocated_module
-relocated_module('pyomo.contrib.parmest.utils.ipopt_solver_wrapper', version='6.4.2')
+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..fdc017cb10e
--- /dev/null
+++ b/pyomo/common/tests/moved.py
@@ -0,0 +1,17 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 20b0712e09b..4881caba671 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 1ef27681b66..0f59f3beebc 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 9de63e0cec9..90cb28c23ba 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 a8daf5a0071..8c10df83005 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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
new file mode 100644
index 00000000000..1dc246be350
--- /dev/null
+++ b/pyomo/common/tests/test_component_map.py
@@ -0,0 +1,111 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.unittest as unittest
+
+from pyomo.common.collections import ComponentMap, ComponentSet, DefaultComponentMap
+from pyomo.environ import ConcreteModel, Block, Var, Constraint
+
+
+class TestComponentMap(unittest.TestCase):
+ def test_tuple(self):
+ m = ConcreteModel()
+ m.v = Var()
+ m.c = Constraint(expr=m.v >= 0)
+ m.cm = cm = ComponentMap()
+
+ cm[(1, 2)] = 5
+ self.assertEqual(len(cm), 1)
+ self.assertIn((1, 2), cm)
+ self.assertEqual(cm[1, 2], 5)
+
+ cm[(1, 2)] = 50
+ self.assertEqual(len(cm), 1)
+ self.assertIn((1, 2), cm)
+ self.assertEqual(cm[1, 2], 50)
+
+ cm[(1, (2, m.v))] = 10
+ self.assertEqual(len(cm), 2)
+ self.assertIn((1, (2, m.v)), cm)
+ self.assertEqual(cm[1, (2, m.v)], 10)
+
+ cm[(1, (2, m.v))] = 100
+ self.assertEqual(len(cm), 2)
+ self.assertIn((1, (2, m.v)), cm)
+ self.assertEqual(cm[1, (2, m.v)], 100)
+
+ i = m.clone()
+ self.assertIn((1, 2), i.cm)
+ self.assertIn((1, (2, i.v)), i.cm)
+ self.assertNotIn((1, (2, i.v)), m.cm)
+ 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):
+ dcm = DefaultComponentMap(ComponentSet)
+
+ m = ConcreteModel()
+ m.x = Var()
+ m.b = Block()
+ m.b.y = Var()
+
+ self.assertEqual(len(dcm), 0)
+
+ dcm[m.x].add(m)
+ self.assertEqual(len(dcm), 1)
+ self.assertIn(m.x, dcm)
+ self.assertIn(m, dcm[m.x])
+
+ dcm[m.b.y].add(m.b)
+ self.assertEqual(len(dcm), 2)
+ self.assertIn(m.b.y, dcm)
+ self.assertNotIn(m, dcm[m.b.y])
+ self.assertIn(m.b, dcm[m.b.y])
+
+ dcm[m.b.y].add(m)
+ self.assertEqual(len(dcm), 2)
+ self.assertIn(m.b.y, dcm)
+ self.assertIn(m, dcm[m.b.y])
+ self.assertIn(m.b, dcm[m.b.y])
+
+ def test_no_default_factory(self):
+ dcm = DefaultComponentMap()
+
+ dcm['found'] = 5
+ self.assertEqual(len(dcm), 1)
+ self.assertIn('found', dcm)
+ self.assertEqual(dcm['found'], 5)
+
+ with self.assertRaisesRegex(KeyError, "'missing'"):
+ dcm["missing"]
diff --git a/pyomo/common/tests/test_config.py b/pyomo/common/tests/test_config.py
index 1b732d86c0a..88e0706ba05 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of Sandia, LLC
# Under the terms of Contract DE-NA0003525 with National Technology and
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
@@ -60,6 +60,7 @@ def yaml_load(arg):
NonPositiveFloat,
NonNegativeFloat,
In,
+ IsInstance,
ListOf,
Module,
Path,
@@ -87,6 +88,7 @@ def _display(obj, *args):
class GlobalClass(object):
"test class for test_known_types"
+
pass
@@ -448,12 +450,83 @@ class TestEnum(enum.Enum):
with self.assertRaisesRegex(ValueError, '.*invalid value'):
cfg.enum = 'ITEM_THREE'
+ def test_IsInstance(self):
+ c = ConfigDict()
+ c.declare("val", ConfigValue(None, IsInstance(int)))
+ c.val = 1
+ self.assertEqual(c.val, 1)
+ exc_str = (
+ "Expected an instance of 'int', but received value 2.4 of type 'float'"
+ )
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.val = 2.4
+
+ class TestClass:
+ def __repr__(self):
+ return f"{TestClass.__name__}()"
+
+ c.declare("val2", ConfigValue(None, IsInstance(TestClass)))
+ testinst = TestClass()
+ c.val2 = testinst
+ self.assertEqual(c.val2, testinst)
+ exc_str = (
+ r"Expected an instance of 'TestClass', "
+ "but received value 2.4 of type 'float'"
+ )
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.val2 = 2.4
+
+ c.declare(
+ "val3",
+ ConfigValue(
+ None, IsInstance(int, TestClass, document_full_base_names=True)
+ ),
+ )
+ self.assertRegex(c.get("val3").domain_name(), r"IsInstance\[int, TestClass\]")
+ c.val3 = 2
+ self.assertEqual(c.val3, 2)
+ exc_str = (
+ r"Expected an instance of one of these types: 'int', '.*\.TestClass'"
+ r", but received value 2.4 of type 'float'"
+ )
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.val3 = 2.4
+
+ c.declare(
+ "val4",
+ ConfigValue(
+ None, IsInstance(int, TestClass, document_full_base_names=False)
+ ),
+ )
+ self.assertEqual(c.get("val4").domain_name(), "IsInstance[int, TestClass]")
+ c.val4 = 2
+ self.assertEqual(c.val4, 2)
+ exc_str = (
+ r"Expected an instance of one of these types: 'int', 'TestClass'"
+ r", but received value 2.4 of type 'float'"
+ )
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.val4 = 2.4
+
def test_Path(self):
def norm(x):
if cwd[1] == ':' and x[0] == '/':
x = cwd[:2] + x
return x.replace('/', os.path.sep)
+ class ExamplePathLike:
+ def __init__(self, path_str_or_bytes):
+ self.path = path_str_or_bytes
+
+ def __fspath__(self):
+ return self.path
+
+ def __str__(self):
+ path_str = str(self.path)
+ return f"{type(self).__name__}({path_str})"
+
+ self.assertEqual(Path().domain_name(), "Path")
+
cwd = os.getcwd() + os.path.sep
c = ConfigDict()
@@ -462,12 +535,30 @@ def norm(x):
c.a = "/a/b/c"
self.assertTrue(os.path.sep in c.a)
self.assertEqual(c.a, norm('/a/b/c'))
+ c.a = b"/a/b/c"
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm('/a/b/c'))
+ c.a = ExamplePathLike("/a/b/c")
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm('/a/b/c'))
c.a = "a/b/c"
self.assertTrue(os.path.sep in c.a)
self.assertEqual(c.a, norm(cwd + 'a/b/c'))
+ c.a = b'a/b/c'
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm(cwd + 'a/b/c'))
+ c.a = ExamplePathLike('a/b/c')
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm(cwd + 'a/b/c'))
c.a = "${CWD}/a/b/c"
self.assertTrue(os.path.sep in c.a)
self.assertEqual(c.a, norm(cwd + 'a/b/c'))
+ c.a = b'${CWD}/a/b/c'
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm(cwd + 'a/b/c'))
+ c.a = ExamplePathLike('${CWD}/a/b/c')
+ self.assertTrue(os.path.sep in c.a)
+ self.assertEqual(c.a, norm(cwd + 'a/b/c'))
c.a = None
self.assertIs(c.a, None)
@@ -476,12 +567,30 @@ def norm(x):
c.b = "/a/b/c"
self.assertTrue(os.path.sep in c.b)
self.assertEqual(c.b, norm('/a/b/c'))
+ c.b = b"/a/b/c"
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm('/a/b/c'))
+ c.b = ExamplePathLike("/a/b/c")
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm('/a/b/c'))
c.b = "a/b/c"
self.assertTrue(os.path.sep in c.b)
self.assertEqual(c.b, norm(cwd + 'rel/path/a/b/c'))
+ c.b = b"a/b/c"
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm(cwd + 'rel/path/a/b/c'))
+ c.b = ExamplePathLike("a/b/c")
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm(cwd + "rel/path/a/b/c"))
c.b = "${CWD}/a/b/c"
self.assertTrue(os.path.sep in c.b)
self.assertEqual(c.b, norm(cwd + 'a/b/c'))
+ c.b = b"${CWD}/a/b/c"
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm(cwd + 'a/b/c'))
+ c.b = ExamplePathLike("${CWD}/a/b/c")
+ self.assertTrue(os.path.sep in c.b)
+ self.assertEqual(c.b, norm(cwd + 'a/b/c'))
c.b = None
self.assertIs(c.b, None)
@@ -490,12 +599,30 @@ def norm(x):
c.c = "/a/b/c"
self.assertTrue(os.path.sep in c.c)
self.assertEqual(c.c, norm('/a/b/c'))
+ c.c = b"/a/b/c"
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm('/a/b/c'))
+ c.c = ExamplePathLike("/a/b/c")
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm('/a/b/c'))
c.c = "a/b/c"
self.assertTrue(os.path.sep in c.c)
self.assertEqual(c.c, norm('/my/dir/a/b/c'))
+ c.c = b"a/b/c"
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm('/my/dir/a/b/c'))
+ c.c = ExamplePathLike("a/b/c")
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm("/my/dir/a/b/c"))
c.c = "${CWD}/a/b/c"
self.assertTrue(os.path.sep in c.c)
self.assertEqual(c.c, norm(cwd + 'a/b/c'))
+ c.c = b"${CWD}/a/b/c"
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm(cwd + 'a/b/c'))
+ c.c = ExamplePathLike("${CWD}/a/b/c")
+ self.assertTrue(os.path.sep in c.c)
+ self.assertEqual(c.c, norm(cwd + 'a/b/c'))
c.c = None
self.assertIs(c.c, None)
@@ -505,12 +632,30 @@ def norm(x):
c.d = "/a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm('/a/b/c'))
+ c.d = b"/a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm('/a/b/c'))
+ c.d = ExamplePathLike("/a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm('/a/b/c'))
c.d = "a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = b"a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = ExamplePathLike("a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
c.d = "${CWD}/a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = b"${CWD}/a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = ExamplePathLike("${CWD}/a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
c.d_base = '/my/dir'
c.d = "/a/b/c"
@@ -527,12 +672,30 @@ def norm(x):
c.d = "/a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm('/a/b/c'))
+ c.d = b"/a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm('/a/b/c'))
+ c.d = ExamplePathLike("/a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm('/a/b/c'))
c.d = "a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm(cwd + 'rel/path/a/b/c'))
+ c.d = b"a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'rel/path/a/b/c'))
+ c.d = ExamplePathLike("a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'rel/path/a/b/c'))
c.d = "${CWD}/a/b/c"
self.assertTrue(os.path.sep in c.d)
self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = b"${CWD}/a/b/c"
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
+ c.d = ExamplePathLike("${CWD}/a/b/c")
+ self.assertTrue(os.path.sep in c.d)
+ self.assertEqual(c.d, norm(cwd + 'a/b/c'))
try:
Path.SuppressPathExpansion = True
@@ -540,14 +703,38 @@ def norm(x):
self.assertTrue('/' in c.d)
self.assertTrue('\\' not in c.d)
self.assertEqual(c.d, '/a/b/c')
+ c.d = b"/a/b/c"
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, '/a/b/c')
+ c.d = ExamplePathLike("/a/b/c")
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, '/a/b/c')
c.d = "a/b/c"
self.assertTrue('/' in c.d)
self.assertTrue('\\' not in c.d)
self.assertEqual(c.d, 'a/b/c')
+ c.d = b"a/b/c"
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, 'a/b/c')
+ c.d = ExamplePathLike("a/b/c")
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, 'a/b/c')
c.d = "${CWD}/a/b/c"
self.assertTrue('/' in c.d)
self.assertTrue('\\' not in c.d)
self.assertEqual(c.d, "${CWD}/a/b/c")
+ c.d = b"${CWD}/a/b/c"
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, "${CWD}/a/b/c")
+ c.d = ExamplePathLike("${CWD}/a/b/c")
+ self.assertTrue('/' in c.d)
+ self.assertTrue('\\' not in c.d)
+ self.assertEqual(c.d, "${CWD}/a/b/c")
finally:
Path.SuppressPathExpansion = False
@@ -560,6 +747,8 @@ def norm(x):
cwd = os.getcwd() + os.path.sep
c = ConfigDict()
+ self.assertEqual(PathList().domain_name(), "PathList")
+
c.declare('a', ConfigValue(None, PathList()))
self.assertEqual(c.a, None)
c.a = "/a/b/c"
@@ -582,6 +771,13 @@ def norm(x):
self.assertEqual(len(c.a), 0)
self.assertIs(type(c.a), list)
+ exc_str = r".*expected str, bytes or os.PathLike.*int"
+
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.a = 2
+ with self.assertRaisesRegex(ValueError, exc_str):
+ c.a = ["/a/b/c", 2]
+
def test_ListOf(self):
c = ConfigDict()
c.declare('a', ConfigValue(domain=ListOf(int), default=None))
@@ -978,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("#"):
@@ -1140,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):
@@ -1179,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:
@@ -1202,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:
@@ -1217,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
@@ -1229,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
@@ -1238,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]
@@ -1288,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]
@@ -1302,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]
@@ -1312,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]
@@ -1372,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]
@@ -1386,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]
@@ -1398,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")
@@ -1433,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")
@@ -1454,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': []}]}
)
@@ -1464,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")
@@ -1472,15 +1642,13 @@ 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})
+ self.assertEqual(yaml_load(test), {'bar': {'baz': None}, 'foo': 0})
@unittest.skipIf(not yaml_available, "Test requires PyYAML")
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")
@@ -1488,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):
@@ -1692,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()
@@ -1901,7 +2081,6 @@ def test_generate_custom_documentation(self):
"generate_documentation is deprecated.",
LOG,
)
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -1916,7 +2095,6 @@ def test_generate_custom_documentation(self):
)
)
self.assertEqual(LOG.getvalue(), "")
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -1962,7 +2140,6 @@ def test_generate_custom_documentation(self):
"generate_documentation is deprecated.",
LOG,
)
- self.maxDiff = None
# print(test)
self.assertEqual(test, reference)
@@ -2227,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:
@@ -2241,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:
@@ -2255,7 +2430,6 @@ def test_list_manipulation(self):
""",
)
test = _display(self.config['scenarios'])
- sys.stdout.write(test)
self.assertEqual(
test,
"""-
@@ -2380,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
@@ -2575,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):
@@ -2722,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):
@@ -2909,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()
@@ -2929,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
@@ -2947,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
@@ -2958,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."""
@@ -2968,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
@@ -2981,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
@@ -2992,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."""
@@ -3001,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.
@@ -3013,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.
@@ -3022,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)
@@ -3068,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 65058e01812..fc4af1af53b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 1fb4a471740..bd3ff24d0b8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 8c41edc1512..4ee781d5738 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..80d081505e9
--- /dev/null
+++ b/pyomo/common/tests/test_enums.py
@@ -0,0 +1,97 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 d14326ddc19..93802fc40bb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ec77643f722..67a200e84e3 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 63570774e5b..068360b55cb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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..b4436907c99
--- /dev/null
+++ b/pyomo/common/tests/test_flags.py
@@ -0,0 +1,49 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 d502c81da5a..29db26676ab 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 b2f23102a0e..176010b8d0d 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 39fab153e98..166e1e44cdb 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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)
diff --git a/pyomo/common/tests/test_modeling.py b/pyomo/common/tests/test_modeling.py
index 0684d77b2e9..553f71611a7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ae1bc48be44..fa1a46fa25f 100644
--- a/pyomo/common/tests/test_multithread.py
+++ b/pyomo/common/tests/test_multithread.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 threading
import pyomo.common.unittest as unittest
from pyomo.common.multithread import *
diff --git a/pyomo/common/tests/test_numeric_types.py b/pyomo/common/tests/test_numeric_types.py
new file mode 100644
index 00000000000..b7ffb5fb255
--- /dev/null
+++ b/pyomo/common/tests/test_numeric_types.py
@@ -0,0 +1,219 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 d87bebc1e4a..8f944e66bd7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 86d136dd9d1..54431334d5b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 7a9fe5ac923..7fbefda6a19 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 666a431631f..e3740e39604 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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,10 @@
# This software is distributed under the 3-clause BSD License.
# ___________________________________________________________________________
+import gc
+import itertools
import os
+import platform
import time
import sys
@@ -22,7 +25,60 @@
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():
+ self.buf.append((time.time(), float(line.strip())))
+
+ 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()
@@ -56,7 +112,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 +132,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()
@@ -183,6 +272,9 @@ class MockStream(object):
def write(self, data):
time.sleep(0.2)
+ 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
@@ -203,6 +295,216 @@ def write(self, data):
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)]]
+ if fd:
+ # TODO: [JDS] If we are capturing the file descriptor, the
+ # stdout channel is sometimes 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.
+ baseline.append([(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):
self.out = sys.stdout
diff --git a/pyomo/common/tests/test_tempfile.py b/pyomo/common/tests/test_tempfile.py
index 5e75c55305a..c49aa8c6771 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 d885359e6c6..fdf6217dddf 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 982462f8a8d..e65effe7f29 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e3779e6f86e..cd81a08fd2b 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 b37570fa666..32c3b269dd4 100644
--- a/pyomo/common/timing.py
+++ b/pyomo/common/timing.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 1ed26f72320..899bd74912b 100644
--- a/pyomo/common/unittest.py
+++ b/pyomo/common/unittest.py
@@ -1,7 +1,7 @@
# ___________________________________________________________________________
#
# Pyomo: Python Optimization Modeling Objects
-# Copyright (c) 2008-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e69de29bb2d..83d661830ba 100644
--- a/pyomo/contrib/__init__.py
+++ b/pyomo/contrib/__init__.py
@@ -0,0 +1,25 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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..0b01e359879
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/__init__.py
@@ -0,0 +1,20 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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..23c31f3874a
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/aos_utils.py
@@ -0,0 +1,304 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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(pe.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 = pe.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 = pe.Constraint(
+ expr=objective_expr <= objective_cutoff
+ )
+ else:
+ aos_block.optimality_tol_rel = pe.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 = pe.Constraint(
+ expr=objective_expr <= objective_cutoff
+ )
+ else:
+ aos_block.optimality_tol_abs = pe.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 = (pe.Objective, pe.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 == pe.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 == pe.Block
+ ):
+ block = comp[0]
+ descend_into = pe.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 = pe.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 == pe.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..5331c3de07b
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/balas.py
@@ -0,0 +1,258 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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 pe.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 = pe.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 = pe.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 = pe.Objective(expr=expr, sense=pe.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 = pe.Objective(expr=expr, sense=pe.maximize)
+
+ results = opt.solve(model, tee=tee, load_solutions=False)
+ status = results.solver.status
+ condition = results.solver.termination_condition
+ if pe.check_optimal_termination(results):
+ model.solutions.load_from(results)
+ orig_obj_value = pe.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 == pe.TerminationCondition.infeasibleOrUnbounded
+ or condition == pe.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..3021887b24c
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/lp_enum.py
@@ -0,0 +1,330 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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 = pe.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 = pe.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 = pe.Set(pe.PositiveIntegers)
+
+ # w variables
+ cb.basic_lower = pe.Var(pe.Any, domain=pe.Binary, dense=False)
+ cb.basic_upper = pe.Var(pe.Any, domain=pe.Binary, dense=False)
+ cb.basic_slack = pe.Var(pe.Any, domain=pe.Binary, dense=False)
+
+ # w upper bounds constraints (Eqn (3))
+ cb.bound_lower = pe.Constraint(pe.Any)
+ cb.bound_upper = pe.Constraint(pe.Any)
+ cb.bound_slack = pe.Constraint(pe.Any)
+
+ # non-zero basic variable no-good cut set
+ cb.cut_set = pe.Constraint(pe.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 = pe.Constraint(pe.Any)
+ # y variables
+ cb.basic_last_lower = pe.Var(pe.Any, domain=pe.Binary, dense=False)
+ cb.basic_last_upper = pe.Var(pe.Any, domain=pe.Binary, dense=False)
+ cb.basic_last_slack = pe.Var(pe.Any, domain=pe.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 = pe.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 == pe.TerminationCondition.infeasibleOrUnbounded
+ or condition == pe.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..5fa9739758e
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/lp_enum_solnpool.py
@@ -0,0 +1,235 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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 != pe.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 = pe.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 = pe.Var(lower_index, domain=pe.Binary)
+ cb.basic_upper = pe.Var(upper_index, domain=pe.Binary)
+ cb.basic_slack = pe.Var(cb.slack_index, domain=pe.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 = pe.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 = pe.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 = pe.Constraint(cb.slack_index, rule=bound_slack_rule)
+
+ cb.cl = pe.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..eb74d75a5db
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/obbt.py
@@ -0,0 +1,355 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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 = pe.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 = pe.TerminationCondition.optimal
+ infeas_or_unbdd_tc = pe.TerminationCondition.infeasibleOrUnbounded
+ unbdd_tc = pe.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 = pe.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 = pe.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 = pe.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 = pe.ComponentMap()
+ solns = [Solution(model, all_variables, objective=orig_objective)]
+
+ senses = [(pe.minimize, "LB"), (pe.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 = pe.value(var)
+ variable_bounds[var][idx] = obj_val
+
+ if refine_discrete_bounds and not var.is_continuous():
+ if sense == pe.minimize and var.lb < obj_val:
+ aos_block.bound_constraints.add(var >= obj_val)
+ new_constraint = True
+
+ if sense == pe.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 == pe.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(pe.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..2f3ae489ba4
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/shifted_lp.py
@@ -0,0 +1,229 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.Var(
+ new_vars.keys(), domain=pe.NonNegativeReals, bounds=var_range
+ )
+ shifted_lp.var_upper = pe.Var(
+ new_vars.keys(), domain=pe.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 = pe.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 = pe.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(pe.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 = pe.Set(initialize=new_constraints.keys())
+ shifted_lp.slack_index = pe.Set(initialize=slacks)
+ shifted_lp.slack_vars = pe.Var(shifted_lp.slack_index, domain=pe.NonNegativeReals)
+ shifted_lp.constraints = pe.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..2f82440c169
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/solnpool.py
@@ -0,0 +1,109 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
+
+import pyomo.environ as pe
+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..7b224e3089b
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/solution.py
@@ -0,0 +1,158 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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] = pe.value(var)
+
+ if objective is None:
+ objective = aos_utils.get_active_objective(model)
+ self.objective = (objective, pe.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/pyomo/contrib/alternative_solutions/tests/__init__.py b/pyomo/contrib/alternative_solutions/tests/__init__.py
new file mode 100644
index 00000000000..a4a626013c4
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/__init__.py
@@ -0,0 +1,10 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
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..625104fa56a
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_aos_utils.py
@@ -0,0 +1,300 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.ConcreteModel()
+ m.b1 = pe.Block()
+ m.b2 = pe.Block()
+ m.x = pe.Var()
+ m.y = pe.Var()
+ m.b1.o = pe.Objective(expr=m.x)
+ m.b2.o = pe.Objective([0, 1])
+ m.b2.o[0] = pe.Objective(expr=m.y)
+ m.b2.o[1] = pe.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, pe.Block)
+
+ def get_simple_model(self, sense=pe.minimize):
+ """Create a simple 2d linear program with an objective."""
+ m = pe.ConcreteModel()
+ m.x = pe.Var()
+ m.y = pe.Var()
+ m.o = pe.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=pe.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=pe.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 = pe.ConcreteModel()
+
+ m.b1 = pe.Block()
+ m.b2 = pe.Block()
+ m.b1.sb1 = pe.Block()
+ m.b2.sb2 = pe.Block()
+
+ m.x = pe.Var(domain=pe.Reals)
+ m.b1.y = pe.Var(domain=pe.Binary)
+ m.b2.z = pe.Var(domain=pe.Integers)
+
+ m.x_f = pe.Var(domain=pe.Reals)
+ m.b1.y_f = pe.Var(domain=pe.Binary)
+ m.b2.z_f = pe.Var(domain=pe.Integers)
+ m.x_f.fix(0)
+ m.b1.y_f.fix(0)
+ m.b2.z_f.fix(0)
+
+ m.b1.sb1.x_l = pe.Var(indices, domain=pe.Reals)
+ m.b1.sb1.y_l = pe.Var(indices, domain=pe.Binary)
+ m.b2.sb2.z_l = pe.Var(indices, domain=pe.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 = pe.Constraint(expr=sum(v for v in vars_minus_x) <= 1)
+ m.b1.con = pe.Constraint(expr=m.b1.y <= 1)
+ m.b1.sb1.con = pe.Constraint(expr=m.b1.sb1.y_l[0] <= 1)
+ m.obj = pe.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..27c3c7b014d
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_balas.py
@@ -0,0 +1,155 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
+
+import pyomo.environ as pe
+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..2cac807ca7e
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_cases.py
@@ -0,0 +1,438 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+
+"""
+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 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.Integers if discrete_x else pe.Reals, bounds=(-10, 10))
+ m.y = pe.Var(within=pe.Integers if discrete_y else pe.Reals, bounds=(-10, 10))
+
+ m.o = pe.Objective(expr=m.x + m.y, sense=pe.maximize)
+
+ m.c1 = pe.Constraint(expr=-4 / 5 * m.x - 4 <= m.y)
+ m.c2 = pe.Constraint(expr=5 / 9 * m.x - 5 <= m.y)
+ m.c3 = pe.Constraint(expr=2 / 9 * m.x + 2 >= m.y)
+ m.c4 = pe.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 = pe.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 = pe.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 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var([0, 1, 2], within=pe.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 = pe.Constraint([i for i in range(5)], rule=_constraint_switch_rule)
+
+ m.o = pe.Objective(expr=m.x[0] + m.x[2], sense=pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.Reals)
+ m.y = pe.Var(within=pe.Reals)
+
+ m.o = pe.Objective(expr=m.y - m.x)
+
+ m.c1 = pe.Constraint(expr=m.x <= 4)
+ m.c2 = pe.Constraint(expr=m.y >= 2)
+
+ m.extreme_points = {(4, 2)}
+
+ m.continuous_bounds = pe.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 = pe.ConcreteModel()
+
+ m.x = pe.Var(within=pe.Reals, bounds=(-1, 3))
+ m.y = pe.Var(within=pe.Reals, bounds=(-3, 2))
+
+ m.obj = pe.Objective(expr=m.x + 2 * m.y, sense=pe.maximize)
+
+ m.con1 = pe.Constraint(expr=m.x + m.y <= 3)
+ m.con2 = pe.Constraint(expr=m.x + 2 * m.y <= 5)
+ m.con3 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.NonNegativeIntegers, bounds=(0, var_max))
+ m.y = pe.Var(within=pe.NonNegativeIntegers, bounds=(0, var_max))
+
+ m.o = pe.Objective(expr=m.x + m.y, sense=pe.maximize)
+ m.c = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.NonNegativeIntegers, bounds=(0, 5))
+ m.y = pe.Var(within=pe.NonNegativeIntegers, bounds=(0, 5))
+ m.z = pe.Var(within=pe.NonNegativeIntegers, bounds=(0, 5))
+
+ m.o = pe.Objective(expr=m.x + m.z)
+
+ m.c1 = pe.Constraint(expr=m.x + m.y == 3)
+ m.c2 = pe.Constraint(expr=m.x + m.y + m.z <= 5)
+ m.c3 = pe.Constraint(expr=m.x + m.y + m.z >= 4)
+
+ m.var_bounds = pe.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 = pe.ConcreteModel()
+ m.i = pe.RangeSet(0, num_vars - 1)
+
+ if var_max == 1:
+ m.x = pe.Var(m.i, within=pe.Binary)
+ else:
+ m.x = pe.Var(m.i, within=pe.NonNegativeIntegers, bounds=(0, var_max))
+
+ m.o = pe.Objective(expr=sum(values[i] * m.x[i] for i in m.i), sense=pe.maximize)
+
+ m.c = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.Reals, bounds=(0, 2 * var_max))
+ m.y = pe.Var(within=pe.Reals, bounds=(0, 2 * var_max))
+ m.z = pe.Var(within=pe.NonNegativeReals, bounds=(0, 2 * var_max))
+ m.o = pe.Objective(expr=m.z, sense=pe.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 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.Integers, bounds=(-var_max, var_max))
+ m.y = pe.Var(within=pe.Integers, bounds=(-var_max, var_max))
+ m.z = pe.Var(within=pe.NonNegativeReals, bounds=(0, var_max))
+ m.o = pe.Objective(expr=m.z, sense=pe.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 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var([1, 2], within=pe.Integers, bounds=(-var_max, var_max))
+ m.z = pe.Var(within=pe.NonNegativeReals, bounds=(0, var_max))
+ m.o = pe.Objective(expr=m.z, sense=pe.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 = pe.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 = pe.ConcreteModel()
+ m.x = pe.Var(within=pe.Integers, bounds=(-2 * var_max, 2 * var_max))
+ m.y = pe.Var(within=pe.Integers, bounds=(-2 * var_max, var_max))
+ m.z = pe.Var(within=pe.NonNegativeReals, bounds=(0, 2 * var_max))
+ m.var_bounds = pe.ComponentMap()
+ m.o = pe.Objective(expr=m.z, sense=pe.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 = pe.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..d761522b019
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_lp_enum.py
@@ -0,0 +1,107 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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 = pe.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 = pe.minimize
+ n.x.domain = pe.Reals
+ n.y.domain = pe.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..ee9f4657acf
--- /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-2024
+# National Technology and Engineering Solutions of 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 pe
+
+# 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 = pe.Reals
+ n.y.domain = pe.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..d2b180c9e3d
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_obbt.py
@@ -0,0 +1,245 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.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..da17e537914
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_shifted_lp.py
@@ -0,0 +1,68 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.Reals
+
+ opt = pe.SolverFactory(lp_solver)
+ old_results = opt.solve(m, tee=False)
+ old_obj = pe.value(m.o)
+
+ new_model = shifted_lp.get_shifted_linear_model(m)
+ new_results = opt.solve(new_model, tee=False)
+ new_obj = pe.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 = pe.SolverFactory(lp_solver)
+ old_results = opt.solve(m, tee=False)
+ old_obj = pe.value(m.o)
+
+ new_model = shifted_lp.get_shifted_linear_model(m)
+ new_results = opt.solve(new_model, tee=False)
+ new_obj = pe.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..7e601906a69
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_solnpool.py
@@ -0,0 +1,144 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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
+import pyomo.environ as pe
+
+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..a3ef042b5fe
--- /dev/null
+++ b/pyomo/contrib/alternative_solutions/tests/test_solution.py
@@ -0,0 +1,93 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 pe
+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 = pe.ConcreteModel()
+ m.x = pe.Var(domain=pe.NonNegativeReals)
+ m.y = pe.Var(domain=pe.Binary)
+ m.z = pe.Var(domain=pe.NonNegativeIntegers)
+ m.f = pe.Var(domain=pe.Reals)
+
+ m.f.fix(1)
+ m.obj = pe.Objective(expr=m.x + m.y + m.z + m.f, sense=pe.maximize)
+
+ m.con_x = pe.Constraint(expr=m.x <= 1.5)
+ m.con_y = pe.Constraint(expr=m.y <= 1)
+ m.con_z = pe.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 = pe.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 e69de29bb2d..a4a626013c4 100644
--- a/pyomo/contrib/ampl_function_demo/__init__.py
+++ b/pyomo/contrib/ampl_function_demo/__init__.py
@@ -0,0 +1,10 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
diff --git a/pyomo/contrib/ampl_function_demo/build.py b/pyomo/contrib/ampl_function_demo/build.py
index cd35064ea4e..764a613b3d7 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 230d9c4b667..5a200174c43 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 ce2c1a60f82..67efc13d3c8 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/FindASL.cmake b/pyomo/contrib/ampl_function_demo/src/FindASL.cmake
index f413176f1cc..8bbc048fa6e 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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/functions.c b/pyomo/contrib/ampl_function_demo/src/functions.c
index f62148c995a..e87af745aea 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-2022
+ * Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 e69de29bb2d..a4a626013c4 100644
--- a/pyomo/contrib/ampl_function_demo/tests/__init__.py
+++ b/pyomo/contrib/ampl_function_demo/tests/__init__.py
@@ -0,0 +1,10 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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.
+# ___________________________________________________________________________
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 af52c2def9f..39890494d55 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 df3ba212448..2f06fc89e70 100644
--- a/pyomo/contrib/appsi/__init__.py
+++ b/pyomo/contrib/appsi/__init__.py
@@ -1,3 +1,14 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 . import base
from . import solvers
from . import writers
diff --git a/pyomo/contrib/appsi/base.py b/pyomo/contrib/appsi/base.py
index e6186eeedd2..b6b60ce2166 100644
--- a/pyomo/contrib/appsi/base.py
+++ b/pyomo/contrib/appsi/base.py
@@ -1,5 +1,20 @@
+# ___________________________________________________________________________
+#
+# Pyomo: Python Optimization Modeling Objects
+# Copyright (c) 2008-2024
+# National Technology and Engineering Solutions of 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 abc
import enum
+import os
+import re
+import weakref
+
from typing import (
Sequence,
Dict,
@@ -10,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,
@@ -36,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
@@ -86,6 +101,9 @@ class TerminationCondition(enum.Enum):
class SolverConfig(ConfigDict):
"""
+ Common configuration options for all APPSI solver interfaces
+
+
Attributes
----------
time_limit: float
@@ -135,6 +153,8 @@ def __init__(
class MIPSolverConfig(SolverConfig):
"""
+ Configuration options common to all MIP solvers
+
Attributes
----------
mip_gap: float
@@ -168,9 +188,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.
@@ -186,8 +204,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.
@@ -205,8 +223,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.
@@ -224,8 +242,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.
@@ -245,8 +263,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.
@@ -292,8 +310,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 '
@@ -308,8 +326,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 '
@@ -325,8 +343,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 '
@@ -342,8 +360,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 '
@@ -361,6 +379,8 @@ def get_reduced_costs(
class Results(object):
"""
+ Base class for all APPSI solver results
+
Attributes
----------
termination_condition: TerminationCondition
@@ -376,6 +396,8 @@ 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
@@ -418,6 +440,8 @@ def __str__(self):
class UpdateConfig(ConfigDict):
"""
+ Config options common to all persistent solvers
+
Attributes
----------
check_for_new_or_removed_constraints: bool
@@ -585,7 +609,7 @@ def __init__(
class Solver(abc.ABC):
- class Availability(enum.IntEnum):
+ class Availability(IntEnum):
NotFound = 0
BadVersion = -1
BadLicense = -2
@@ -610,20 +634,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
@@ -672,7 +696,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.
"""
@@ -697,9 +721,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.
@@ -715,13 +737,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.
@@ -741,8 +763,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
----------
@@ -760,8 +782,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
----------
@@ -788,43 +810,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
@@ -846,20 +868,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)
@@ -943,10 +965,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(
@@ -964,19 +986,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)
@@ -984,7 +1006,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)
@@ -993,14 +1015,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:
@@ -1023,10 +1045,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(
@@ -1043,10 +1065,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
@@ -1121,10 +1143,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:
@@ -1143,10 +1165,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:
@@ -1163,10 +1185,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)
@@ -1187,10 +1209,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)]
@@ -1235,10 +1257,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,
@@ -1323,12 +1345,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)
@@ -1356,40 +1378,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')
@@ -1518,7 +1513,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,
@@ -1654,7 +1649,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')
@@ -1662,7 +1657,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
@@ -1685,7 +1680,7 @@ def decorator(cls):
class LegacySolver(LegacySolverInterface, cls):
pass
- LegacySolverFactory.register(name, doc)(LegacySolver)
+ LegacySolverFactory.register('appsi_' + name, doc)(LegacySolver)
return cls
diff --git a/pyomo/contrib/appsi/build.py b/pyomo/contrib/appsi/build.py
index 2c8d02dd3ac..38f8cb713ca 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 9c276b518de..cc2aec28241 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-2022
+# Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 db9d3112069..5a838ffd786 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-2022
+ * Copyright (c) 2008-2024
# National Technology and Engineering Solutions of 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 255a0a3a70f..6f8002cb50e 100644
--- a/pyomo/contrib/appsi/cmodel/src/common.cpp
+++ b/pyomo/contrib/appsi/cmodel/src/common.cpp
@@ -1,3 +1,15 @@
+/**___________________________________________________________________________
+ *
+ * Pyomo: Python Optimization Modeling Objects
+ * Copyright (c) 2008-2024
+ * National Technology and Engineering Solutions of 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.
+ * ___________________________________________________________________________
+**/
+
#include "common.hpp"
double inf;
diff --git a/pyomo/contrib/appsi/cmodel/src/common.hpp b/pyomo/contrib/appsi/cmodel/src/common.hpp
index 36afd549116..9edc9571a4d 100644
--- a/pyomo/contrib/appsi/cmodel/src/common.hpp
+++ b/pyomo/contrib/appsi/cmodel/src/common.hpp
@@ -1,3 +1,15 @@
+/**___________________________________________________________________________
+ *
+ * Pyomo: Python Optimization Modeling Objects
+ * Copyright (c) 2008-2024
+ * National Technology and Engineering Solutions of 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.
+ * ___________________________________________________________________________
+**/
+
#include
#include
diff --git a/pyomo/contrib/appsi/cmodel/src/expression.cpp b/pyomo/contrib/appsi/cmodel/src/expression.cpp
index 1923d3a1894..a49d6f2e499 100644
--- a/pyomo/contrib/appsi/cmodel/src/expression.cpp
+++ b/pyomo/contrib/appsi/cmodel/src/expression.cpp
@@ -1,1970 +1,1986 @@
-#include "expression.hpp"
-
-bool Leaf::is_leaf() { return true; }
-
-bool Var::is_variable_type() { return true; }
-
-bool Param::is_param_type() { return true; }
-
-bool Constant::is_constant_type() { return true; }
-
-bool Expression::is_expression_type() { return true; }
-
-double Leaf::evaluate() { return value; }
-
-double Var::get_lb() {
- if (fixed)
- return value;
- else
- return std::max(lb->evaluate(), domain_lb);
-}
-
-double Var::get_ub() {
- if (fixed)
- return value;
- else
- return std::min(ub->evaluate(), domain_ub);
-}
-
-Domain Var::get_domain() { return domain; }
-
-bool Operator::is_operator_type() { return true; }
-
-std::vector> Expression::get_operators() {
- std::vector> res(n_operators);
- for (unsigned int i = 0; i < n_operators; ++i) {
- res[i] = operators[i];
- }
- return res;
-}
-
-double Leaf::get_value_from_array(double *val_array) { return value; }
-
-double Expression::get_value_from_array(double *val_array) {
- return val_array[n_operators - 1];
-}
-
-double Operator::get_value_from_array(double *val_array) {
- return val_array[index];
-}
-
-void MultiplyOperator::evaluate(double *values) {
- values[index] = operand1->get_value_from_array(values) *
- operand2->get_value_from_array(values);
-}
-
-void ExternalOperator::evaluate(double *values) {
- // It would be nice to implement this, but it will take some more work.
- // This would require dynamic linking to the external function.
- throw std::runtime_error("cannot evaluate ExternalOperator yet");
-}
-
-void LinearOperator::evaluate(double *values) {
- values[index] = constant->evaluate();
- for (unsigned int i = 0; i < nterms; ++i) {
- values[index] += coefficients[i]->evaluate() * variables[i]->evaluate();
- }
-}
-
-void SumOperator::evaluate(double *values) {
- values[index] = 0.0;
- for (unsigned int i = 0; i < nargs; ++i) {
- values[index] += operands[i]->get_value_from_array(values);
- }
-}
-
-void DivideOperator::evaluate(double *values) {
- values[index] = operand1->get_value_from_array(values) /
- operand2->get_value_from_array(values);
-}
-
-void PowerOperator::evaluate(double *values) {
- values[index] = std::pow(operand1->get_value_from_array(values),
- operand2->get_value_from_array(values));
-}
-
-void NegationOperator::evaluate(double *values) {
- values[index] = -operand->get_value_from_array(values);
-}
-
-void ExpOperator::evaluate(double *values) {
- values[index] = std::exp(operand->get_value_from_array(values));
-}
-
-void LogOperator::evaluate(double *values) {
- values[index] = std::log(operand->get_value_from_array(values));
-}
-
-void AbsOperator::evaluate(double *values) {
- values[index] = std::fabs(operand->get_value_from_array(values));
-}
-
-void SqrtOperator::evaluate(double *values) {
- values[index] = std::pow(operand->get_value_from_array(values), 0.5);
-}
-
-void Log10Operator::evaluate(double *values) {
- values[index] = std::log10(operand->get_value_from_array(values));
-}
-
-void SinOperator::evaluate(double *values) {
- values[index] = std::sin(operand->get_value_from_array(values));
-}
-
-void CosOperator::evaluate(double *values) {
- values[index] = std::cos(operand->get_value_from_array(values));
-}
-
-void TanOperator::evaluate(double *values) {
- values[index] = std::tan(operand->get_value_from_array(values));
-}
-
-void AsinOperator::evaluate(double *values) {
- values[index] = std::asin(operand->get_value_from_array(values));
-}
-
-void AcosOperator::evaluate(double *values) {
- values[index] = std::acos(operand->get_value_from_array(values));
-}
-
-void AtanOperator::evaluate(double *values) {
- values[index] = std::atan(operand->get_value_from_array(values));
-}
-
-double Expression::evaluate() {
- double *values = new double[n_operators];
- for (unsigned int i = 0; i < n_operators; ++i) {
- operators[i]->index = i;
- operators[i]->evaluate(values);
- }
- double res = get_value_from_array(values);
- delete[] values;
- return res;
-}
-
-void UnaryOperator::identify_variables(
- std::set> &var_set,
- std::shared_ptr>> var_vec) {
- if (operand->is_variable_type()) {
- if (var_set.count(operand) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(operand));
- var_set.insert(operand);
- }
- }
-}
-
-void BinaryOperator::identify_variables(
- std::set> &var_set,
- std::shared_ptr>> var_vec) {
- if (operand1->is_variable_type()) {
- if (var_set.count(operand1) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(operand1));
- var_set.insert(operand1);
- }
- }
- if (operand2->is_variable_type()) {
- if (var_set.count(operand2) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(operand2));
- var_set.insert(operand2);
- }
- }
-}
-
-void ExternalOperator::identify_variables(
- std::set> &var_set,
- std::shared_ptr>> var_vec) {
- for (unsigned int i = 0; i < nargs; ++i) {
- if (operands[i]->is_variable_type()) {
- if (var_set.count(operands[i]) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(operands[i]));
- var_set.insert(operands[i]);
- }
- }
- }
-}
-
-void LinearOperator::identify_variables(
- std::set> &var_set,
- std::shared_ptr>> var_vec) {
- for (unsigned int i = 0; i < nterms; ++i) {
- if (var_set.count(variables[i]) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(variables[i]));
- var_set.insert(variables[i]);
- }
- }
-}
-
-void SumOperator::identify_variables(
- std::set> &var_set,
- std::shared_ptr>> var_vec) {
- for (unsigned int i = 0; i < nargs; ++i) {
- if (operands[i]->is_variable_type()) {
- if (var_set.count(operands[i]) == 0) {
- var_vec->push_back(std::dynamic_pointer_cast(operands[i]));
- var_set.insert(operands[i]);
- }
- }
- }
-}
-
-std::shared_ptr>>
-Expression::identify_variables() {
- std::set> var_set;
- std::shared_ptr>> res =
- std::make_shared>>(var_set.size());
- for (unsigned int i = 0; i < n_operators; ++i) {
- operators[i]->identify_variables(var_set, res);
- }
- return res;
-}
-
-std::shared_ptr>> Var::identify_variables() {
- std::shared_ptr>> res =
- std::make_shared>>();
- res->push_back(shared_from_this());
- return res;
-}
-
-std::shared_ptr>>
-Constant::identify_variables() {
- std::shared_ptr>> res =
- std::make_shared>>();
- return res;
-}
-
-std::shared_ptr>> Param::identify_variables() {
- std::shared_ptr>> res =
- std::make_shared>>();
- return res;
-}
-
-std::shared_ptr>>
-Expression::identify_external_operators() {
- std::set> external_set;
- for (unsigned int i = 0; i < n_operators; ++i) {
- if (operators[i]->is_external_operator()) {
- external_set.insert(operators[i]);
- }
- }
- std::shared_ptr>> res =
- std::make_shared>>(
- external_set.size());
- int ndx = 0;
- for (std::shared_ptr n : external_set) {
- (*res)[ndx] = std::dynamic_pointer_cast(n);
- ndx += 1;
- }
- return res;
-}
-
-std::shared_ptr>>
-Var::identify_external_operators() {
- std::shared_ptr>> res =
- std::make_shared>>();
- return res;
-}
-
-std::shared_ptr>>
-Constant::identify_external_operators() {
- std::shared_ptr>> res =
- std::make_shared