Spaces:
Sleeping
Sleeping
Upload 3525 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +27 -0
- Dockerfile +18 -0
- README.md +27 -5
- app.py +45 -0
- pyomo/mcp_output/README_MCP.md +56 -0
- pyomo/mcp_output/analysis.json +0 -0
- pyomo/mcp_output/diff_report.md +65 -0
- pyomo/mcp_output/mcp_plugin/__init__.py +0 -0
- pyomo/mcp_output/mcp_plugin/adapter.py +94 -0
- pyomo/mcp_output/mcp_plugin/main.py +13 -0
- pyomo/mcp_output/mcp_plugin/mcp_service.py +82 -0
- pyomo/mcp_output/requirements.txt +8 -0
- pyomo/mcp_output/start_mcp.py +30 -0
- pyomo/mcp_output/workflow_summary.json +215 -0
- pyomo/source/.codecov.yml +25 -0
- pyomo/source/.coin-or/projDesc.xml +312 -0
- pyomo/source/.coveragerc +19 -0
- pyomo/source/.jenkins.sh +266 -0
- pyomo/source/.readthedocs.yaml +39 -0
- pyomo/source/CHANGELOG.md +0 -0
- pyomo/source/CITATION.cff +31 -0
- pyomo/source/CONTRIBUTING.md +33 -0
- pyomo/source/LICENSE.md +36 -0
- pyomo/source/MANIFEST.in +2 -0
- pyomo/source/README.md +110 -0
- pyomo/source/RELEASE.md +48 -0
- pyomo/source/__init__.py +4 -0
- pyomo/source/conftest.py +87 -0
- pyomo/source/doc/OnlineDocs/Makefile +36 -0
- pyomo/source/doc/OnlineDocs/README.md +70 -0
- pyomo/source/doc/OnlineDocs/_static/theme_overrides.css +101 -0
- pyomo/source/doc/OnlineDocs/_templates/layout.html +15 -0
- pyomo/source/doc/OnlineDocs/_templates/recursive-base.rst +18 -0
- pyomo/source/doc/OnlineDocs/_templates/recursive-class.rst +54 -0
- pyomo/source/doc/OnlineDocs/_templates/recursive-enum.rst +59 -0
- pyomo/source/doc/OnlineDocs/_templates/recursive-module.rst +105 -0
- pyomo/source/doc/OnlineDocs/code.rst +16 -0
- pyomo/source/doc/OnlineDocs/conf.py +455 -0
- pyomo/source/doc/OnlineDocs/contribution_guide.rst +435 -0
- pyomo/source/doc/OnlineDocs/docutils.conf +2 -0
- pyomo/source/doc/OnlineDocs/errors.rst +195 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/alternative_solutions.rst +234 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/communities_8pp.png +3 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/communities_decode_1.png +3 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/community.rst +396 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/doe/CCSI-license.txt +43 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png +3 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/doe/doe.rst +245 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/doe/flowchart.png +3 -0
- pyomo/source/doc/OnlineDocs/explanation/analysis/doe/grid-1.png +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,30 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
pyomo/source/doc/logos/coopr/CooprLogo6.ai filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
pyomo/source/doc/logos/coopr/CooprLogo6.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
pyomo/source/doc/logos/dae/Pyomo-DAE-2400-transparent.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
pyomo/source/doc/logos/dae/Pyomo-DAE-2400.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
pyomo/source/doc/logos/dae/Pyomo-DAE.eps filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
pyomo/source/doc/logos/dae/Pyomo-DAE.pdf filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
pyomo/source/doc/logos/doe/PyomoDoE-lg.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
pyomo/source/doc/logos/doe/PyomoDoE.ai filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
pyomo/source/doc/logos/doe/PyomoDoE.eps filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
pyomo/source/doc/logos/pyomo/favicon.ico filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
pyomo/source/doc/logos/pyomo/PyomoNewBlue.ai filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
pyomo/source/doc/logos/pyomo/PyomoNewBlue.jpg filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
pyomo/source/doc/logos/pysp/PySP-logo-forPrint.ai filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
pyomo/source/doc/logos/pysp/PySP-logo-forPrint.bmp filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
pyomo/source/doc/logos/pysp/PySP-logo-forPrint.pdf filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
pyomo/source/doc/logos/pysp/PySP-logo-forWeb.eps filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
pyomo/source/doc/logos/pysp/PySP-logo-v2.ai filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
pyomo/source/doc/logos/pysp/PySP-logo-v2.pdf filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/communities_8pp.png filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/communities_decode_1.png filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/flowchart.png filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/grid-1.png filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/reactor.png filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/uml.png filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
pyomo/source/doc/OnlineDocs/explanation/solvers/pyros/tutorial/por_heatmaps.png filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
pyomo/source/examples/pyomo/diet/diet.mdb filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.10
|
| 2 |
+
|
| 3 |
+
RUN useradd -m -u 1000 user && python -m pip install --upgrade pip
|
| 4 |
+
USER user
|
| 5 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
| 6 |
+
|
| 7 |
+
WORKDIR /app
|
| 8 |
+
|
| 9 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
| 10 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 11 |
+
|
| 12 |
+
COPY --chown=user . /app
|
| 13 |
+
ENV MCP_TRANSPORT=http
|
| 14 |
+
ENV MCP_PORT=7860
|
| 15 |
+
|
| 16 |
+
EXPOSE 7860
|
| 17 |
+
|
| 18 |
+
CMD ["python", "pyomo/mcp_output/start_mcp.py"]
|
README.md
CHANGED
|
@@ -1,10 +1,32 @@
|
|
| 1 |
---
|
| 2 |
-
title: Pyomo
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
|
|
|
|
|
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Pyomo MCP
|
| 3 |
+
emoji: 🤖
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: docker
|
| 7 |
+
sdk_version: "4.26.0"
|
| 8 |
+
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Pyomo MCP Service
|
| 13 |
+
|
| 14 |
+
Auto-generated MCP service for pyomo.
|
| 15 |
+
|
| 16 |
+
## Usage
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
https://None-pyomo-mcp.hf.space/mcp
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
## Connect with Cursor
|
| 23 |
+
|
| 24 |
+
```json
|
| 25 |
+
{
|
| 26 |
+
"mcpServers": {
|
| 27 |
+
"pyomo": {
|
| 28 |
+
"url": "https://None-pyomo-mcp.hf.space/mcp"
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
```
|
app.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import FastAPI
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
mcp_plugin_path = os.path.join(os.path.dirname(__file__), "pyomo", "mcp_output", "mcp_plugin")
|
| 6 |
+
sys.path.insert(0, mcp_plugin_path)
|
| 7 |
+
|
| 8 |
+
app = FastAPI(
|
| 9 |
+
title="Pyomo MCP Service",
|
| 10 |
+
description="Auto-generated MCP service for pyomo",
|
| 11 |
+
version="1.0.0"
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
@app.get("/")
|
| 15 |
+
def root():
|
| 16 |
+
return {
|
| 17 |
+
"service": "Pyomo MCP Service",
|
| 18 |
+
"version": "1.0.0",
|
| 19 |
+
"status": "running",
|
| 20 |
+
"transport": os.environ.get("MCP_TRANSPORT", "http")
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
@app.get("/health")
|
| 24 |
+
def health_check():
|
| 25 |
+
return {"status": "healthy", "service": "pyomo MCP"}
|
| 26 |
+
|
| 27 |
+
@app.get("/tools")
|
| 28 |
+
def list_tools():
|
| 29 |
+
try:
|
| 30 |
+
from mcp_service import create_app
|
| 31 |
+
mcp_app = create_app()
|
| 32 |
+
tools = []
|
| 33 |
+
for tool_name, tool_func in mcp_app.tools.items():
|
| 34 |
+
tools.append({
|
| 35 |
+
"name": tool_name,
|
| 36 |
+
"description": tool_func.__doc__ or "No description available"
|
| 37 |
+
})
|
| 38 |
+
return {"tools": tools}
|
| 39 |
+
except Exception as e:
|
| 40 |
+
return {"error": f"Failed to load tools: {str(e)}"}
|
| 41 |
+
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
import uvicorn
|
| 44 |
+
port = int(os.environ.get("PORT", 7860))
|
| 45 |
+
uvicorn.run(app, host="0.0.0.0", port=port)
|
pyomo/mcp_output/README_MCP.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pyomo MCP (Model Context Protocol) Service
|
| 2 |
+
|
| 3 |
+
## Project Introduction
|
| 4 |
+
|
| 5 |
+
Pyomo is a Python-based open-source software package designed to support a wide range of optimization capabilities. It allows users to define symbolic problems, create concrete problem instances, and solve these instances using both commercial and open-source solvers. Pyomo is versatile, supporting various optimization problem types such as linear programming, nonlinear programming, mixed-integer programming, and more. It integrates optimization modeling within Python, enabling complex analysis and transparent parallelization.
|
| 6 |
+
|
| 7 |
+
## Installation Method
|
| 8 |
+
|
| 9 |
+
To install Pyomo, ensure you have Python installed on your system. Pyomo requires several dependencies, including `numpy`, `scipy`, and `pyparsing`. Optional dependencies include `matplotlib` and `pandas` for enhanced functionality.
|
| 10 |
+
|
| 11 |
+
Install Pyomo using pip:
|
| 12 |
+
|
| 13 |
+
```
|
| 14 |
+
pip install pyomo
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
## Quick Start
|
| 18 |
+
|
| 19 |
+
To get started with Pyomo, you can define and solve a simple optimization model. Here is a basic example of how to create a model, define variables, constraints, and an objective, and then solve it using a solver like Gurobi or CPLEX.
|
| 20 |
+
|
| 21 |
+
1. Import Pyomo and create a model.
|
| 22 |
+
2. Define variables, constraints, and objectives.
|
| 23 |
+
3. Use the `SolverFactory` to solve the model.
|
| 24 |
+
|
| 25 |
+
Example:
|
| 26 |
+
|
| 27 |
+
```
|
| 28 |
+
from pyomo.environ import ConcreteModel, Var, Objective, Constraint, SolverFactory
|
| 29 |
+
|
| 30 |
+
model = ConcreteModel()
|
| 31 |
+
model.x = Var(domain=NonNegativeReals)
|
| 32 |
+
model.y = Var(domain=NonNegativeReals)
|
| 33 |
+
model.obj = Objective(expr=model.x + model.y)
|
| 34 |
+
model.constr = Constraint(expr=model.x + 2*model.y >= 1)
|
| 35 |
+
|
| 36 |
+
solver = SolverFactory('gurobi')
|
| 37 |
+
solver.solve(model)
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## Available Tools and Endpoints List
|
| 41 |
+
|
| 42 |
+
- **Core Modeling Framework**: Provides components for defining optimization models, including variables, constraints, objectives, and parameters.
|
| 43 |
+
- **Expression System**: Handles mathematical expressions within Pyomo models, including numeric and boolean expressions.
|
| 44 |
+
- **Solver Services**: Interfaces for integrating with various solvers, providing methods to solve optimization problems.
|
| 45 |
+
- **GDP Services**: Provides transformations for generalized disjunctive programming (GDP) models.
|
| 46 |
+
- **PyROS**: A robust optimization solver for handling uncertainty in optimization models.
|
| 47 |
+
|
| 48 |
+
## Common Issues and Notes
|
| 49 |
+
|
| 50 |
+
- **Dependencies**: Ensure all required dependencies are installed. Use `pip` to manage Python packages.
|
| 51 |
+
- **Environment**: Pyomo is compatible with Python 3.x. Ensure your environment is set up correctly.
|
| 52 |
+
- **Performance**: The performance of solving models can vary based on the complexity of the model and the solver used. Consider using commercial solvers like Gurobi or CPLEX for large-scale problems.
|
| 53 |
+
|
| 54 |
+
## Reference Links or Documentation
|
| 55 |
+
|
| 56 |
+
For more detailed information, visit the [Pyomo GitHub Repository](https://github.com/Pyomo/pyomo) or refer to the official [Pyomo Documentation](https://pyomo.readthedocs.io/). These resources provide comprehensive guides, examples, and API references to help you effectively use Pyomo for optimization modeling.
|
pyomo/mcp_output/analysis.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
pyomo/mcp_output/diff_report.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pyomo Project Difference Report
|
| 2 |
+
|
| 3 |
+
**Date:** February 4, 2026
|
| 4 |
+
**Time:** 12:42:51
|
| 5 |
+
**Repository:** Pyomo
|
| 6 |
+
**Project Type:** Python Library
|
| 7 |
+
**Main Features:** Basic Functionality
|
| 8 |
+
**Intrusiveness:** None
|
| 9 |
+
**Workflow Status:** Success
|
| 10 |
+
**Test Status:** Failed
|
| 11 |
+
|
| 12 |
+
## Project Overview
|
| 13 |
+
|
| 14 |
+
Pyomo is a Python-based open-source optimization modeling language that is widely used for formulating and analyzing mathematical models. It provides a flexible and extensible framework for defining optimization problems and supports a wide range of solvers.
|
| 15 |
+
|
| 16 |
+
## Difference Analysis
|
| 17 |
+
|
| 18 |
+
### Summary of Changes
|
| 19 |
+
|
| 20 |
+
- **New Files Added:** 8
|
| 21 |
+
- **Modified Files:** 0
|
| 22 |
+
|
| 23 |
+
The recent update to the Pyomo project involved the addition of eight new files. There were no modifications to existing files, indicating that the changes were likely focused on introducing new features or components rather than altering existing functionality.
|
| 24 |
+
|
| 25 |
+
### Workflow and Test Status
|
| 26 |
+
|
| 27 |
+
- **Workflow Status:** The workflow executed successfully, indicating that the integration and deployment processes were completed without errors.
|
| 28 |
+
- **Test Status:** The test suite failed, suggesting that the new additions may have introduced issues or that existing tests do not cover the new functionality adequately.
|
| 29 |
+
|
| 30 |
+
## Technical Analysis
|
| 31 |
+
|
| 32 |
+
### New Files
|
| 33 |
+
|
| 34 |
+
The introduction of eight new files suggests the addition of new modules or features. Without modifications to existing files, these new files might represent isolated components or extensions to the current capabilities of Pyomo.
|
| 35 |
+
|
| 36 |
+
### Potential Issues
|
| 37 |
+
|
| 38 |
+
- **Test Failures:** The failure in the test status indicates potential issues with the new files. This could be due to:
|
| 39 |
+
- Incomplete or incorrect implementation of new features.
|
| 40 |
+
- Lack of integration with existing components.
|
| 41 |
+
- Insufficient test coverage for the new additions.
|
| 42 |
+
|
| 43 |
+
## Recommendations and Improvements
|
| 44 |
+
|
| 45 |
+
1. **Review New Files:** Conduct a thorough review of the newly added files to ensure they meet the project's coding standards and integrate well with the existing codebase.
|
| 46 |
+
|
| 47 |
+
2. **Enhance Test Coverage:** Develop comprehensive test cases for the new features to ensure they function as expected and do not introduce regressions.
|
| 48 |
+
|
| 49 |
+
3. **Debug Test Failures:** Investigate the cause of the test failures and address any issues identified. This may involve debugging the new code or updating existing tests to accommodate new functionality.
|
| 50 |
+
|
| 51 |
+
4. **Documentation Update:** Ensure that the documentation is updated to reflect the new features, including usage examples and any changes to the API.
|
| 52 |
+
|
| 53 |
+
## Deployment Information
|
| 54 |
+
|
| 55 |
+
The successful workflow status indicates that the deployment process was completed without issues. However, given the test failures, it is advisable to hold off on deploying the new version to production until the issues are resolved.
|
| 56 |
+
|
| 57 |
+
## Future Planning
|
| 58 |
+
|
| 59 |
+
- **Stabilization Phase:** Focus on stabilizing the current release by addressing test failures and ensuring all new features are robust and well-documented.
|
| 60 |
+
- **Feature Expansion:** Plan for future enhancements based on user feedback and emerging needs in the optimization modeling community.
|
| 61 |
+
- **Community Engagement:** Engage with the Pyomo user community to gather feedback on the new features and identify areas for improvement.
|
| 62 |
+
|
| 63 |
+
## Conclusion
|
| 64 |
+
|
| 65 |
+
The recent update to the Pyomo project has introduced new capabilities through the addition of eight new files. However, the test failures highlight the need for further refinement and testing. By addressing these issues and enhancing test coverage, the project can ensure a stable and reliable release. Future efforts should focus on both stabilization and strategic feature expansion to maintain Pyomo's position as a leading optimization modeling tool.
|
pyomo/mcp_output/mcp_plugin/__init__.py
ADDED
|
File without changes
|
pyomo/mcp_output/mcp_plugin/adapter.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
# Path settings
|
| 5 |
+
source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
|
| 6 |
+
sys.path.insert(0, source_path)
|
| 7 |
+
|
| 8 |
+
# Import statements
|
| 9 |
+
try:
|
| 10 |
+
from pyomo.scripting.pyomo_command import solve as pyomo_solve
|
| 11 |
+
from pyomo.scripting.convert import convert as pyomo_convert
|
| 12 |
+
except ImportError as e:
|
| 13 |
+
print("Error importing Pyomo modules. Ensure Pyomo is correctly installed and available in the source path.")
|
| 14 |
+
raise e
|
| 15 |
+
|
| 16 |
+
class Adapter:
|
| 17 |
+
"""
|
| 18 |
+
Adapter class for interacting with Pyomo functionalities.
|
| 19 |
+
|
| 20 |
+
Attributes:
|
| 21 |
+
mode (str): The mode of operation, initialized to "import".
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
def __init__(self):
|
| 25 |
+
self.mode = "import"
|
| 26 |
+
|
| 27 |
+
# -------------------------------------------------------------------------
|
| 28 |
+
# Pyomo Solve Method
|
| 29 |
+
# -------------------------------------------------------------------------
|
| 30 |
+
|
| 31 |
+
def solve_model(self, model_file, solver='glpk', options=None):
|
| 32 |
+
"""
|
| 33 |
+
Solve a Pyomo model using the specified solver.
|
| 34 |
+
|
| 35 |
+
Parameters:
|
| 36 |
+
model_file (str): Path to the Pyomo model file.
|
| 37 |
+
solver (str): Solver to use for solving the model. Default is 'glpk'.
|
| 38 |
+
options (dict): Additional solver options.
|
| 39 |
+
|
| 40 |
+
Returns:
|
| 41 |
+
dict: A dictionary containing the status and results of the solve operation.
|
| 42 |
+
"""
|
| 43 |
+
try:
|
| 44 |
+
if options is None:
|
| 45 |
+
options = {}
|
| 46 |
+
result = pyomo_solve(model_file, solver=solver, options=options)
|
| 47 |
+
return {'status': 'success', 'result': result}
|
| 48 |
+
except Exception as e:
|
| 49 |
+
return {'status': 'error', 'message': str(e)}
|
| 50 |
+
|
| 51 |
+
# -------------------------------------------------------------------------
|
| 52 |
+
# Pyomo Convert Method
|
| 53 |
+
# -------------------------------------------------------------------------
|
| 54 |
+
|
| 55 |
+
def convert_model(self, model_file, output_format='lp'):
|
| 56 |
+
"""
|
| 57 |
+
Convert a Pyomo model to a different format.
|
| 58 |
+
|
| 59 |
+
Parameters:
|
| 60 |
+
model_file (str): Path to the Pyomo model file.
|
| 61 |
+
output_format (str): Desired output format. Default is 'lp'.
|
| 62 |
+
|
| 63 |
+
Returns:
|
| 64 |
+
dict: A dictionary containing the status and path to the converted file.
|
| 65 |
+
"""
|
| 66 |
+
try:
|
| 67 |
+
output_file = pyomo_convert(model_file, output_format=output_format)
|
| 68 |
+
return {'status': 'success', 'output_file': output_file}
|
| 69 |
+
except Exception as e:
|
| 70 |
+
return {'status': 'error', 'message': str(e)}
|
| 71 |
+
|
| 72 |
+
# -------------------------------------------------------------------------
|
| 73 |
+
# Error Handling and Fallback
|
| 74 |
+
# -------------------------------------------------------------------------
|
| 75 |
+
|
| 76 |
+
def handle_import_failure(self):
|
| 77 |
+
"""
|
| 78 |
+
Handle import failures gracefully by providing guidance.
|
| 79 |
+
|
| 80 |
+
Returns:
|
| 81 |
+
dict: A dictionary containing the status and guidance message.
|
| 82 |
+
"""
|
| 83 |
+
return {
|
| 84 |
+
'status': 'error',
|
| 85 |
+
'message': 'Failed to import required Pyomo modules. Please ensure Pyomo is installed and the source path is correct.'
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
# Example usage
|
| 89 |
+
if __name__ == "__main__":
|
| 90 |
+
adapter = Adapter()
|
| 91 |
+
solve_result = adapter.solve_model("example_model.py")
|
| 92 |
+
print(solve_result)
|
| 93 |
+
convert_result = adapter.convert_model("example_model.py")
|
| 94 |
+
print(convert_result)
|
pyomo/mcp_output/mcp_plugin/main.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
MCP Service Auto-Wrapper - Auto-generated
|
| 3 |
+
"""
|
| 4 |
+
from mcp_service import create_app
|
| 5 |
+
|
| 6 |
+
def main():
|
| 7 |
+
"""Main entry point"""
|
| 8 |
+
app = create_app()
|
| 9 |
+
return app
|
| 10 |
+
|
| 11 |
+
if __name__ == "__main__":
|
| 12 |
+
app = main()
|
| 13 |
+
app.run()
|
pyomo/mcp_output/mcp_plugin/mcp_service.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
# Add the local source directory to sys.path
|
| 5 |
+
source_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "source")
|
| 6 |
+
if source_path not in sys.path:
|
| 7 |
+
sys.path.insert(0, source_path)
|
| 8 |
+
|
| 9 |
+
from fastmcp import FastMCP
|
| 10 |
+
|
| 11 |
+
# Import core modules from the local source directory
|
| 12 |
+
from pyomo.core import base, expr, kernel
|
| 13 |
+
from pyomo.environ import solve
|
| 14 |
+
|
| 15 |
+
# Create the FastMCP service application
|
| 16 |
+
mcp = FastMCP("pyomo_service")
|
| 17 |
+
|
| 18 |
+
@mcp.tool(name="solve_model", description="Solve a Pyomo model using specified solvers.")
|
| 19 |
+
def solve_model(model_path: str, solver_name: str) -> dict:
|
| 20 |
+
"""
|
| 21 |
+
Solve a Pyomo model using the specified solver.
|
| 22 |
+
|
| 23 |
+
Parameters:
|
| 24 |
+
- model_path: str - Path to the Pyomo model file.
|
| 25 |
+
- solver_name: str - Name of the solver to use.
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
- dict: Contains success, result, or error fields.
|
| 29 |
+
"""
|
| 30 |
+
try:
|
| 31 |
+
# Load and solve the model
|
| 32 |
+
model = base.PyomoModel(model_path)
|
| 33 |
+
result = solve(model, solver=solver_name)
|
| 34 |
+
return {"success": True, "result": result}
|
| 35 |
+
except Exception as e:
|
| 36 |
+
return {"success": False, "error": str(e)}
|
| 37 |
+
|
| 38 |
+
@mcp.tool(name="evaluate_expression", description="Evaluate a Pyomo expression.")
|
| 39 |
+
def evaluate_expression(expression: str) -> dict:
|
| 40 |
+
"""
|
| 41 |
+
Evaluate a Pyomo expression.
|
| 42 |
+
|
| 43 |
+
Parameters:
|
| 44 |
+
- expression: str - The expression to evaluate.
|
| 45 |
+
|
| 46 |
+
Returns:
|
| 47 |
+
- dict: Contains success, result, or error fields.
|
| 48 |
+
"""
|
| 49 |
+
try:
|
| 50 |
+
# Evaluate the expression
|
| 51 |
+
expr_result = expr.evaluate(expression)
|
| 52 |
+
return {"success": True, "result": expr_result}
|
| 53 |
+
except Exception as e:
|
| 54 |
+
return {"success": False, "error": str(e)}
|
| 55 |
+
|
| 56 |
+
@mcp.tool(name="create_kernel_block", description="Create a kernel block in Pyomo.")
|
| 57 |
+
def create_kernel_block() -> dict:
|
| 58 |
+
"""
|
| 59 |
+
Create a kernel block in Pyomo.
|
| 60 |
+
|
| 61 |
+
Returns:
|
| 62 |
+
- dict: Contains success, result, or error fields.
|
| 63 |
+
"""
|
| 64 |
+
try:
|
| 65 |
+
# Create a kernel block
|
| 66 |
+
block = kernel.block()
|
| 67 |
+
return {"success": True, "result": block}
|
| 68 |
+
except Exception as e:
|
| 69 |
+
return {"success": False, "error": str(e)}
|
| 70 |
+
|
| 71 |
+
def create_app() -> FastMCP:
|
| 72 |
+
"""
|
| 73 |
+
Create and return the FastMCP instance.
|
| 74 |
+
|
| 75 |
+
Returns:
|
| 76 |
+
- FastMCP: The FastMCP service instance.
|
| 77 |
+
"""
|
| 78 |
+
return mcp
|
| 79 |
+
|
| 80 |
+
# Ensure the application is created when the module is executed
|
| 81 |
+
if __name__ == "__main__":
|
| 82 |
+
app = create_app()
|
pyomo/mcp_output/requirements.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastmcp
|
| 2 |
+
fastapi
|
| 3 |
+
uvicorn[standard]
|
| 4 |
+
pydantic>=2.0.0
|
| 5 |
+
ply
|
| 6 |
+
numpy
|
| 7 |
+
scipy
|
| 8 |
+
pyparsing
|
pyomo/mcp_output/start_mcp.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
"""
|
| 3 |
+
MCP Service Startup Entry
|
| 4 |
+
"""
|
| 5 |
+
import sys
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
project_root = os.path.dirname(os.path.abspath(__file__))
|
| 9 |
+
mcp_plugin_dir = os.path.join(project_root, "mcp_plugin")
|
| 10 |
+
if mcp_plugin_dir not in sys.path:
|
| 11 |
+
sys.path.insert(0, mcp_plugin_dir)
|
| 12 |
+
|
| 13 |
+
from mcp_service import create_app
|
| 14 |
+
|
| 15 |
+
def main():
|
| 16 |
+
"""Start FastMCP service"""
|
| 17 |
+
app = create_app()
|
| 18 |
+
# Use environment variable to configure port, default 8000
|
| 19 |
+
port = int(os.environ.get("MCP_PORT", "8000"))
|
| 20 |
+
|
| 21 |
+
# Choose transport mode based on environment variable
|
| 22 |
+
transport = os.environ.get("MCP_TRANSPORT", "stdio")
|
| 23 |
+
if transport == "http":
|
| 24 |
+
app.run(transport="http", host="0.0.0.0", port=port)
|
| 25 |
+
else:
|
| 26 |
+
# Default to STDIO mode
|
| 27 |
+
app.run()
|
| 28 |
+
|
| 29 |
+
if __name__ == "__main__":
|
| 30 |
+
main()
|
pyomo/mcp_output/workflow_summary.json
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"repository": {
|
| 3 |
+
"name": "pyomo",
|
| 4 |
+
"url": "https://github.com/Pyomo/pyomo",
|
| 5 |
+
"local_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/pyomo",
|
| 6 |
+
"description": "Python library",
|
| 7 |
+
"features": "Basic functionality",
|
| 8 |
+
"tech_stack": "Python",
|
| 9 |
+
"stars": 0,
|
| 10 |
+
"forks": 0,
|
| 11 |
+
"language": "Python",
|
| 12 |
+
"last_updated": "",
|
| 13 |
+
"complexity": "complex",
|
| 14 |
+
"intrusiveness_risk": "medium"
|
| 15 |
+
},
|
| 16 |
+
"execution": {
|
| 17 |
+
"start_time": 1770179905.6668937,
|
| 18 |
+
"end_time": 1770180075.7479434,
|
| 19 |
+
"duration": 170.08104991912842,
|
| 20 |
+
"status": "success",
|
| 21 |
+
"workflow_status": "success",
|
| 22 |
+
"nodes_executed": [
|
| 23 |
+
"download",
|
| 24 |
+
"analysis",
|
| 25 |
+
"env",
|
| 26 |
+
"generate",
|
| 27 |
+
"run",
|
| 28 |
+
"review",
|
| 29 |
+
"finalize"
|
| 30 |
+
],
|
| 31 |
+
"total_files_processed": 21,
|
| 32 |
+
"environment_type": "unknown",
|
| 33 |
+
"llm_calls": 0,
|
| 34 |
+
"deepwiki_calls": 0
|
| 35 |
+
},
|
| 36 |
+
"tests": {
|
| 37 |
+
"original_project": {
|
| 38 |
+
"passed": false,
|
| 39 |
+
"details": {},
|
| 40 |
+
"test_coverage": "100%",
|
| 41 |
+
"execution_time": 0,
|
| 42 |
+
"test_files": []
|
| 43 |
+
},
|
| 44 |
+
"mcp_plugin": {
|
| 45 |
+
"passed": true,
|
| 46 |
+
"details": {},
|
| 47 |
+
"service_health": "healthy",
|
| 48 |
+
"startup_time": 0,
|
| 49 |
+
"transport_mode": "stdio",
|
| 50 |
+
"fastmcp_version": "unknown",
|
| 51 |
+
"mcp_version": "unknown"
|
| 52 |
+
}
|
| 53 |
+
},
|
| 54 |
+
"analysis": {
|
| 55 |
+
"structure": {
|
| 56 |
+
"packages": [
|
| 57 |
+
"source.examples.pyomobook",
|
| 58 |
+
"source.pyomo",
|
| 59 |
+
"source.pyomo._archive",
|
| 60 |
+
"source.pyomo.common",
|
| 61 |
+
"source.pyomo.contrib",
|
| 62 |
+
"source.pyomo.core",
|
| 63 |
+
"source.pyomo.dae",
|
| 64 |
+
"source.pyomo.dataportal",
|
| 65 |
+
"source.pyomo.duality",
|
| 66 |
+
"source.pyomo.environ",
|
| 67 |
+
"source.pyomo.gdp",
|
| 68 |
+
"source.pyomo.kernel",
|
| 69 |
+
"source.pyomo.mpec",
|
| 70 |
+
"source.pyomo.neos",
|
| 71 |
+
"source.pyomo.network",
|
| 72 |
+
"source.pyomo.opt",
|
| 73 |
+
"source.pyomo.repn",
|
| 74 |
+
"source.pyomo.scripting",
|
| 75 |
+
"source.pyomo.solvers",
|
| 76 |
+
"source.pyomo.util",
|
| 77 |
+
"source.pyomo.version"
|
| 78 |
+
]
|
| 79 |
+
},
|
| 80 |
+
"dependencies": {
|
| 81 |
+
"has_environment_yml": false,
|
| 82 |
+
"has_requirements_txt": false,
|
| 83 |
+
"pyproject": true,
|
| 84 |
+
"setup_cfg": false,
|
| 85 |
+
"setup_py": true
|
| 86 |
+
},
|
| 87 |
+
"entry_points": {
|
| 88 |
+
"imports": [],
|
| 89 |
+
"cli": [],
|
| 90 |
+
"modules": []
|
| 91 |
+
},
|
| 92 |
+
"risk_assessment": {
|
| 93 |
+
"import_feasibility": 0.8,
|
| 94 |
+
"intrusiveness_risk": "medium",
|
| 95 |
+
"complexity": "complex"
|
| 96 |
+
},
|
| 97 |
+
"deepwiki_analysis": {
|
| 98 |
+
"repo_url": "https://github.com/Pyomo/pyomo",
|
| 99 |
+
"repo_name": "pyomo",
|
| 100 |
+
"content": "Pyomo/pyomo\nPyomo Overview\nInstallation and Setup\nProject Structure\nCore Modeling Framework\nSets and Indexing\nVariables, Constraints, and Objectives\nExpression System\nNumeric and Boolean Expressions\nExpression Visitors\nModel Representation and Solver Interfaces\nStandard Representation\nProblem Writers\nDirect and Persistent Solver Interfaces\nModel Transformations\nGeneralized Disjunctive Programming\nLogical to Linear Transformations\nSpecialized Solvers\nPyROS: Robust Optimization Solver\nMindtPy: MINLP Decomposition Toolbox\nGDPopt: GDP Optimization Solver\nAdvanced Modules\nParameter Estimation\nDesign of Experiments\nIncidence Analysis\nTesting and Utilities\nTesting Infrastructure\nCommon Utilities\nDevelopment and Contribution\nDevelopment Workflow\nDocumentation System\nPyomo Overview\n.codecov.yml\n.coin-or/projDesc.xml\n.coveragerc\n.github/workflows/release_wheel_creation.yml\n.github/workflows/test_branches.yml\n.github/workflows/test_pr_and_main.yml\n.github/workflows/url_check.yml\n.jenkins.sh\n.readthedocs.yaml\nCHANGELOG.md\nconftest.py\ndoc/OnlineDocs/_static/theme_overrides.css\ndoc/OnlineDocs/_templates/layout.html\ndoc/OnlineDocs/_templates/recursive-base.rst\ndoc/OnlineDocs/_templates/recursive-class.rst\ndoc/OnlineDocs/_templates/recursive-enum.rst\ndoc/OnlineDocs/_templates/recursive-module.rst\ndoc/OnlineDocs/conf.py\ndoc/OnlineDocs/contribution_guide.rst\ndoc/OnlineDocs/docutils.conf\ndoc/OnlineDocs/errors.rst\ndoc/OnlineDocs/getting_started/installation.rst\ndoc/OnlineDocs/index.rst\ndoc/OnlineDocs/reference/index.rst\ndoc/logos/pyomo/favicon.ico\nexamples/pyomo/README.txt\npyomo/common/backports.py\npyomo/common/plugin_base.py\npyomo/contrib/solver/__init__.py\npyomo/solvers/amplfunc_merge.py\npyomo/solvers/tests/checks/test_amplfunc_merge.py\npyomo/version/__init__.py\npyomo/version/info.py\nPyomo is a Python-based open-source software package that supports a diverse set of optimization capabilities for formulating and analyzing optimization models. This page provides a high-level overview of Pyomo's architecture, core components, and capabilities.\nWhat is Pyomo?\nPyomo allows users to define symbolic problems, create concrete problem instances, and solve these instances using commercial and open-source solvers. It is designed to support a wide range of optimization problem types, including:\nLinear programming\nQuadratic programming\nNonlinear programming\nMixed-integer linear programming\nMixed-integer quadratic programming\nMixed-integer nonlinear programming\nMixed-integer stochastic programming\nGeneralized disjunctive programming\nDifferential algebraic equations\nMathematical programming with equilibrium constraints\nConstraint programming\nOne of the key advantages of Pyomo is that it embeds optimization modeling capabilities within a full-featured programming language (Python), allowing for transparent parallelization and complex analysis scripting.\nSources:README.md11-47pyomo/version/__init__.py12-21.coin-or/projDesc.xml41-53\nSystem Architecture\nThe architecture of Pyomo is organized into several interconnected subsystems:\nSpecialized ComponentsSolver IntegrationCore SystemsCore Modeling FrameworkExpression SystemRepresentation SystemTransformations SystemSolver InterfacesProblem WritersSolution ReadersContrib SolversGeneralized Disjunctive ProgrammingRobust OptimizationMINLP Decomposition\nSpecialized Components\nSolver Integration\nCore Systems\nCore Modeling Framework\nExpression System\nRepresentation System\nTransformations System\nSolver Interfaces\nProblem Writers\nSolution Readers\nContrib Solvers\nGeneralized Disjunctive Programming\nRobust Optimization\nMINLP Decomposition\nDiagram: High-Level System Architecture\nSources:setup.py96-106.coin-or/projDesc.xml41-53\nCore Modeling Framework\nThe Core Modeling Framework provides the fundamental components for defining optimization models. These include:\nSets and Indexing: The foundation for creating indexed components\nVariables: Decision variables with domains, bounds, and values\nConstraints: Mathematical relationships that restrict solutions\nObjectives: Functions to be minimized or maximized\nParameters: Data values that parameterize the model\nBlocks: Hierarchical model organization\nThe following diagram illustrates the data flow in Pyomo's core modeling framework:\nExpression SystemComponentsUser Model DefinitionConcrete/Abstract ModelVariablesConstraintsSetsParametersObjectivesNumeric/Boolean ExpressionsStandard RepresentationSolver InterfacesSolution\nExpression System\nUser Model Definition\nConcrete/Abstract Model\nConstraints\nNumeric/Boolean Expressions\nStandard Representation\nSolver Interfaces\nDiagram: Core Components and Data Flow\nSources:setup.py248-305README.md11-47\nVersion Information\nPyomo follows semantic versioning. The current version is defined in the version module:\nThe version information is used throughout the system, including in documentation and in releases.\nSources:pyomo/version/info.py14-81RELEASE.md1-46\nExpression System\nThe Expression System is responsible for representing and manipulating mathematical expressions within Pyomo models. It handles:\nNumeric Expressions: Mathematical operations (+, -, *, /, etc.)\nBoolean Expressions: Logical operations (and, or, not, etc.)\nRelational Expressions: Comparisons (==, <=, >=, etc.)\nThe expression system uses a visitor pattern to traverse and manipulate expression trees. Key components include:\nExpression SystemTraverse, Simplify,TransformTraverse, Simplify,TransformTraverse, Simplify,TransformNumeric ExpressionsBoolean ExpressionsRelational ExpressionsExpression VisitorsStandard RepresentationTree ManipulationProblem WritersDirect Solver Interfaces\nExpression System\nTraverse, Simplify,Transform\nTraverse, Simplify,Transform\nTraverse, Simplify,Transform\nNumeric Expressions\nBoolean Expressions\nRelational Expressions\nExpression Visitors\nStandard Representation\nTree Manipulation\nProblem Writers\nDirect Solver Interfaces\nDiagram: Expression System Components\nSources:setup.py96-106doc/OnlineDocs/errors.rst96-149\nModel Representation and Solver Interfaces\nPyomo converts the user's model into standardized representations that can be passed to solvers. This process involves:\nStandard Representation: Intermediate form of expressions\nProblem Writers: Convert models to solver-specific file formats\nDirect/Persistent Interfaces: Communicate with solvers through Python bindings\nSolver InterfacesProblem WritersModel RepresentationStandard RepresentationAMPL RepresentationQuadratic RepresentationLinear RepresentationNL WriterLP WriterMPS WriterGAMS WriterDirect SolversPersistent SolversFile-Based SolversPyomo ModelSolution\nSolver Interfaces\nProblem Writers\nModel Representation\nStandard Representation\nAMPL Representation\nQuadratic Representation\nLinear Representation\nGAMS Writer\nDirect Solvers\nPersistent Solvers\nFile-Based Solvers\nPyomo Model\nDiagram: Representation and Solver Interface Components\nSources:setup.py96-106pyomo/solvers/amplfunc_merge.py46-62\nTransformations\nTransformations convert models between different formulations. Key transformation types include:\nGeneralized Disjunctive Programming (GDP): Transformations for disjunctive constraints\nLogical to Linear: Convert logical constraints to linear forms\nStandard Form: Convert models to standard forms for specific solvers\nTransformationsGDP TransformationsLogical to LinearStandard FormBigMHull ReformulationCutting PlaneMixed Integer ProgramLinear ConstraintsStandard ModelOriginal Model\nTransformations\nGDP Transformations\nLogical to Linear\nStandard Form\nHull Reformulation\nCutting Plane\nMixed Integer Program\nLinear Constraints\nStandard Model\nOriginal Model\nDiagram: Key Transformation Types\nSources:setup.py96-106\nSpecialized Solvers and Contributed Packages\nPyomo includes specialized solvers in thecontribpackage for specific problem types:\nPyROS: Robust Optimization Solver\nMindtPy: MINLP Decomposition Toolbox\nGDPopt: GDP Optimization Solver\nParameter Estimation: Tools for fitting models to data\nDesign of Experiments: Tools for optimal experimental design\nIncidence Analysis: Analysis of model structure\nSpecializedSolversCore ModelingPyROS - Robust OptimizationMindtPy - MINLP DecompositionGDPopt - GDP SolverParameter EstimationDesign of ExperimentsIncidence AnalysisRobust Cutting-Set MethodsDecomposition AlgorithmsGDP AlgorithmsStatistical MethodsExperimental DesignStructural AnalysisExternal Solvers\nSpecializedSolvers\nCore Modeling\nPyROS - Robust Optimization\nMindtPy - MINLP Decomposition\nGDPopt - GDP Solver\nParameter Estimation\nDesign of Experiments\nIncidence Analysis\nRobust Cutting-Set Methods",
|
| 101 |
+
"model": "gpt-4o-2024-08-06",
|
| 102 |
+
"source": "selenium",
|
| 103 |
+
"success": true
|
| 104 |
+
},
|
| 105 |
+
"code_complexity": {
|
| 106 |
+
"cyclomatic_complexity": "medium",
|
| 107 |
+
"cognitive_complexity": "medium",
|
| 108 |
+
"maintainability_index": 75
|
| 109 |
+
},
|
| 110 |
+
"security_analysis": {
|
| 111 |
+
"vulnerabilities_found": 0,
|
| 112 |
+
"security_score": 85,
|
| 113 |
+
"recommendations": []
|
| 114 |
+
}
|
| 115 |
+
},
|
| 116 |
+
"plugin_generation": {
|
| 117 |
+
"files_created": [
|
| 118 |
+
"mcp_output/start_mcp.py",
|
| 119 |
+
"mcp_output/mcp_plugin/__init__.py",
|
| 120 |
+
"mcp_output/mcp_plugin/mcp_service.py",
|
| 121 |
+
"mcp_output/mcp_plugin/adapter.py",
|
| 122 |
+
"mcp_output/mcp_plugin/main.py",
|
| 123 |
+
"mcp_output/requirements.txt",
|
| 124 |
+
"mcp_output/README_MCP.md"
|
| 125 |
+
],
|
| 126 |
+
"main_entry": "start_mcp.py",
|
| 127 |
+
"requirements": [
|
| 128 |
+
"fastmcp>=0.1.0",
|
| 129 |
+
"pydantic>=2.0.0"
|
| 130 |
+
],
|
| 131 |
+
"readme_path": "/export/zxcpu1/shiweijie/code/ghh/Code2MCP/workspace/pyomo/mcp_output/README_MCP.md",
|
| 132 |
+
"adapter_mode": "import",
|
| 133 |
+
"total_lines_of_code": 0,
|
| 134 |
+
"generated_files_size": 0,
|
| 135 |
+
"tool_endpoints": 0,
|
| 136 |
+
"supported_features": [
|
| 137 |
+
"Basic functionality"
|
| 138 |
+
],
|
| 139 |
+
"generated_tools": [
|
| 140 |
+
"Basic tools",
|
| 141 |
+
"Health check tools",
|
| 142 |
+
"Version info tools"
|
| 143 |
+
]
|
| 144 |
+
},
|
| 145 |
+
"code_review": {},
|
| 146 |
+
"errors": [],
|
| 147 |
+
"warnings": [],
|
| 148 |
+
"recommendations": [
|
| 149 |
+
"Improve test coverage by adding more unit tests for critical modules",
|
| 150 |
+
"streamline the repository structure to reduce complexity",
|
| 151 |
+
"enhance documentation for better clarity on core functionalities",
|
| 152 |
+
"optimize the import strategy to improve performance",
|
| 153 |
+
"update dependencies to the latest versions to ensure compatibility and security",
|
| 154 |
+
"implement continuous integration to automate testing and deployment",
|
| 155 |
+
"refactor large files into smaller",
|
| 156 |
+
"more manageable components",
|
| 157 |
+
"improve error handling and logging for better debugging",
|
| 158 |
+
"conduct a security audit to identify and fix vulnerabilities",
|
| 159 |
+
"enhance the user interface for the command-line tools to improve usability."
|
| 160 |
+
],
|
| 161 |
+
"performance_metrics": {
|
| 162 |
+
"memory_usage_mb": 0,
|
| 163 |
+
"cpu_usage_percent": 0,
|
| 164 |
+
"response_time_ms": 0,
|
| 165 |
+
"throughput_requests_per_second": 0
|
| 166 |
+
},
|
| 167 |
+
"deployment_info": {
|
| 168 |
+
"supported_platforms": [
|
| 169 |
+
"Linux",
|
| 170 |
+
"Windows",
|
| 171 |
+
"macOS"
|
| 172 |
+
],
|
| 173 |
+
"python_versions": [
|
| 174 |
+
"3.8",
|
| 175 |
+
"3.9",
|
| 176 |
+
"3.10",
|
| 177 |
+
"3.11",
|
| 178 |
+
"3.12"
|
| 179 |
+
],
|
| 180 |
+
"deployment_methods": [
|
| 181 |
+
"Docker",
|
| 182 |
+
"pip",
|
| 183 |
+
"conda"
|
| 184 |
+
],
|
| 185 |
+
"monitoring_support": true,
|
| 186 |
+
"logging_configuration": "structured"
|
| 187 |
+
},
|
| 188 |
+
"execution_analysis": {
|
| 189 |
+
"success_factors": [
|
| 190 |
+
"Comprehensive package structure analysis",
|
| 191 |
+
"Successful execution of all workflow nodes"
|
| 192 |
+
],
|
| 193 |
+
"failure_reasons": [],
|
| 194 |
+
"overall_assessment": "good",
|
| 195 |
+
"node_performance": {
|
| 196 |
+
"download_time": "Efficient, completed without delay",
|
| 197 |
+
"analysis_time": "Moderate, handled complex structure",
|
| 198 |
+
"generation_time": "Quick, generated necessary files efficiently",
|
| 199 |
+
"test_time": "Not applicable, as original project tests did not pass"
|
| 200 |
+
},
|
| 201 |
+
"resource_usage": {
|
| 202 |
+
"memory_efficiency": "Not measured, but no memory issues reported",
|
| 203 |
+
"cpu_efficiency": "Not measured, but no CPU issues reported",
|
| 204 |
+
"disk_usage": "Efficient, generated files were minimal in size"
|
| 205 |
+
}
|
| 206 |
+
},
|
| 207 |
+
"technical_quality": {
|
| 208 |
+
"code_quality_score": 75,
|
| 209 |
+
"architecture_score": 80,
|
| 210 |
+
"performance_score": 70,
|
| 211 |
+
"maintainability_score": 75,
|
| 212 |
+
"security_score": 85,
|
| 213 |
+
"scalability_score": 70
|
| 214 |
+
}
|
| 215 |
+
}
|
pyomo/source/.codecov.yml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
codecov:
|
| 2 |
+
notify:
|
| 3 |
+
# GHA: 5, Jenkins: 11
|
| 4 |
+
# Accurate as of April 1, 2025
|
| 5 |
+
# Potential to change when Python versions change. We will allow
|
| 6 |
+
# codecov to start reporting when 80% of the reports are in. This
|
| 7 |
+
# will hopefully help avoid an issue where codecov is not tracking
|
| 8 |
+
# PR branches (see https://github.com/codecov/feedback/issues/692).
|
| 9 |
+
after_n_builds: 13
|
| 10 |
+
wait_for_ci: false
|
| 11 |
+
require_ci_to_pass: false
|
| 12 |
+
comment:
|
| 13 |
+
after_n_builds: 13
|
| 14 |
+
coverage:
|
| 15 |
+
range: 70..98
|
| 16 |
+
status:
|
| 17 |
+
patch:
|
| 18 |
+
default:
|
| 19 |
+
# Force patches to be covered at the level of the codebase
|
| 20 |
+
threshold: 0.0
|
| 21 |
+
project:
|
| 22 |
+
default:
|
| 23 |
+
# Allow overall coverage to drop to avoid failures due to code
|
| 24 |
+
# cleanup or CI unavailability/lag
|
| 25 |
+
threshold: 5.0
|
pyomo/source/.coin-or/projDesc.xml
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
| 2 |
+
<?xml-stylesheet type = "text/xsl" href = "http://www.coin-or.org/projects/autoGen.xsl"?>
|
| 3 |
+
<projectData xmlns="coin-or.org"
|
| 4 |
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
| 5 |
+
xsi:schemaLocation="coin-or.org http://www.coin-or.org/projects/autoGen.xsd">
|
| 6 |
+
|
| 7 |
+
<!-- This file is a template that will you fill in in order to provide -->
|
| 8 |
+
<!-- specific information about your project. Once the template is -->
|
| 9 |
+
<!-- filled in and checked into your projects repository in the conf/ -->
|
| 10 |
+
<!-- directory, it will be automatically parsed and displayed in a -->
|
| 11 |
+
<!-- standard HTML format when users call up the file from the main -->
|
| 12 |
+
<!-- COIN Web site. The file is extensively commented to help you -->
|
| 13 |
+
<!-- understand where to fill in the various pieces of required -->
|
| 14 |
+
<!-- information. The comments are enclosed in blocks like this one. -->
|
| 15 |
+
|
| 16 |
+
<projectBasics>
|
| 17 |
+
|
| 18 |
+
<!-- Fill in your project's name in this block. -->
|
| 19 |
+
<!-- For example, for SYMPHONY, you would put: -->
|
| 20 |
+
<!-- -->
|
| 21 |
+
<!-- <projectName> -->
|
| 22 |
+
<!-- SYMPHONY -->
|
| 23 |
+
<!-- </projectName> -->
|
| 24 |
+
<!-- -->
|
| 25 |
+
<!-- Fill in your text below (outside the comment block). -->
|
| 26 |
+
|
| 27 |
+
<projectName>Pyomo</projectName>
|
| 28 |
+
|
| 29 |
+
<!-- Fill in a brief description of your project here. -->
|
| 30 |
+
<!-- For example, for SYMPHONY, you might put: -->
|
| 31 |
+
<!-- -->
|
| 32 |
+
<!-- <projectDescription> -->
|
| 33 |
+
<!-- SYMPHONY is an open-source generic MILP solver, -->
|
| 34 |
+
<!-- callable library, and extensible framework for -->
|
| 35 |
+
<!-- implementing customized solvers for mixed-integer -->
|
| 36 |
+
<!-- linear programs (MILPs). Blah, blah, blah. -->
|
| 37 |
+
<!-- </projectDescription> -->
|
| 38 |
+
<!-- -->
|
| 39 |
+
<!-- Fill in your text below (outside the comment block) -->
|
| 40 |
+
|
| 41 |
+
<projectDescription>
|
| 42 |
+
Pyomo is a Python-based open-source software package that supports a
|
| 43 |
+
diverse set of optimization capabilities for formulating and analyzing
|
| 44 |
+
optimization models.
|
| 45 |
+
|
| 46 |
+
Modeling optimization applications is a core capability of Pyomo. Pyomo
|
| 47 |
+
can be used to define symbolic problems, create concrete problem
|
| 48 |
+
instances, and solve these instances with standard solvers. Thus, Pyomo
|
| 49 |
+
provides a capability that is commonly associated with algebraic
|
| 50 |
+
modeling languages such as AMPL, AIMMS, and GAMS, but Pyomo's modeling
|
| 51 |
+
objects are embedded within a full-featured high-level programming
|
| 52 |
+
language with a rich set of supporting libraries.
|
| 53 |
+
</projectDescription>
|
| 54 |
+
<projectShortDescription>
|
| 55 |
+
Pyomo is a Python-based open-source software package that supports a
|
| 56 |
+
diverse set of optimization capabilities for formulating and analyzing
|
| 57 |
+
optimization models.
|
| 58 |
+
</projectShortDescription>
|
| 59 |
+
|
| 60 |
+
<!-- Fill in the project manager's name and (obfuscated) -->
|
| 61 |
+
<!-- e-mail address here (only one name allowed). -->
|
| 62 |
+
<!-- For example, for the SYMPHONY project, you would put -->
|
| 63 |
+
<!-- -->
|
| 64 |
+
<!--<projectManager> -->
|
| 65 |
+
<!-- Ted Ralphs, tkralphs at lehigh dot edu -->
|
| 66 |
+
<!--</projectManager> -->
|
| 67 |
+
<!-- -->
|
| 68 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 69 |
+
|
| 70 |
+
<projectManager>
|
| 71 |
+
Carl D. Laird, Chair, Pyomo Management Committee, claird at andrew dot cmu dot edu
|
| 72 |
+
</projectManager>
|
| 73 |
+
|
| 74 |
+
<!-- Fill in the URLS you would like use for your main -->
|
| 75 |
+
<!-- home page. This could be either your Trac page or -->
|
| 76 |
+
<!-- your static page (if you have one). -->
|
| 77 |
+
|
| 78 |
+
<projectHomePage>https://www.pyomo.org/</projectHomePage>
|
| 79 |
+
|
| 80 |
+
<!-- Fill in the name of the license your project uses -->
|
| 81 |
+
<!-- and a link to its page on www.opensource.org -->
|
| 82 |
+
|
| 83 |
+
<projectLicense>BSD</projectLicense>
|
| 84 |
+
<!-- Note that while Pyomo is licensed under the
|
| 85 |
+
3-clause BSD license, see
|
| 86 |
+
https://opensource.org/licenses/BSD-3-Clause
|
| 87 |
+
Sandia / DOE require an additional disclaimer as
|
| 88 |
+
part of the license, so we will point to our
|
| 89 |
+
license file directly.
|
| 90 |
+
-->
|
| 91 |
+
<projectLicenseURL>
|
| 92 |
+
https://github.com/Pyomo/pyomo/blob/main/LICENSE.md
|
| 93 |
+
</projectLicenseURL>
|
| 94 |
+
|
| 95 |
+
<!-- Below, you can list other COIN projects your project -->
|
| 96 |
+
<!-- depends on. These are listed one by one, as in the -->
|
| 97 |
+
<!-- following example for SYMPHONY: -->
|
| 98 |
+
<!-- -->
|
| 99 |
+
<!--<coinLinkedProjects> -->
|
| 100 |
+
<!-- -->
|
| 101 |
+
<!-- <coinProject> -->
|
| 102 |
+
<!-- <repoName> -->
|
| 103 |
+
<!-- CoinUtils -->
|
| 104 |
+
<!-- </repoName> -->
|
| 105 |
+
<!-- </coinProject> -->
|
| 106 |
+
<!-- -->
|
| 107 |
+
<!-- <coinProject> -->
|
| 108 |
+
<!-- <repoName> -->
|
| 109 |
+
<!-- Cgl -->
|
| 110 |
+
<!-- </repoName> -->
|
| 111 |
+
<!-- </coinProject> -->
|
| 112 |
+
<!-- -->
|
| 113 |
+
<!-- <coinProject> -->
|
| 114 |
+
<!-- <repoName> -->
|
| 115 |
+
<!-- Osi -->
|
| 116 |
+
<!-- </repoName> -->
|
| 117 |
+
<!-- </coinProject> -->
|
| 118 |
+
<!-- -->
|
| 119 |
+
<!-- <coinProject> -->
|
| 120 |
+
<!-- <repoName> -->
|
| 121 |
+
<!-- Clp -->
|
| 122 |
+
<!-- </repoName> -->
|
| 123 |
+
<!-- </coinProject> -->
|
| 124 |
+
<!-- -->
|
| 125 |
+
<!--</coinLinkedProjects> -->
|
| 126 |
+
<!-- -->
|
| 127 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 128 |
+
|
| 129 |
+
<coinLinkedProjects> </coinLinkedProjects>
|
| 130 |
+
|
| 131 |
+
<!-- Below, you can list other packages your project -->
|
| 132 |
+
<!-- either requires or can optionally link to. These are -->
|
| 133 |
+
<!-- one by one, as in the following example: -->
|
| 134 |
+
<!-- -->
|
| 135 |
+
<!--<otherLinkedPackages> -->
|
| 136 |
+
<!-- -->
|
| 137 |
+
<!-- <otherPackage> -->
|
| 138 |
+
<!-- <packageName> -->
|
| 139 |
+
<!-- GLPK -->
|
| 140 |
+
<!-- </packageName> -->
|
| 141 |
+
<!-- <packageURL> -->
|
| 142 |
+
<!-- </packageURL> -->
|
| 143 |
+
<!-- <requiredOrOptional> -->
|
| 144 |
+
<!-- Optional -->
|
| 145 |
+
<!-- </requiredOrOptional> -->
|
| 146 |
+
<!-- </otherPackage> -->
|
| 147 |
+
<!-- -->
|
| 148 |
+
<!-- <otherPackage> -->
|
| 149 |
+
<!-- <packageName> -->
|
| 150 |
+
<!-- GNU Readline -->
|
| 151 |
+
<!-- </packageName> -->
|
| 152 |
+
<!-- <packageURL> -->
|
| 153 |
+
<!-- </packageURL> -->
|
| 154 |
+
<!-- <requiredOrOptional> -->
|
| 155 |
+
<!-- Optional -->
|
| 156 |
+
<!-- </requiredOrOptional> -->
|
| 157 |
+
<!-- </otherPackage> -->
|
| 158 |
+
<!-- -->
|
| 159 |
+
<!-- <otherPackage> -->
|
| 160 |
+
<!-- <packageName> -->
|
| 161 |
+
<!-- GNU History -->
|
| 162 |
+
<!-- </packageName> -->
|
| 163 |
+
<!-- <packageURL> -->
|
| 164 |
+
<!-- </packageURL> -->
|
| 165 |
+
<!-- <requiredOrOptional> -->
|
| 166 |
+
<!-- Optional -->
|
| 167 |
+
<!-- </requiredOrOptional> -->
|
| 168 |
+
<!-- </otherPackage> -->
|
| 169 |
+
<!-- -->
|
| 170 |
+
<!--</otherLinkedPackages> -->
|
| 171 |
+
<!-- -->
|
| 172 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 173 |
+
|
| 174 |
+
<otherLinkedPackages> </otherLinkedPackages>
|
| 175 |
+
|
| 176 |
+
<!-- Below, you can list the programming language(s) used in -->
|
| 177 |
+
<!-- the project. For example: -->
|
| 178 |
+
<!--<projectLanguage>C</projectLanguage> -->
|
| 179 |
+
<!-- -->
|
| 180 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 181 |
+
|
| 182 |
+
<projectLanguage>Python</projectLanguage>
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
<!--The following fields describe the development status -->
|
| 186 |
+
<!--of the project. -->
|
| 187 |
+
<!-- -->
|
| 188 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 189 |
+
|
| 190 |
+
<developmentStatus>
|
| 191 |
+
|
| 192 |
+
<!--If you are actively managing your project, use -->
|
| 193 |
+
|
| 194 |
+
<activityStatus>Active</activityStatus>
|
| 195 |
+
|
| 196 |
+
<!--The maturity level is determined during project -->
|
| 197 |
+
<!--review and should have been reported to you. -->
|
| 198 |
+
<!--See http://www.coin-or.org/faqs.html#q18 for -->
|
| 199 |
+
<!--more information on maturity level. -->
|
| 200 |
+
<!--Fill it in like this: -->
|
| 201 |
+
<!-- -->
|
| 202 |
+
<!--<maturityLevel>5</maturityLevel> -->
|
| 203 |
+
<!-- -->
|
| 204 |
+
|
| 205 |
+
<maturityLevel>4</maturityLevel>
|
| 206 |
+
|
| 207 |
+
<!-- Very non-standard (by COIN standards) repo structure.
|
| 208 |
+
Use explicit overrides to disable use of automated
|
| 209 |
+
version reporting.
|
| 210 |
+
-->
|
| 211 |
+
<stableVersionNumber>6.9.5</stableVersionNumber>
|
| 212 |
+
<releaseNumber>6.9.5</releaseNumber>
|
| 213 |
+
|
| 214 |
+
</developmentStatus>
|
| 215 |
+
|
| 216 |
+
<!--Below, you can list the platforms on which your -->
|
| 217 |
+
<!--project has been tested. Again, these are listed one -->
|
| 218 |
+
<!--by one. There are fields for both operating system and -->
|
| 219 |
+
<!--compiler. Here is an example for SYMPHONY -->
|
| 220 |
+
<!-- -->
|
| 221 |
+
<!--<testedPlatforms> -->
|
| 222 |
+
<!-- -->
|
| 223 |
+
<!-- <platform> -->
|
| 224 |
+
<!-- <operatingSystem>Microsoft Windows</operatingSystem> -->
|
| 225 |
+
<!-- <compiler>MSVC++/cl</compiler> -->
|
| 226 |
+
<!-- </platform> -->
|
| 227 |
+
<!-- -->
|
| 228 |
+
<!-- <platform> -->
|
| 229 |
+
<!-- <operatingSystem>Microsoft Windows</operatingSystem> -->
|
| 230 |
+
<!-- <compiler>CYGWIN/cl</compiler> -->
|
| 231 |
+
<!-- </platform> -->
|
| 232 |
+
<!-- -->
|
| 233 |
+
<!-- <platform> -->
|
| 234 |
+
<!-- <operatingSystem>Microsoft Windows</operatingSystem> -->
|
| 235 |
+
<!-- <compiler>CYGWIN/gcc</compiler> -->
|
| 236 |
+
<!-- </platform> -->
|
| 237 |
+
<!-- -->
|
| 238 |
+
<!-- <platform> -->
|
| 239 |
+
<!-- <operatingSystem>Microsoft Windows</operatingSystem> -->
|
| 240 |
+
<!-- <compiler>MSys/gcc</compiler> -->
|
| 241 |
+
<!-- </platform> -->
|
| 242 |
+
<!-- -->
|
| 243 |
+
<!-- <platform> -->
|
| 244 |
+
<!-- <operatingSystem>Linux</operatingSystem> -->
|
| 245 |
+
<!-- <compiler>gcc</compiler> -->
|
| 246 |
+
<!-- </platform> -->
|
| 247 |
+
<!-- -->
|
| 248 |
+
<!-- <platform> -->
|
| 249 |
+
<!-- <operatingSystem>Mac OSX</operatingSystem> -->
|
| 250 |
+
<!-- <compiler>gcc</compiler> -->
|
| 251 |
+
<!-- </platform> -->
|
| 252 |
+
<!-- -->
|
| 253 |
+
<!-- <platform> -->
|
| 254 |
+
<!-- <operatingSystem>Solaris x86</operatingSystem> -->
|
| 255 |
+
<!-- <compiler>gcc</compiler> -->
|
| 256 |
+
<!-- </platform> -->
|
| 257 |
+
<!-- -->
|
| 258 |
+
<!-- <platform> -->
|
| 259 |
+
<!-- <operatingSystem>Solaris x86</operatingSystem> -->
|
| 260 |
+
<!-- <compiler>sunpro</compiler> -->
|
| 261 |
+
<!-- </platform> -->
|
| 262 |
+
<!-- -->
|
| 263 |
+
<!--</testedPlatforms> -->
|
| 264 |
+
<!-- -->
|
| 265 |
+
<!--Fill in your text below (outside the comment block). -->
|
| 266 |
+
|
| 267 |
+
<testedPlatforms>
|
| 268 |
+
|
| 269 |
+
<platform>
|
| 270 |
+
<operatingSystem>Any</operatingSystem>
|
| 271 |
+
<compiler>Python 3.10, 3.11, 3.12, 3.13, 3.14</compiler>
|
| 272 |
+
</platform>
|
| 273 |
+
|
| 274 |
+
</testedPlatforms>
|
| 275 |
+
|
| 276 |
+
<projectCategories>
|
| 277 |
+
<!-- Start of projectCategories block -->
|
| 278 |
+
|
| 279 |
+
<!--Below is the list of COIN-OR project categores. -->
|
| 280 |
+
<!--Simply "un-comment" any categories that apply to -->
|
| 281 |
+
<!--your project. -->
|
| 282 |
+
|
| 283 |
+
<category> Modeling systems </category>
|
| 284 |
+
<category> Development tools </category>
|
| 285 |
+
<category> Optimization stochastic </category>
|
| 286 |
+
<category> Optimization utility </category>
|
| 287 |
+
|
| 288 |
+
<!-- End of projectCategories block -->
|
| 289 |
+
</projectCategories>
|
| 290 |
+
|
| 291 |
+
<!-- End of projectBasics block -->
|
| 292 |
+
|
| 293 |
+
</projectBasics>
|
| 294 |
+
|
| 295 |
+
<!--Below, you can specify the links for the left-hand side menu. -->
|
| 296 |
+
<!--Note that these are optional, so if there is a blank, there will -->
|
| 297 |
+
<!--be no corresponding menu item -->
|
| 298 |
+
|
| 299 |
+
<leftMenuLinks>
|
| 300 |
+
|
| 301 |
+
<documentation>https://pyomo.readthedocs.org/</documentation>
|
| 302 |
+
|
| 303 |
+
<sourceCodeDownload>https://github.com/Pyomo/pyomo/releases/latest</sourceCodeDownload>
|
| 304 |
+
|
| 305 |
+
<binaryDownload>https://github.com/Pyomo/pyomo/releases/latest</binaryDownload>
|
| 306 |
+
|
| 307 |
+
<mailingList>https://groups.google.com/group/pyomo-forum</mailingList>
|
| 308 |
+
|
| 309 |
+
</leftMenuLinks>
|
| 310 |
+
|
| 311 |
+
<!-- End of projectData block -->
|
| 312 |
+
</projectData>
|
pyomo/source/.coveragerc
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[report]
|
| 2 |
+
omit =
|
| 3 |
+
setup.py
|
| 4 |
+
*/tests/*
|
| 5 |
+
*/tmp/*
|
| 6 |
+
|
| 7 |
+
# The [run] section must be at the end, as the build harness will add a
|
| 8 |
+
# "data_file" directive to the end of this file.
|
| 9 |
+
[run]
|
| 10 |
+
concurrency =
|
| 11 |
+
multiprocessing
|
| 12 |
+
thread
|
| 13 |
+
parallel = True
|
| 14 |
+
source =
|
| 15 |
+
pyomo
|
| 16 |
+
examples
|
| 17 |
+
omit =
|
| 18 |
+
# github actions creates a cache directory we don't want measured
|
| 19 |
+
cache/*
|
pyomo/source/.jenkins.sh
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
# Important environment variables:
|
| 3 |
+
#
|
| 4 |
+
# WORKSPACE: path to the base WORKSPACE. This script assumes that there
|
| 5 |
+
# are 2 available subdirectories: pyomo (the pyomo source checkout
|
| 6 |
+
# and pyomo-model-libraries
|
| 7 |
+
# (the checkout of the additional model libraries repo). It will
|
| 8 |
+
# create two additional directories within WORKSPACE: python (a
|
| 9 |
+
# virtualenv) and config (the local Pyomo configuration/cache
|
| 10 |
+
# directory)
|
| 11 |
+
#
|
| 12 |
+
# CATEGORY: the category to pass to pytest
|
| 13 |
+
#
|
| 14 |
+
# TEST_SUITES: Paths (module or directory) to be passed to pytest to
|
| 15 |
+
# run. (defaults to "pyomo '$WORKSPACE/pyomo-model-libraries'")
|
| 16 |
+
#
|
| 17 |
+
# SLIM: If nonempty, then the virtualenv will only have pip, setuptools,
|
| 18 |
+
# and wheel installed. Otherwise the virtualenv will inherit the
|
| 19 |
+
# system site-packages.
|
| 20 |
+
#
|
| 21 |
+
# CODECOV_TOKEN: the token to use when uploading results to codecov.io
|
| 22 |
+
#
|
| 23 |
+
# CODECOV_SOURCE_BRANCH: passed to the 'codecov-cli' command; branch of Pyomo
|
| 24 |
+
# (e.g., to enable correct codecov uploads)
|
| 25 |
+
#
|
| 26 |
+
# CODECOV_REPO_OWNER: passed to the 'codecov-cli' command; owner of repo
|
| 27 |
+
# (e.g., to enable correct codecov uploads)
|
| 28 |
+
#
|
| 29 |
+
# DISABLE_COVERAGE: if nonempty, then coverage analysis is disabled
|
| 30 |
+
#
|
| 31 |
+
# PYOMO_SETUP_ARGS: passed to the 'pip install' command
|
| 32 |
+
# (e.g., to specify --with-cython)
|
| 33 |
+
#
|
| 34 |
+
# PYOMO_DOWNLOAD_ARGS: passed to the 'pyomo download-extensions' command
|
| 35 |
+
# (e.g., to set up local SSL certificate authorities)
|
| 36 |
+
#
|
| 37 |
+
# PYTEST_EXTRA_ARGS: passed to the 'pytest' command
|
| 38 |
+
# (e.g., to add extra pytest options like '--collect-only')
|
| 39 |
+
#
|
| 40 |
+
if test -z "$WORKSPACE"; then
|
| 41 |
+
export WORKSPACE=`pwd`
|
| 42 |
+
fi
|
| 43 |
+
if test -z "$TEST_SUITES"; then
|
| 44 |
+
export TEST_SUITES="${WORKSPACE}/pyomo/pyomo ${WORKSPACE}/pyomo-model-libraries ${WORKSPACE}/pyomo/examples ${WORKSPACE}/pyomo/doc"
|
| 45 |
+
fi
|
| 46 |
+
if test -z "$SLIM"; then
|
| 47 |
+
export VENV_SYSTEM_PACKAGES='--system-site-packages'
|
| 48 |
+
fi
|
| 49 |
+
|
| 50 |
+
if test "$WORKSPACE" != "`pwd`"; then
|
| 51 |
+
echo "ERROR: pwd is not WORKSPACE"
|
| 52 |
+
echo " pwd= `pwd`"
|
| 53 |
+
echo " WORKSPACE= $WORKSPACE"
|
| 54 |
+
exit 1
|
| 55 |
+
fi
|
| 56 |
+
MODE="$1"
|
| 57 |
+
|
| 58 |
+
if test -z "$MODE" -o "$MODE" == setup; then
|
| 59 |
+
# Clean old PYC files and remove any previous virtualenv
|
| 60 |
+
echo "#"
|
| 61 |
+
echo "# Removing python virtual environment"
|
| 62 |
+
echo "#"
|
| 63 |
+
rm -rf ${WORKSPACE}/python
|
| 64 |
+
echo "#"
|
| 65 |
+
echo "# Cleaning out old .pyc and cython files"
|
| 66 |
+
echo "#"
|
| 67 |
+
for EXT in pyc pyx pyd so dylib dll; do
|
| 68 |
+
find ${WORKSPACE}/pyomo -name \*.$EXT -delete
|
| 69 |
+
done
|
| 70 |
+
|
| 71 |
+
# Set up the local lpython
|
| 72 |
+
echo ""
|
| 73 |
+
echo "#"
|
| 74 |
+
echo "# Setting up virtual environment"
|
| 75 |
+
echo "#"
|
| 76 |
+
virtualenv python $VENV_SYSTEM_PACKAGES --clear || exit 1
|
| 77 |
+
source python/bin/activate
|
| 78 |
+
# Because modules set the PYTHONPATH, we need to make sure that the
|
| 79 |
+
# virtualenv appears first
|
| 80 |
+
LOCAL_SITE_PACKAGES=`python -c "import sysconfig; print(sysconfig.get_path('purelib'))"`
|
| 81 |
+
export PYTHONPATH="$LOCAL_SITE_PACKAGES:$PYTHONPATH"
|
| 82 |
+
|
| 83 |
+
# Set up Pyomo checkouts
|
| 84 |
+
echo ""
|
| 85 |
+
# configure the Pyomo configuration directory
|
| 86 |
+
echo "#"
|
| 87 |
+
echo "# Installing pyomo modules"
|
| 88 |
+
echo "#"
|
| 89 |
+
if test -d "$WORKSPACE/pyutilib"; then
|
| 90 |
+
pushd "$WORKSPACE/pyutilib"
|
| 91 |
+
python setup.py develop || echo "PyUtilib failed - skipping."
|
| 92 |
+
popd
|
| 93 |
+
else
|
| 94 |
+
echo "PyUtilib not found; skipping"
|
| 95 |
+
fi
|
| 96 |
+
pushd "$WORKSPACE/pyomo" || exit 1
|
| 97 |
+
pip install -e . || exit 1
|
| 98 |
+
popd
|
| 99 |
+
#
|
| 100 |
+
# DO NOT install pyomo-model-libraries
|
| 101 |
+
#
|
| 102 |
+
|
| 103 |
+
# Set up coverage tracking for subprocesses
|
| 104 |
+
if test -z "$DISABLE_COVERAGE"; then
|
| 105 |
+
# Clean up old coverage files
|
| 106 |
+
rm -fv ${WORKSPACE}/pyomo/.coverage ${WORKSPACE}/pyomo/.coverage.*
|
| 107 |
+
# Set up coverage for this build
|
| 108 |
+
export COVERAGE_PROCESS_START=${WORKSPACE}/coveragerc
|
| 109 |
+
cp ${WORKSPACE}/pyomo/.coveragerc ${COVERAGE_PROCESS_START}
|
| 110 |
+
echo "data_file=${WORKSPACE}/pyomo/.coverage" \
|
| 111 |
+
>> ${COVERAGE_PROCESS_START}
|
| 112 |
+
echo 'import coverage; coverage.process_startup()' \
|
| 113 |
+
> "${LOCAL_SITE_PACKAGES}/run_coverage_at_startup.pth"
|
| 114 |
+
fi
|
| 115 |
+
|
| 116 |
+
# Move into the pyomo directory
|
| 117 |
+
pushd ${WORKSPACE}/pyomo || exit 1
|
| 118 |
+
|
| 119 |
+
# Set a local Pyomo configuration dir within this workspace
|
| 120 |
+
export PYOMO_CONFIG_DIR="${WORKSPACE}/config"
|
| 121 |
+
echo ""
|
| 122 |
+
echo "PYOMO_CONFIG_DIR=$PYOMO_CONFIG_DIR"
|
| 123 |
+
echo ""
|
| 124 |
+
|
| 125 |
+
# Call Pyomo build scripts to build TPLs that would normally be
|
| 126 |
+
# skipped by the pyomo download-extensions / build-extensions
|
| 127 |
+
# actions below
|
| 128 |
+
if [[ " $CATEGORY " == *" builders "* ]]; then
|
| 129 |
+
echo ""
|
| 130 |
+
echo "Running local build scripts..."
|
| 131 |
+
echo ""
|
| 132 |
+
set -x
|
| 133 |
+
python pyomo/contrib/simplification/build.py --build-deps || exit 1
|
| 134 |
+
set +x
|
| 135 |
+
fi
|
| 136 |
+
|
| 137 |
+
# Use Pyomo to download & compile binary extensions
|
| 138 |
+
i=0
|
| 139 |
+
while /bin/true; do
|
| 140 |
+
i=$[$i+1]
|
| 141 |
+
echo ""
|
| 142 |
+
echo "Downloading pyomo extensions (attempt $i)"
|
| 143 |
+
pyomo download-extensions $PYOMO_DOWNLOAD_ARGS
|
| 144 |
+
if test $? == 0; then
|
| 145 |
+
break
|
| 146 |
+
elif test $i -ge 3; then
|
| 147 |
+
exit 1
|
| 148 |
+
fi
|
| 149 |
+
DELAY=$(( RANDOM % 30 + 15))
|
| 150 |
+
echo "Pausing $DELAY seconds before re-attempting download"
|
| 151 |
+
sleep $DELAY
|
| 152 |
+
done
|
| 153 |
+
pyomo build-extensions || exit 1
|
| 154 |
+
|
| 155 |
+
# Print useful version information
|
| 156 |
+
echo ""
|
| 157 |
+
echo "#"
|
| 158 |
+
echo "# Package information:"
|
| 159 |
+
echo "#"
|
| 160 |
+
python --version
|
| 161 |
+
pip --version
|
| 162 |
+
pip list
|
| 163 |
+
echo "#"
|
| 164 |
+
echo "# Installed programs:"
|
| 165 |
+
echo "#"
|
| 166 |
+
gjh -v || echo "GJH not found"
|
| 167 |
+
glpsol -v || echo "GLPK not found"
|
| 168 |
+
cbc -quit || echo "CBC not found"
|
| 169 |
+
cplex -c quit || echo "CPLEX not found"
|
| 170 |
+
gurobi_cl --version || echo "GUROBI not found"
|
| 171 |
+
ipopt -v || echo "IPOPT not found"
|
| 172 |
+
gams || echo "GAMS not found"
|
| 173 |
+
|
| 174 |
+
# Exit ${WORKSPACE}/pyomo
|
| 175 |
+
popd
|
| 176 |
+
fi
|
| 177 |
+
|
| 178 |
+
if test -z "$MODE" -o "$MODE" == test; then
|
| 179 |
+
# Copy conftest.py into every requested test suite that is NOT
|
| 180 |
+
# within ${WORKSPACE}/pyomo
|
| 181 |
+
for TEST in $TEST_SUITES; do
|
| 182 |
+
if [[ "$TEST" != *"${WORKSPACE}/pyomo/"* ]]; then
|
| 183 |
+
cp ${WORKSPACE}/conftest.py $TEST
|
| 184 |
+
fi;
|
| 185 |
+
done
|
| 186 |
+
rm ${WORKSPACE}/conftest.py
|
| 187 |
+
echo ""
|
| 188 |
+
echo "#"
|
| 189 |
+
echo "# Running Pyomo tests"
|
| 190 |
+
echo "#"
|
| 191 |
+
python -m pytest -v \
|
| 192 |
+
-W ignore::Warning \
|
| 193 |
+
--junitxml="TEST-pyomo.xml" \
|
| 194 |
+
-m "$CATEGORY" $TEST_SUITES $PYTEST_EXTRA_ARGS
|
| 195 |
+
|
| 196 |
+
# Combine the coverage results and upload
|
| 197 |
+
if test -z "$DISABLE_COVERAGE"; then
|
| 198 |
+
# Enter ${WORKSPACE}/pyomo for coverage Processing
|
| 199 |
+
pushd ${WORKSPACE}/pyomo || exit 1
|
| 200 |
+
echo ""
|
| 201 |
+
echo "#"
|
| 202 |
+
echo "# Processing coverage information in "`pwd`
|
| 203 |
+
echo "#"
|
| 204 |
+
#
|
| 205 |
+
# Note, that the PWD should still be $WORKSPACE/pyomo
|
| 206 |
+
#
|
| 207 |
+
coverage combine || exit 1
|
| 208 |
+
coverage report -i || exit 1
|
| 209 |
+
coverage xml -i || exit 1
|
| 210 |
+
export OS=`uname`
|
| 211 |
+
if test -z "$PYOMO_SOURCE_SHA"; then
|
| 212 |
+
PYOMO_SOURCE_SHA=$GIT_COMMIT
|
| 213 |
+
fi
|
| 214 |
+
if test -n "$CODECOV_TOKEN" -a -n "$PYOMO_SOURCE_SHA"; then
|
| 215 |
+
_NAME=$(echo $JOB_NAME | sed -r 's/^(.*(autotest|Build)_)?([^\/]+).*/\3/')
|
| 216 |
+
_MATRIX=$(echo $JOB_NAME | sed -r "s/,/\n/g" | grep -v host \
|
| 217 |
+
| sed -r 's/.*=//' | tr '\n' , | sed -r 's/,+$//')
|
| 218 |
+
CODECOV_JOB_NAME=${_NAME}/${_MATRIX}.${BUILD_NUMBER}
|
| 219 |
+
CODECOV_FLAG=$(echo $JOB_NAME | sed -r "s/,/\n/g" | grep CATEGORY \
|
| 220 |
+
| sed -r 's/.*=//')
|
| 221 |
+
if test -z "$CODECOV_FLAG"; then
|
| 222 |
+
CODECOV_FLAG=linux
|
| 223 |
+
fi
|
| 224 |
+
if test -z "$CODECOV_REPO_OWNER"; then
|
| 225 |
+
if test -n "$PYOMO_SOURCE_REPO"; then
|
| 226 |
+
CODECOV_REPO_OWNER=$(echo "$PYOMO_SOURCE_REPO" | cut -d '/' -f 4)
|
| 227 |
+
elif test -n "$GIT_URL"; then
|
| 228 |
+
CODECOV_REPO_OWNER=$(echo "$GIT_URL" | cut -d '/' -f 4)
|
| 229 |
+
else
|
| 230 |
+
CODECOV_REPO_OWNER=""
|
| 231 |
+
fi
|
| 232 |
+
fi
|
| 233 |
+
if test -z "$CODECOV_SOURCE_BRANCH"; then
|
| 234 |
+
CODECOV_SOURCE_BRANCH=$(git branch -av --contains "$PYOMO_SOURCE_SHA" \
|
| 235 |
+
| grep "${PYOMO_SOURCE_SHA:0:7}" | grep "/origin/" \
|
| 236 |
+
| cut -d '/' -f 3 | cut -d' ' -f 1)
|
| 237 |
+
if test -z "$CODECOV_SOURCE_BRANCH"; then
|
| 238 |
+
CODECOV_SOURCE_BRANCH=main
|
| 239 |
+
fi
|
| 240 |
+
fi
|
| 241 |
+
i=0
|
| 242 |
+
while /bin/true; do
|
| 243 |
+
i=$[$i+1]
|
| 244 |
+
echo "Uploading coverage to codecov (attempt $i)"
|
| 245 |
+
codecovcli -v upload-process --sha $PYOMO_SOURCE_SHA \
|
| 246 |
+
--fail-on-error --git-service github --token $CODECOV_TOKEN \
|
| 247 |
+
--slug pyomo/pyomo --file coverage.xml --disable-search \
|
| 248 |
+
--flag $CODECOV_FLAG \
|
| 249 |
+
--name $CODECOV_JOB_NAME \
|
| 250 |
+
--branch $CODECOV_REPO_OWNER:$CODECOV_SOURCE_BRANCH \
|
| 251 |
+
--env OS,python --network-root-folder `pwd` --plugin noop
|
| 252 |
+
if test $? == 0; then
|
| 253 |
+
break
|
| 254 |
+
elif test $i -ge 4; then
|
| 255 |
+
exit 1
|
| 256 |
+
fi
|
| 257 |
+
DELAY=$(( RANDOM % 30 + 15))
|
| 258 |
+
echo "Pausing $DELAY seconds before re-attempting upload"
|
| 259 |
+
sleep $DELAY
|
| 260 |
+
done
|
| 261 |
+
fi
|
| 262 |
+
rm .coverage
|
| 263 |
+
# Exit ${WORKSPACE}/pyomo
|
| 264 |
+
popd
|
| 265 |
+
fi
|
| 266 |
+
fi
|
pyomo/source/.readthedocs.yaml
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# .readthedocs.yaml
|
| 2 |
+
# Read the Docs configuration file
|
| 3 |
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
| 4 |
+
|
| 5 |
+
# Required
|
| 6 |
+
version: 2
|
| 7 |
+
|
| 8 |
+
build:
|
| 9 |
+
os: ubuntu-22.04
|
| 10 |
+
tools:
|
| 11 |
+
python: "3.13"
|
| 12 |
+
apt_packages:
|
| 13 |
+
- graphviz
|
| 14 |
+
- latexmk
|
| 15 |
+
- texlive
|
| 16 |
+
- texlive-latex-extra
|
| 17 |
+
- texlive-pictures
|
| 18 |
+
jobs:
|
| 19 |
+
post_build:
|
| 20 |
+
- |
|
| 21 |
+
for pdf in $READTHEDOCS_OUTPUT/pdf/*.pdf; do
|
| 22 |
+
if test [[ `basename $pdf` == graphviz* ]]; then
|
| 23 |
+
rm -v $pdf;
|
| 24 |
+
fi;
|
| 25 |
+
done
|
| 26 |
+
|
| 27 |
+
sphinx:
|
| 28 |
+
configuration: doc/OnlineDocs/conf.py
|
| 29 |
+
|
| 30 |
+
formats:
|
| 31 |
+
- pdf
|
| 32 |
+
|
| 33 |
+
# Set the version of Python and requirements required to build the docs
|
| 34 |
+
python:
|
| 35 |
+
install:
|
| 36 |
+
- method: pip
|
| 37 |
+
path: .
|
| 38 |
+
extra_requirements:
|
| 39 |
+
- docs
|
pyomo/source/CHANGELOG.md
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
pyomo/source/CITATION.cff
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
cff-version: 1.2.0
|
| 2 |
+
message: "If you use this software, please cite it as below."
|
| 3 |
+
authors:
|
| 4 |
+
- name: "Pyomo contributors"
|
| 5 |
+
title: "Pyomo: a Python-based, open-source optimization modeling language with a diverse set of optimization capabilities"
|
| 6 |
+
url: "https://github.com/Pyomo/pyomo"
|
| 7 |
+
license-url: "https://github.com/Pyomo/pyomo/blob/main/LICENSE.md"
|
| 8 |
+
preferred-citation:
|
| 9 |
+
type: book
|
| 10 |
+
authors:
|
| 11 |
+
- family-names: "Bynum"
|
| 12 |
+
given-names: "Michael L"
|
| 13 |
+
- family-names: "Hackebeil"
|
| 14 |
+
given-names: "Gabriel A"
|
| 15 |
+
- family-names: "Hart"
|
| 16 |
+
given-names: "William E"
|
| 17 |
+
- family-names: "Laird"
|
| 18 |
+
given-names: "Carl D"
|
| 19 |
+
- family-names: "Nicholson"
|
| 20 |
+
given-names: "Bethany L"
|
| 21 |
+
- family-names: "Siirola"
|
| 22 |
+
given-names: "John D"
|
| 23 |
+
- family-names: "Watson"
|
| 24 |
+
given-names: "Jean-Paul"
|
| 25 |
+
- family-names: "Woodruff"
|
| 26 |
+
given-names: "David L"
|
| 27 |
+
title: "Pyomo - optimization modeling in Python, 3rd Edition"
|
| 28 |
+
publisher: "Springer"
|
| 29 |
+
volume: 67
|
| 30 |
+
year: 2021
|
| 31 |
+
doi: "10.1007/978-3-030-68928-5"
|
pyomo/source/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Contributing to Pyomo
|
| 2 |
+
=====================
|
| 3 |
+
|
| 4 |
+
Online Documentation
|
| 5 |
+
--------------------
|
| 6 |
+
|
| 7 |
+
Detailed contribution guidelines may be found in our
|
| 8 |
+
[online documentation](http://pyomo.readthedocs.io/en/latest/contribution_guide.html).
|
| 9 |
+
|
| 10 |
+
Pull Requests
|
| 11 |
+
-------------
|
| 12 |
+
|
| 13 |
+
Pyomo manages source code contributions via pull requests. For a pull request
|
| 14 |
+
to be accepted, it must satisfy all code integration and coverage tests, and
|
| 15 |
+
then pass review by two core developers. For core developers, authorship of a
|
| 16 |
+
pull request counts as a review.
|
| 17 |
+
|
| 18 |
+
Submitted code that addresses an issue should include a test exercising the
|
| 19 |
+
relevant case. New functionality should include tests to establish validity of
|
| 20 |
+
its results and/or effects.
|
| 21 |
+
|
| 22 |
+
Legal Disclaimer
|
| 23 |
+
----------------
|
| 24 |
+
|
| 25 |
+
By contributing to this software project, you are agreeing to the
|
| 26 |
+
following terms and conditions for your contributions:
|
| 27 |
+
|
| 28 |
+
1. You agree your contributions are submitted under the BSD license.
|
| 29 |
+
2. You represent you are authorized to make the contributions and grant
|
| 30 |
+
the license. If your employer has rights to intellectual property that
|
| 31 |
+
includes your contributions, you represent that you have received
|
| 32 |
+
permission to make contributions and grant the required license on
|
| 33 |
+
behalf of that employer.
|
pyomo/source/LICENSE.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
LICENSE
|
| 2 |
+
=======
|
| 3 |
+
|
| 4 |
+
Copyright (c) 2008-2025 National Technology and Engineering Solutions of
|
| 5 |
+
Sandia, LLC . Under the terms of Contract DE-NA0003525 with National
|
| 6 |
+
Technology and Engineering Solutions of Sandia, LLC , the U.S.
|
| 7 |
+
Government retains certain rights in this software.
|
| 8 |
+
|
| 9 |
+
All rights reserved.
|
| 10 |
+
|
| 11 |
+
Redistribution and use in source and binary forms, with or without
|
| 12 |
+
modification, are permitted provided that the following conditions
|
| 13 |
+
are met:
|
| 14 |
+
|
| 15 |
+
* Redistributions of source code must retain the above copyright notice,
|
| 16 |
+
this list of conditions and the following disclaimer.
|
| 17 |
+
|
| 18 |
+
* Redistributions in binary form must reproduce the above copyright
|
| 19 |
+
notice, this list of conditions and the following disclaimer in the
|
| 20 |
+
documentation and/or other materials provided with the distribution.
|
| 21 |
+
|
| 22 |
+
* Neither the name of the Sandia National Laboratories nor the names of
|
| 23 |
+
its contributors may be used to endorse or promote products derived from
|
| 24 |
+
this software without specific prior written permission.
|
| 25 |
+
|
| 26 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 27 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 28 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 29 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 30 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 31 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
| 32 |
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| 33 |
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 34 |
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 35 |
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| 36 |
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
pyomo/source/MANIFEST.in
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
include README.md
|
| 2 |
+
include LICENSE.md
|
pyomo/source/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[](https://github.com/Pyomo/pyomo/actions/workflows/test_pr_and_main.yml?query=branch%3Amain+event%3Apush)
|
| 2 |
+
[](https://pyomo-jenkins.sandia.gov/)
|
| 3 |
+
[](https://codecov.io/gh/Pyomo/pyomo)
|
| 4 |
+
[](https://pyomo.readthedocs.org/en/latest/)
|
| 5 |
+
[](https://pyomo-jenkins.sandia.gov/)
|
| 6 |
+
[](https://github.com/pyomo/pyomo/graphs/contributors)
|
| 7 |
+
[](https://github.com/pyomo/pyomo/pulls?q=is:pr+is:merged)
|
| 8 |
+
|
| 9 |
+
[](https://www.coin-or.org)
|
| 10 |
+
|
| 11 |
+
## Pyomo Overview
|
| 12 |
+
|
| 13 |
+
Pyomo is a Python-based open-source software package that supports a
|
| 14 |
+
diverse set of optimization capabilities for formulating and analyzing
|
| 15 |
+
optimization models. Pyomo can be used to define symbolic problems,
|
| 16 |
+
create concrete problem instances, and solve these instances with
|
| 17 |
+
standard solvers. Pyomo supports a wide range of problem types,
|
| 18 |
+
including:
|
| 19 |
+
|
| 20 |
+
- Linear programming
|
| 21 |
+
- Quadratic programming
|
| 22 |
+
- Nonlinear programming
|
| 23 |
+
- Mixed-integer linear programming
|
| 24 |
+
- Mixed-integer quadratic programming
|
| 25 |
+
- Mixed-integer nonlinear programming
|
| 26 |
+
- Mixed-integer stochastic programming
|
| 27 |
+
- Generalized disjunctive programming
|
| 28 |
+
- Differential algebraic equations
|
| 29 |
+
- Mathematical programming with equilibrium constraints
|
| 30 |
+
- Constraint programming
|
| 31 |
+
|
| 32 |
+
Pyomo supports analysis and scripting within a full-featured programming
|
| 33 |
+
language. Further, Pyomo has also proven an effective framework for
|
| 34 |
+
developing high-level optimization and analysis tools. For example, the
|
| 35 |
+
[`mpi-sppy`](https://github.com/Pyomo/mpi-sppy) package provides generic
|
| 36 |
+
solvers for stochastic programming. `mpi-sppy` leverages the fact that
|
| 37 |
+
Pyomo's modeling objects are embedded within a full-featured high-level
|
| 38 |
+
programming language, which allows for transparent parallelization of
|
| 39 |
+
subproblems using Python parallel communication libraries.
|
| 40 |
+
|
| 41 |
+
* [Pyomo Home](https://www.pyomo.org)
|
| 42 |
+
* [About Pyomo](https://www.pyomo.org/about)
|
| 43 |
+
* [Download](https://www.pyomo.org/installation/)
|
| 44 |
+
* [Documentation](https://www.pyomo.org/documentation/)
|
| 45 |
+
* [Performance Plots](https://pyomo.github.io/performance/)
|
| 46 |
+
|
| 47 |
+
Pyomo was formerly released as the Coopr software library.
|
| 48 |
+
|
| 49 |
+
Pyomo is available under the BSD License - see the
|
| 50 |
+
[`LICENSE.md`](https://github.com/Pyomo/pyomo/blob/main/LICENSE.md) file.
|
| 51 |
+
|
| 52 |
+
Pyomo is currently tested with the following Python implementations:
|
| 53 |
+
|
| 54 |
+
* CPython: 3.10, 3.11, 3.12, 3.13, 3.14
|
| 55 |
+
* PyPy: 3.11
|
| 56 |
+
|
| 57 |
+
_Testing and support policy_:
|
| 58 |
+
|
| 59 |
+
At the time of the first Pyomo release after the end-of-life of a minor Python
|
| 60 |
+
version, we will remove testing for that Python version.
|
| 61 |
+
|
| 62 |
+
### Installation
|
| 63 |
+
|
| 64 |
+
#### PyPI   [](https://pypi.org/project/Pyomo/) [](https://pypistats.org/packages/pyomo)
|
| 65 |
+
|
| 66 |
+
pip install pyomo
|
| 67 |
+
|
| 68 |
+
#### Anaconda   [](https://anaconda.org/conda-forge/pyomo) [](https://anaconda.org/conda-forge/pyomo)
|
| 69 |
+
|
| 70 |
+
conda install -c conda-forge pyomo
|
| 71 |
+
|
| 72 |
+
### Tutorials and Examples
|
| 73 |
+
|
| 74 |
+
* [Pyomo — Optimization Modeling in Python](https://link.springer.com/book/10.1007/978-3-030-68928-5)
|
| 75 |
+
* [Pyomo Workshop Slides](https://github.com/Pyomo/pyomo-tutorials/blob/main/Pyomo-Workshop-December-2023.pdf)
|
| 76 |
+
* [Prof. Jeffrey Kantor's Pyomo Cookbook](https://jckantor.github.io/ND-Pyomo-Cookbook/)
|
| 77 |
+
* The [companion notebooks](https://mobook.github.io/MO-book/intro.html)
|
| 78 |
+
for *Hands-On Mathematical Optimization with Python*
|
| 79 |
+
* [Pyomo Gallery](https://github.com/Pyomo/PyomoGallery)
|
| 80 |
+
|
| 81 |
+
### Getting Help
|
| 82 |
+
|
| 83 |
+
To get help from the Pyomo community ask a question on one of the following:
|
| 84 |
+
* [Use the #pyomo tag on StackOverflow](https://stackoverflow.com/questions/ask?tags=pyomo)
|
| 85 |
+
* [Pyomo Forum](https://groups.google.com/forum/?hl=en#!forum/pyomo-forum)
|
| 86 |
+
|
| 87 |
+
### Developers
|
| 88 |
+
|
| 89 |
+
Pyomo development moved to this repository in June 2016 from
|
| 90 |
+
Sandia National Laboratories. Developer discussions are hosted by
|
| 91 |
+
[Google Groups](https://groups.google.com/forum/#!forum/pyomo-developers).
|
| 92 |
+
|
| 93 |
+
The Pyomo Development team holds weekly coordination meetings on
|
| 94 |
+
Tuesdays 12:30 - 14:00 (MT). Please contact wg-pyomo@sandia.gov to
|
| 95 |
+
request call-in information.
|
| 96 |
+
|
| 97 |
+
By contributing to this software project, you are agreeing to the
|
| 98 |
+
following terms and conditions for your contributions:
|
| 99 |
+
|
| 100 |
+
1. You agree your contributions are submitted under the BSD license.
|
| 101 |
+
2. You represent you are authorized to make the contributions and grant
|
| 102 |
+
the license. If your employer has rights to intellectual property that
|
| 103 |
+
includes your contributions, you represent that you have received
|
| 104 |
+
permission to make contributions and grant the required license on
|
| 105 |
+
behalf of that employer.
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
### Related Packages
|
| 109 |
+
|
| 110 |
+
See https://pyomo.readthedocs.io/en/latest/related_packages.html.
|
pyomo/source/RELEASE.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
We are pleased to announce the release of Pyomo 6.9.5.
|
| 2 |
+
|
| 3 |
+
Pyomo is a collection of Python software packages that supports a
|
| 4 |
+
diverse set of optimization capabilities for formulating and analyzing
|
| 5 |
+
optimization models.
|
| 6 |
+
|
| 7 |
+
The following are highlights of the 6.9 release series:
|
| 8 |
+
|
| 9 |
+
- Removed support for Python 3.8
|
| 10 |
+
- Added support for Python 3.14
|
| 11 |
+
- New Logic-Based Discrete-Steepest Descent Algorithm in GDPOpt
|
| 12 |
+
- New External Function for Cubic Spline Interpolation
|
| 13 |
+
- New ASL External Functions Library
|
| 14 |
+
- New solver interfaces:
|
| 15 |
+
- `knitro_direct` KNITRO Python bindings interface
|
| 16 |
+
- Add `gurobi_direct` support for MINLP
|
| 17 |
+
- v2: Ongoing solver interface refactor
|
| 18 |
+
- ...and of course numerous minor bug fixes and performance enhancements
|
| 19 |
+
|
| 20 |
+
A full list of updates and changes is available in the
|
| 21 |
+
[`CHANGELOG.md`](https://github.com/Pyomo/pyomo/blob/main/CHANGELOG.md).
|
| 22 |
+
|
| 23 |
+
Enjoy!
|
| 24 |
+
|
| 25 |
+
- Pyomo Developer Team
|
| 26 |
+
- pyomo-developers@googlegroups.com
|
| 27 |
+
- https://www.pyomo.org
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
About Pyomo
|
| 31 |
+
-----------
|
| 32 |
+
|
| 33 |
+
The Pyomo home page provides resources for Pyomo users:
|
| 34 |
+
|
| 35 |
+
* https://www.pyomo.org
|
| 36 |
+
|
| 37 |
+
Detailed documentation is hosted on Read the Docs:
|
| 38 |
+
|
| 39 |
+
* https://pyomo.readthedocs.io/en/stable/
|
| 40 |
+
|
| 41 |
+
Pyomo development is hosted at GitHub:
|
| 42 |
+
|
| 43 |
+
* https://github.com/Pyomo
|
| 44 |
+
|
| 45 |
+
Get help at:
|
| 46 |
+
|
| 47 |
+
* StackOverflow: https://stackoverflow.com/questions/tagged/pyomo
|
| 48 |
+
* Pyomo Forum: https://groups.google.com/group/pyomo-forum/
|
pyomo/source/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
pyomo Project Package Initialization File
|
| 4 |
+
"""
|
pyomo/source/conftest.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ___________________________________________________________________________
|
| 2 |
+
#
|
| 3 |
+
# Pyomo: Python Optimization Modeling Objects
|
| 4 |
+
# Copyright (c) 2008-2025
|
| 5 |
+
# National Technology and Engineering Solutions of Sandia, LLC
|
| 6 |
+
# Under the terms of Contract DE-NA0003525 with National Technology and
|
| 7 |
+
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
|
| 8 |
+
# rights in this software.
|
| 9 |
+
# This software is distributed under the 3-clause BSD License.
|
| 10 |
+
# ___________________________________________________________________________
|
| 11 |
+
|
| 12 |
+
import pytest
|
| 13 |
+
|
| 14 |
+
_implicit_markers = {'default'}
|
| 15 |
+
_extended_implicit_markers = _implicit_markers.union({'solver'})
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def pytest_collection_modifyitems(items):
|
| 19 |
+
"""
|
| 20 |
+
This method will mark any unmarked tests with the implicit marker ('default')
|
| 21 |
+
|
| 22 |
+
"""
|
| 23 |
+
for item in items:
|
| 24 |
+
try:
|
| 25 |
+
next(item.iter_markers())
|
| 26 |
+
except StopIteration:
|
| 27 |
+
for marker in _implicit_markers:
|
| 28 |
+
item.add_marker(getattr(pytest.mark, marker))
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def pytest_runtest_setup(item):
|
| 32 |
+
"""
|
| 33 |
+
This method overrides pytest's default behavior for marked tests.
|
| 34 |
+
|
| 35 |
+
The logic below follows this flow:
|
| 36 |
+
1) Did the user ask for a specific solver using the '--solver' flag?
|
| 37 |
+
If so: Add skip statements to any test NOT labeled with the
|
| 38 |
+
requested solver category.
|
| 39 |
+
2) Did the user ask for a specific marker using the '-m' flag?
|
| 40 |
+
If so: Return to pytest's default behavior.
|
| 41 |
+
3) If the user requested no specific solver or marker, look at each
|
| 42 |
+
test for the following:
|
| 43 |
+
a) If unmarked, run the test
|
| 44 |
+
b) If marked with implicit_markers, run the test
|
| 45 |
+
c) If marked "solver" and NOT any explicit marker, run the test
|
| 46 |
+
OTHERWISE: Skip the test.
|
| 47 |
+
In other words - we want to run unmarked, implicit, and solver tests as
|
| 48 |
+
the default mode; but if solver tests are also marked with an explicit
|
| 49 |
+
category (e.g., "expensive"), we will skip them.
|
| 50 |
+
"""
|
| 51 |
+
solvernames = [mark.args[0] for mark in item.iter_markers(name="solver")]
|
| 52 |
+
solveroption = item.config.getoption("--solver")
|
| 53 |
+
markeroption = item.config.getoption("-m")
|
| 54 |
+
item_markers = set(mark.name for mark in item.iter_markers())
|
| 55 |
+
if solveroption:
|
| 56 |
+
if solveroption not in solvernames:
|
| 57 |
+
pytest.skip("SKIPPED: Test not marked {!r}".format(solveroption))
|
| 58 |
+
return
|
| 59 |
+
elif markeroption:
|
| 60 |
+
return
|
| 61 |
+
elif item_markers:
|
| 62 |
+
if not _implicit_markers.issubset(item_markers) and not item_markers.issubset(
|
| 63 |
+
_extended_implicit_markers
|
| 64 |
+
):
|
| 65 |
+
pytest.skip('SKIPPED: Only running default, solver, and unmarked tests.')
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def pytest_addoption(parser):
|
| 69 |
+
"""
|
| 70 |
+
Add another parser option to specify suite of solver tests to run
|
| 71 |
+
"""
|
| 72 |
+
parser.addoption(
|
| 73 |
+
"--solver",
|
| 74 |
+
action="store",
|
| 75 |
+
metavar="SOLVER",
|
| 76 |
+
help="Run tests matching the requested SOLVER.",
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def pytest_configure(config):
|
| 81 |
+
"""
|
| 82 |
+
Register additional solver marker, as applicable.
|
| 83 |
+
This stops pytest from printing a warning about unregistered solver options.
|
| 84 |
+
"""
|
| 85 |
+
config.addinivalue_line(
|
| 86 |
+
"markers", "solver(name): mark test to run the named solver"
|
| 87 |
+
)
|
pyomo/source/doc/OnlineDocs/Makefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Minimal makefile for Sphinx documentation
|
| 2 |
+
#
|
| 3 |
+
|
| 4 |
+
# You can set these variables from the command line.
|
| 5 |
+
SPHINXOPTS =
|
| 6 |
+
SPHINXBUILD = sphinx-build
|
| 7 |
+
SPHINXPROJ = Pyomo
|
| 8 |
+
SOURCEDIR = .
|
| 9 |
+
BUILDDIR = _build
|
| 10 |
+
APIDIR = api
|
| 11 |
+
|
| 12 |
+
# Put it first so that "make" without argument is like "make help".
|
| 13 |
+
help:
|
| 14 |
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
| 15 |
+
|
| 16 |
+
.PHONY: help Makefile
|
| 17 |
+
|
| 18 |
+
# Catch-all target: route all unknown targets to Sphinx using the new
|
| 19 |
+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
| 20 |
+
%: Makefile
|
| 21 |
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
| 22 |
+
|
| 23 |
+
clean:
|
| 24 |
+
@$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
| 25 |
+
@echo "Removing *.spy"
|
| 26 |
+
@find . -name \*.spy -delete
|
| 27 |
+
@for D in $(BUILDDIR) $(SOURCEDIR)/$(APIDIR); do \
|
| 28 |
+
if test -d "$$D"; then echo "Removing $$D"; rm -r "$$D"; fi \
|
| 29 |
+
done
|
| 30 |
+
@for D in ext src; do \
|
| 31 |
+
if test -d "$$D/__pycache__"; then \
|
| 32 |
+
echo "Removing $$D/__pycache__"; rm -r "$$D/__pycache__" ; \
|
| 33 |
+
fi \
|
| 34 |
+
done
|
| 35 |
+
|
| 36 |
+
rebuild: clean html
|
pyomo/source/doc/OnlineDocs/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Pyomo leverages ``make`` to generate documentation. The following two
|
| 2 |
+
sections describe how to build and test the online documentation
|
| 3 |
+
locally.
|
| 4 |
+
|
| 5 |
+
> **NOTE**: All commands assume you are running from the *root Pyomo source directory*.
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
Preview Changes Locally
|
| 9 |
+
-----------------------
|
| 10 |
+
|
| 11 |
+
1. Install documentation dependencies (e.g., Sphinx, etc):
|
| 12 |
+
|
| 13 |
+
```bash
|
| 14 |
+
$ pip install -e .[docs]
|
| 15 |
+
```
|
| 16 |
+
|
| 17 |
+
> **NOTE**: You may get a warning about the `dot` command if you do
|
| 18 |
+
> not have `graphviz` installed.
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
2. Build the documentation. Sphinx (and Pyomo) support multiple
|
| 22 |
+
documentation *targets*. These instructions describe building the
|
| 23 |
+
`html` target, but the same process applies for other targets.
|
| 24 |
+
|
| 25 |
+
```bash
|
| 26 |
+
$ make -C doc/OnlineDocs html
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
3. View ``doc/OnlineDocs/_build/html/index.html`` in your browser
|
| 30 |
+
|
| 31 |
+
Test Changes Locally
|
| 32 |
+
--------------------
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
$ make -C doc/OnlineDocs doctest
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
Rebuilding the documentation
|
| 39 |
+
----------------------------
|
| 40 |
+
|
| 41 |
+
Sphinx caches significant amounts of work at the end of a documentation
|
| 42 |
+
build. However, if you are in the process of editing the documentation,
|
| 43 |
+
it may not correctly invalidate the cache. You can purge the entire
|
| 44 |
+
cache with
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
$ make -C doc/OnlineDocs clean
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
Combining steps
|
| 51 |
+
---------------
|
| 52 |
+
|
| 53 |
+
These steps can, of course, be combined into a single command:
|
| 54 |
+
|
| 55 |
+
```bash
|
| 56 |
+
$ make -c doc/OnlineDocs clean html doctest
|
| 57 |
+
```
|
| 58 |
+
|
| 59 |
+
Documentation history
|
| 60 |
+
---------------------
|
| 61 |
+
|
| 62 |
+
The Pyomo online documentation went through a significant overhaul in
|
| 63 |
+
2024. If you need to go back and look at the old documentation, the
|
| 64 |
+
following git hashes might be relevant:
|
| 65 |
+
|
| 66 |
+
- [23fb726ce](https://github.com/Pyomo/pyomo/commit/23fb726ce0e092412081bd70e8a0370af46f6d0f):
|
| 67 |
+
main (close to just) before the reorg was merged
|
| 68 |
+
|
| 69 |
+
- [c157587fc](https://github.com/Pyomo/pyomo/commit/c157587fc9a03300b53879b99c1f350a26a9519f):
|
| 70 |
+
reorg branch just before the `Archive` subdirectory was removed
|
pyomo/source/doc/OnlineDocs/_static/theme_overrides.css
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* links and fixed-with literals should NOT be bold */
|
| 2 |
+
.rst-content code {
|
| 3 |
+
font-weight: normal !important;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
/* internal reference links should be purple (not grey) */
|
| 7 |
+
code.xref.py {
|
| 8 |
+
color: #8C1AFF;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
/* method names should be bold */
|
| 12 |
+
code.descname {
|
| 13 |
+
font-weight: bold !important;
|
| 14 |
+
color: black;
|
| 15 |
+
}
|
| 16 |
+
/* method argument lists should *not* be bold, argument names in black */
|
| 17 |
+
dl.py.method dt {
|
| 18 |
+
font-weight: normal;
|
| 19 |
+
}
|
| 20 |
+
dl.py.method dt em span.n {
|
| 21 |
+
color: black;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
/* Fix to RTD theme to allow table cell content to wrap */
|
| 25 |
+
@media screen and (min-width: 767px) {
|
| 26 |
+
.wy-table-responsive table td {
|
| 27 |
+
white-space: normal !important;
|
| 28 |
+
}
|
| 29 |
+
.wy-table-responsive {
|
| 30 |
+
overflow: visible !important;
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.rst-content table.diataxis td {
|
| 35 |
+
vertical-align: top;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.rst-content table.diataxis li.toctree-l1 {
|
| 39 |
+
list-style-type: none;
|
| 40 |
+
font-weight: bold;
|
| 41 |
+
font-size: x-large;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
.rst-content table.diataxis li ul li {
|
| 45 |
+
list-style-type: none;
|
| 46 |
+
font-weight: normal;
|
| 47 |
+
font-size: medium;
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.rst-content table.diataxis li ul li ul li {
|
| 51 |
+
list-style-type: "- ";
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
/* Remove space after tables in definition lists (e.g., for function
|
| 56 |
+
"Parameters" lists*/
|
| 57 |
+
.rst-content dl div.wy-table-responsive {
|
| 58 |
+
margin-bottom: 12px !important;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
/* Define a new "tight-table" class that we can use to format tighter
|
| 62 |
+
simple banded tables */
|
| 63 |
+
.rst-content table.tight-table {
|
| 64 |
+
border-style: solid;
|
| 65 |
+
border-collapse: separate !important;
|
| 66 |
+
}
|
| 67 |
+
.rst-content table.tight-table td {
|
| 68 |
+
border-style: hidden !important;
|
| 69 |
+
padding-top: 4px !important;
|
| 70 |
+
padding-bottom: 4px !important;
|
| 71 |
+
padding-left: 8px !important;
|
| 72 |
+
padding-right: 8px !important;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
/* Define a new "scrollwide-table" class so that we allow tables
|
| 76 |
+
to scroll instead of overflow */
|
| 77 |
+
.rst-content table.scrollwide-table {
|
| 78 |
+
overflow: scroll !important;
|
| 79 |
+
display: block;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
/* OLD theme overrides
|
| 83 |
+
|
| 84 |
+
code.docutils.literal{
|
| 85 |
+
color:#8C1AFF;
|
| 86 |
+
border: 0px;
|
| 87 |
+
background-color:#fcfcfc;
|
| 88 |
+
padding:0px;
|
| 89 |
+
font-size: 100%;
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
.wy-table-responsive table td, .wy-table-responsive table th {
|
| 93 |
+
white-space: normal;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
.wy-table-responsive {
|
| 97 |
+
margin-bottom: 24px;
|
| 98 |
+
max-width: 100%;
|
| 99 |
+
overflow: visible;
|
| 100 |
+
}
|
| 101 |
+
*/
|
pyomo/source/doc/OnlineDocs/_templates/layout.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% extends "!layout.html" %}
|
| 2 |
+
{# Explicitly put RTD's ads in the sidebar. If we don't specify a
|
| 3 |
+
location, RTD puts them at the bottom of the page content in a
|
| 4 |
+
style that is easily visually confused with the documentation
|
| 5 |
+
content.
|
| 6 |
+
#}
|
| 7 |
+
{%- block navigation %}
|
| 8 |
+
{{ super() }}
|
| 9 |
+
<div id="side-ad-box" style="max-width:90%; margin-left: auto; margin-right: auto;">
|
| 10 |
+
<hr/>
|
| 11 |
+
<div id="readthedocs-ea" class="raised ethical-rtd ethical-dark-theme">
|
| 12 |
+
<div id="ethical-ad-placement"></div>
|
| 13 |
+
</div
|
| 14 |
+
</div>
|
| 15 |
+
{% endblock %}
|
pyomo/source/doc/OnlineDocs/_templates/recursive-base.rst
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ name | escape | underline}}
|
| 2 |
+
|
| 3 |
+
({{ objtype }} from :py:mod:`{{ module }}`)
|
| 4 |
+
|
| 5 |
+
.. testsetup:: *
|
| 6 |
+
|
| 7 |
+
# import everything from the module containing this class so that
|
| 8 |
+
# doctests for the class docstrings see the correct environment
|
| 9 |
+
from {{ module }} import *
|
| 10 |
+
try:
|
| 11 |
+
from {{ module }} import _autosummary_doctest_setup
|
| 12 |
+
_autosummary_doctest_setup()
|
| 13 |
+
except ImportError:
|
| 14 |
+
pass
|
| 15 |
+
|
| 16 |
+
.. currentmodule:: {{ module }}
|
| 17 |
+
|
| 18 |
+
.. auto{{ objtype }}:: {{ module }}::{{ objname }}
|
pyomo/source/doc/OnlineDocs/_templates/recursive-class.rst
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ name | escape | underline}}
|
| 2 |
+
|
| 3 |
+
(class from :py:mod:`{{ module }}`)
|
| 4 |
+
|
| 5 |
+
.. testsetup:: *
|
| 6 |
+
|
| 7 |
+
# import everything from the module containing this class so that
|
| 8 |
+
# doctests for the class docstrings see the correct environment
|
| 9 |
+
from {{ module }} import *
|
| 10 |
+
try:
|
| 11 |
+
from {{ module }} import _autosummary_doctest_setup
|
| 12 |
+
_autosummary_doctest_setup()
|
| 13 |
+
except ImportError:
|
| 14 |
+
pass
|
| 15 |
+
|
| 16 |
+
.. currentmodule:: {{ module }}
|
| 17 |
+
|
| 18 |
+
{# Note that numpy.ndarray examples fail doctest; disable documentation
|
| 19 |
+
of inherited members for classes derived from ndarray #}
|
| 20 |
+
|
| 21 |
+
.. autoclass:: {{ module }}::{{ objname }}
|
| 22 |
+
:members:
|
| 23 |
+
:show-inheritance:
|
| 24 |
+
{{ '' if (module + '.' + name) in (
|
| 25 |
+
'pyomo.contrib.pynumero.sparse.block_vector.BlockVector',
|
| 26 |
+
'pyomo.contrib.pynumero.sparse.mpi_block_vector.MPIBlockVector',
|
| 27 |
+
'pyomo.core.expr.ndarray.NumericNDArray',
|
| 28 |
+
) else ':inherited-members:' }}
|
| 29 |
+
|
| 30 |
+
{% block methods %}
|
| 31 |
+
.. automethod:: __init__
|
| 32 |
+
|
| 33 |
+
{% if methods %}
|
| 34 |
+
.. rubric:: {{ _('Methods') }}
|
| 35 |
+
|
| 36 |
+
.. autosummary::
|
| 37 |
+
{% for item in methods %}
|
| 38 |
+
~{{ name }}.{{ item }}
|
| 39 |
+
{%- endfor %}
|
| 40 |
+
{% endif %}
|
| 41 |
+
{% endblock %}
|
| 42 |
+
|
| 43 |
+
{% block attributes %}
|
| 44 |
+
{% if attributes %}
|
| 45 |
+
.. rubric:: {{ _('Attributes') }}
|
| 46 |
+
|
| 47 |
+
.. autosummary::
|
| 48 |
+
{% for item in attributes %}
|
| 49 |
+
~{{ name }}.{{ item }}
|
| 50 |
+
{%- endfor %}
|
| 51 |
+
{% endif %}
|
| 52 |
+
{% endblock %}
|
| 53 |
+
|
| 54 |
+
.. rubric:: Member Documentation
|
pyomo/source/doc/OnlineDocs/_templates/recursive-enum.rst
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ name | escape | underline}}
|
| 2 |
+
|
| 3 |
+
(enum from :py:mod:`{{ module }}`)
|
| 4 |
+
|
| 5 |
+
.. testsetup:: *
|
| 6 |
+
|
| 7 |
+
# import everything from the module containing this class so that
|
| 8 |
+
# doctests for the class docstrings see the correct environment
|
| 9 |
+
from {{ module }} import *
|
| 10 |
+
try:
|
| 11 |
+
from {{ module }} import _autosummary_doctest_setup
|
| 12 |
+
_autosummary_doctest_setup()
|
| 13 |
+
except ImportError:
|
| 14 |
+
pass
|
| 15 |
+
|
| 16 |
+
.. currentmodule:: {{ module }}
|
| 17 |
+
|
| 18 |
+
.. autoenum:: {{ module }}::{{ objname }}
|
| 19 |
+
:members:
|
| 20 |
+
:inherited-members:
|
| 21 |
+
:undoc-members:
|
| 22 |
+
:show-inheritance:
|
| 23 |
+
|
| 24 |
+
{% block enum_members %}
|
| 25 |
+
{% if enum_members %}
|
| 26 |
+
.. rubric:: {{ _('Enum Members') }}
|
| 27 |
+
|
| 28 |
+
{{ member_type }}
|
| 29 |
+
|
| 30 |
+
.. autosummary::
|
| 31 |
+
{% for item in enum_members %}
|
| 32 |
+
~{{ name }}.{{ item }}
|
| 33 |
+
{%- endfor %}
|
| 34 |
+
{% endif %}
|
| 35 |
+
{% endblock %}
|
| 36 |
+
|
| 37 |
+
{% block methods %}
|
| 38 |
+
{% if methods %}
|
| 39 |
+
.. rubric:: {{ _('Methods') }}
|
| 40 |
+
|
| 41 |
+
.. autosummary::
|
| 42 |
+
{% for item in methods %}
|
| 43 |
+
~{{ name }}.{{ item }}
|
| 44 |
+
{%- endfor %}
|
| 45 |
+
{% endif %}
|
| 46 |
+
{% endblock %}
|
| 47 |
+
|
| 48 |
+
{% block attributes %}
|
| 49 |
+
{% if attributes %}
|
| 50 |
+
.. rubric:: {{ _('Attributes') }}
|
| 51 |
+
|
| 52 |
+
.. autosummary::
|
| 53 |
+
{% for item in attributes %}
|
| 54 |
+
~{{ name }}.{{ item }}
|
| 55 |
+
{%- endfor %}
|
| 56 |
+
{% endif %}
|
| 57 |
+
{% endblock %}
|
| 58 |
+
|
| 59 |
+
.. rubric:: Member Documentation
|
pyomo/source/doc/OnlineDocs/_templates/recursive-module.rst
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if fullname == 'pyomo' %}
|
| 2 |
+
Library Reference
|
| 3 |
+
=================
|
| 4 |
+
{% else %}
|
| 5 |
+
{{ name | escape | underline}}
|
| 6 |
+
{% endif %}
|
| 7 |
+
|
| 8 |
+
.. testsetup:: *
|
| 9 |
+
|
| 10 |
+
# import everything from the module containing this class so that
|
| 11 |
+
# doctests for the class docstrings see the correct environment
|
| 12 |
+
from {{ module }} import *
|
| 13 |
+
try:
|
| 14 |
+
from {{ module }} import _autosummary_doctest_setup
|
| 15 |
+
_autosummary_doctest_setup()
|
| 16 |
+
except ImportError:
|
| 17 |
+
pass
|
| 18 |
+
|
| 19 |
+
.. currentmodule:: {{ module }}
|
| 20 |
+
|
| 21 |
+
.. automodule:: {{ fullname }}
|
| 22 |
+
:undoc-members:
|
| 23 |
+
|
| 24 |
+
{% block attributes %}
|
| 25 |
+
{%- if attributes %}
|
| 26 |
+
.. rubric:: {{ _('Module Attributes') }}
|
| 27 |
+
|
| 28 |
+
.. autosummary::
|
| 29 |
+
:toctree:
|
| 30 |
+
:template: recursive-base.rst
|
| 31 |
+
{% for item in attributes %}
|
| 32 |
+
{{ item }}
|
| 33 |
+
{%- endfor %}
|
| 34 |
+
{% endif %}
|
| 35 |
+
{%- endblock %}
|
| 36 |
+
|
| 37 |
+
{% block enums %}
|
| 38 |
+
{%- if enums %}
|
| 39 |
+
.. rubric:: {{ _('Enums') }}
|
| 40 |
+
|
| 41 |
+
.. autosummary::
|
| 42 |
+
:toctree:
|
| 43 |
+
:template: recursive-enum.rst
|
| 44 |
+
{% for item in enums %}
|
| 45 |
+
{{ item }}
|
| 46 |
+
{%- endfor %}
|
| 47 |
+
{% endif %}
|
| 48 |
+
{%- endblock %}
|
| 49 |
+
|
| 50 |
+
{%- block classes %}
|
| 51 |
+
{%- if classes %}
|
| 52 |
+
.. rubric:: {{ _('Classes') }}
|
| 53 |
+
|
| 54 |
+
.. autosummary::
|
| 55 |
+
:toctree:
|
| 56 |
+
:template: recursive-class.rst
|
| 57 |
+
{% for item in classes %}
|
| 58 |
+
{{ item }}
|
| 59 |
+
{%- endfor %}
|
| 60 |
+
{% endif %}
|
| 61 |
+
{%- endblock %}
|
| 62 |
+
|
| 63 |
+
{%- block exceptions %}
|
| 64 |
+
{%- if exceptions %}
|
| 65 |
+
.. rubric:: {{ _('Exceptions') }}
|
| 66 |
+
|
| 67 |
+
.. autosummary::
|
| 68 |
+
:toctree:
|
| 69 |
+
:template: recursive-class.rst
|
| 70 |
+
{% for item in exceptions %}
|
| 71 |
+
{{ item }}
|
| 72 |
+
{%- endfor %}
|
| 73 |
+
{% endif %}
|
| 74 |
+
{%- endblock %}
|
| 75 |
+
|
| 76 |
+
{%- block functions %}
|
| 77 |
+
{%- if functions %}
|
| 78 |
+
.. rubric:: {{ _('Functions') }}
|
| 79 |
+
|
| 80 |
+
.. autosummary::
|
| 81 |
+
:toctree:
|
| 82 |
+
:template: recursive-base.rst
|
| 83 |
+
{% for item in functions %}
|
| 84 |
+
{{ item }}
|
| 85 |
+
{%- endfor %}
|
| 86 |
+
{% endif %}
|
| 87 |
+
{%- endblock %}
|
| 88 |
+
|
| 89 |
+
{%- block modules %}
|
| 90 |
+
{%- if modules %}
|
| 91 |
+
.. rubric:: Modules
|
| 92 |
+
|
| 93 |
+
.. autosummary::
|
| 94 |
+
:toctree:
|
| 95 |
+
:template: recursive-module.rst
|
| 96 |
+
:recursive:
|
| 97 |
+
{% for item in all_modules %}
|
| 98 |
+
{# Need item != tests for Sphinx >= 8.0; !endswith(.tests) for < 8.0 #}
|
| 99 |
+
{% if item != 'tests' and not item.endswith('.tests')
|
| 100 |
+
and item != 'examples' and not item.endswith('.examples') %}
|
| 101 |
+
{{ item }}
|
| 102 |
+
{% endif %}
|
| 103 |
+
{%- endfor %}
|
| 104 |
+
{% endif %}
|
| 105 |
+
{%- endblock %}
|
pyomo/source/doc/OnlineDocs/code.rst
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:orphan:
|
| 2 |
+
|
| 3 |
+
This document is a reference containing all Pyomo module, class, and
|
| 4 |
+
function documentation.
|
| 5 |
+
|
| 6 |
+
.. autosummary::
|
| 7 |
+
:toctree: api
|
| 8 |
+
:caption: Library Reference
|
| 9 |
+
:template: recursive-module.rst
|
| 10 |
+
:recursive:
|
| 11 |
+
|
| 12 |
+
pyomo
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
* :ref:`genindex`
|
| 16 |
+
* :ref:`modindex`
|
pyomo/source/doc/OnlineDocs/conf.py
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ___________________________________________________________________________
|
| 2 |
+
#
|
| 3 |
+
# Pyomo: Python Optimization Modeling Objects
|
| 4 |
+
# Copyright (c) 2008-2025
|
| 5 |
+
# National Technology and Engineering Solutions of Sandia, LLC
|
| 6 |
+
# Under the terms of Contract DE-NA0003525 with National Technology and
|
| 7 |
+
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
|
| 8 |
+
# rights in this software.
|
| 9 |
+
# This software is distributed under the 3-clause BSD License.
|
| 10 |
+
# ___________________________________________________________________________
|
| 11 |
+
|
| 12 |
+
#!/usr/bin/env python3
|
| 13 |
+
# -*- coding: utf-8 -*-
|
| 14 |
+
#
|
| 15 |
+
# pyomo documentation build configuration file, created by
|
| 16 |
+
# sphinx-quickstart on Mon Dec 12 16:08:36 2016.
|
| 17 |
+
#
|
| 18 |
+
# This file is execfile()d with the current directory set to its
|
| 19 |
+
# containing dir.
|
| 20 |
+
#
|
| 21 |
+
# Note that not all possible configuration values are present in this
|
| 22 |
+
# autogenerated file.
|
| 23 |
+
#
|
| 24 |
+
# All configuration values have a default; values that are commented out
|
| 25 |
+
# serve to show the default.
|
| 26 |
+
|
| 27 |
+
import os
|
| 28 |
+
import sys
|
| 29 |
+
|
| 30 |
+
# If extensions (or modules to document with autodoc) are in another directory,
|
| 31 |
+
# add these directories to sys.path here. If the directory is relative to the
|
| 32 |
+
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
| 33 |
+
#
|
| 34 |
+
# assumes pyutilib source is next to the pyomo source directory
|
| 35 |
+
sys.path.insert(0, os.path.abspath('../../../pyutilib'))
|
| 36 |
+
# top-level pyomo source directory
|
| 37 |
+
sys.path.insert(0, os.path.abspath('../..'))
|
| 38 |
+
# our sphinx extensions
|
| 39 |
+
sys.path.insert(0, os.path.abspath('ext'))
|
| 40 |
+
|
| 41 |
+
# -- Mark that we are running Sphinx --------------------------------------
|
| 42 |
+
import pyomo
|
| 43 |
+
|
| 44 |
+
# Mark a "convenient" and reasonably unique global flag that we can use
|
| 45 |
+
# elsewhere to reliably tell if Sphinx is building / testing the docs
|
| 46 |
+
pyomo.__sphinx_build__ = True
|
| 47 |
+
|
| 48 |
+
# -- Rebuild SPY files ----------------------------------------------------
|
| 49 |
+
sys.path.insert(0, os.path.abspath('src'))
|
| 50 |
+
try:
|
| 51 |
+
print("Regenerating SPY files...")
|
| 52 |
+
from strip_examples import generate_spy_files
|
| 53 |
+
|
| 54 |
+
generate_spy_files(os.path.abspath('src'))
|
| 55 |
+
generate_spy_files(
|
| 56 |
+
os.path.abspath(os.path.join('explanation', 'experimental', 'kernel'))
|
| 57 |
+
)
|
| 58 |
+
finally:
|
| 59 |
+
sys.path.pop(0)
|
| 60 |
+
|
| 61 |
+
# -- Options for intersphinx ---------------------------------------------
|
| 62 |
+
|
| 63 |
+
intersphinx_mapping = {
|
| 64 |
+
'python': ('https://docs.python.org/3', None),
|
| 65 |
+
'matplotlib': ('https://matplotlib.org/stable/', None),
|
| 66 |
+
'numpy': ('https://numpy.org/doc/stable/', None),
|
| 67 |
+
'pandas': ('https://pandas.pydata.org/docs/', None),
|
| 68 |
+
'scikit-learn': ('https://scikit-learn.org/stable/', None),
|
| 69 |
+
'scipy': ('https://docs.scipy.org/doc/scipy/', None),
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
# -- General configuration ------------------------------------------------
|
| 73 |
+
|
| 74 |
+
# If your documentation needs a minimal Sphinx version, state it here.
|
| 75 |
+
#
|
| 76 |
+
needs_sphinx = '1.8'
|
| 77 |
+
|
| 78 |
+
# Add any Sphinx extension module names here, as strings. They can be
|
| 79 |
+
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
| 80 |
+
# ones.
|
| 81 |
+
extensions = [
|
| 82 |
+
'sphinx.ext.intersphinx',
|
| 83 |
+
'sphinx.ext.coverage',
|
| 84 |
+
'sphinx.ext.mathjax',
|
| 85 |
+
'sphinx.ext.viewcode',
|
| 86 |
+
'sphinx.ext.napoleon',
|
| 87 |
+
'sphinx.ext.inheritance_diagram',
|
| 88 |
+
'sphinx.ext.doctest',
|
| 89 |
+
'sphinx.ext.todo',
|
| 90 |
+
'sphinx_copybutton',
|
| 91 |
+
# Our version of 'autoenum', designed to work with autosummary.
|
| 92 |
+
# This adds 'sphinx.ext.autosummary', and 'sphinx.ext.autodoc':
|
| 93 |
+
'pyomo_autosummary_autoenum',
|
| 94 |
+
'pyomo_tocref',
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
viewcode_follow_imported_members = True
|
| 98 |
+
# napoleon_include_private_with_doc = True
|
| 99 |
+
|
| 100 |
+
copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
|
| 101 |
+
copybutton_prompt_is_regexp = True
|
| 102 |
+
|
| 103 |
+
# Add any paths that contain templates here, relative to this directory.
|
| 104 |
+
templates_path = ['_templates']
|
| 105 |
+
|
| 106 |
+
# The suffix(es) of source filenames.
|
| 107 |
+
# You can specify multiple suffix as a list of string:
|
| 108 |
+
#
|
| 109 |
+
# source_suffix = ['.rst', '.md']
|
| 110 |
+
source_suffix = '.rst'
|
| 111 |
+
|
| 112 |
+
# The master toctree document.
|
| 113 |
+
master_doc = 'index'
|
| 114 |
+
|
| 115 |
+
# General information about the project.
|
| 116 |
+
project = u'Pyomo'
|
| 117 |
+
copyright = u'2008-2025, Sandia National Laboratories'
|
| 118 |
+
author = u'Pyomo Development Team'
|
| 119 |
+
|
| 120 |
+
# The version info for the project you're documenting, acts as replacement for
|
| 121 |
+
# |version| and |release|, also used in various other places throughout the
|
| 122 |
+
# built documents.
|
| 123 |
+
#
|
| 124 |
+
# The short X.Y version.
|
| 125 |
+
import pyomo.version
|
| 126 |
+
|
| 127 |
+
version = pyomo.version.__version__
|
| 128 |
+
# The full version, including alpha/beta/rc tags.
|
| 129 |
+
release = pyomo.version.__version__
|
| 130 |
+
|
| 131 |
+
# The language for content autogenerated by Sphinx. Refer to documentation
|
| 132 |
+
# for a list of supported languages.
|
| 133 |
+
#
|
| 134 |
+
# This is also used if you do content translation via gettext catalogs.
|
| 135 |
+
# Usually you set "language" from the command line for these cases.
|
| 136 |
+
language = "en"
|
| 137 |
+
|
| 138 |
+
# List of patterns, relative to source directory, that match files and
|
| 139 |
+
# directories to ignore when looking for source files.
|
| 140 |
+
# These patterns also effect to html_static_path and html_extra_path
|
| 141 |
+
# Notes:
|
| 142 |
+
# - _build : this is the Sphinx build (output) dir
|
| 143 |
+
#
|
| 144 |
+
# - api/*.tests.* : this matches autosummary RST files generated for
|
| 145 |
+
# test modules. Note that the _templates/recursive-modules.rst
|
| 146 |
+
# should prevent these file from being generated, so this is not
|
| 147 |
+
# strictly necessary, but including it makes Sphinx throw warnings if
|
| 148 |
+
# the filter in the template ever "breaks"
|
| 149 |
+
#
|
| 150 |
+
# - **/tests/** : this matches source files in any tests directory
|
| 151 |
+
# [JDS: I *believe* this is necessary, but am not 100% certain]
|
| 152 |
+
#
|
| 153 |
+
# - 'Thumbs.db', '.DS_Store' : these have been included from the
|
| 154 |
+
# beginning. Unclear if they are still necessary
|
| 155 |
+
exclude_patterns = ['_build', 'api/*.tests.*', '**/tests/**', 'Thumbs.db', '.DS_Store']
|
| 156 |
+
|
| 157 |
+
# The name of the Pygments (syntax highlighting) style to use.
|
| 158 |
+
pygments_style = 'sphinx'
|
| 159 |
+
|
| 160 |
+
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
| 161 |
+
todo_include_todos = True
|
| 162 |
+
|
| 163 |
+
# If true, doctest flags (comments looking like # doctest: FLAG, ...) at
|
| 164 |
+
# the ends of lines and <BLANKLINE> markers are removed for all code
|
| 165 |
+
# blocks showing interactive Python sessions (i.e. doctests)
|
| 166 |
+
trim_doctest_flags = True
|
| 167 |
+
|
| 168 |
+
# If true, figures, tables and code-blocks are automatically numbered if
|
| 169 |
+
# they have a caption.
|
| 170 |
+
numfig = True
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
# We want to be able to document the CONFIG class attribute in a special
|
| 174 |
+
# section. Nominally, we would use the napoleon_custom_sections hook.
|
| 175 |
+
# Unfortunately, there isn't a generic "kwargs_style", and aliasing
|
| 176 |
+
# 'Keyword Arguments' would render the section header in the
|
| 177 |
+
# documentation as 'Keyword Arguments'.
|
| 178 |
+
#
|
| 179 |
+
# Our solution is to declare a new PyObject field type (:config:) and
|
| 180 |
+
# define a new parser that generates :config: fields. We register the
|
| 181 |
+
# new parser with Napoleon by monkey-patching _load_custom_sections().
|
| 182 |
+
def _monkey_patch_napoleon():
|
| 183 |
+
from sphinx.ext.napoleon.docstring import GoogleDocstring
|
| 184 |
+
from sphinx.domains.python._object import PyObject, PyTypedField
|
| 185 |
+
from sphinx.locale import _
|
| 186 |
+
from sphinx import addnodes
|
| 187 |
+
from functools import partial
|
| 188 |
+
|
| 189 |
+
class PyConfigDomainField(PyTypedField):
|
| 190 |
+
def make_xref(
|
| 191 |
+
self,
|
| 192 |
+
rolename: str,
|
| 193 |
+
domain: str,
|
| 194 |
+
target: str,
|
| 195 |
+
innernode=addnodes.literal_emphasis,
|
| 196 |
+
contnode=None,
|
| 197 |
+
env=None,
|
| 198 |
+
inliner=None,
|
| 199 |
+
location=None,
|
| 200 |
+
):
|
| 201 |
+
ans = super().make_xref(
|
| 202 |
+
rolename=rolename,
|
| 203 |
+
domain=domain,
|
| 204 |
+
target=target,
|
| 205 |
+
innernode=innernode,
|
| 206 |
+
contnode=contnode,
|
| 207 |
+
env=env,
|
| 208 |
+
inliner=inliner,
|
| 209 |
+
location=location,
|
| 210 |
+
)
|
| 211 |
+
# Part of the call stack will override the reftype to
|
| 212 |
+
# "class". We want to support a broader set of domain
|
| 213 |
+
# types, so we will set it to "anything" (i.e., object)
|
| 214 |
+
ans['reftype'] = 'obj'
|
| 215 |
+
return ans
|
| 216 |
+
|
| 217 |
+
PyObject.doc_field_types.append(
|
| 218 |
+
PyConfigDomainField(
|
| 219 |
+
'config',
|
| 220 |
+
label=_('CONFIG'),
|
| 221 |
+
names=('config',),
|
| 222 |
+
typerolename='obj',
|
| 223 |
+
typenames=('configtype',),
|
| 224 |
+
can_collapse=True,
|
| 225 |
+
)
|
| 226 |
+
)
|
| 227 |
+
PyObject.doc_field_types.append(
|
| 228 |
+
PyConfigDomainField(
|
| 229 |
+
'option',
|
| 230 |
+
label=_('Options'),
|
| 231 |
+
names=('option',),
|
| 232 |
+
typerolename='obj',
|
| 233 |
+
typenames=('optiontype',),
|
| 234 |
+
can_collapse=True,
|
| 235 |
+
)
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
def _parse_config_section(self, field: str, section: str) -> list[str]:
|
| 239 |
+
fields = self._consume_fields()
|
| 240 |
+
if self._config.napoleon_use_keyword:
|
| 241 |
+
return self._format_docutils_params(
|
| 242 |
+
fields, field_role=field, type_role=field + 'type'
|
| 243 |
+
)
|
| 244 |
+
else:
|
| 245 |
+
return self._format_fields(_(section), fields)
|
| 246 |
+
|
| 247 |
+
original_loader = GoogleDocstring._load_custom_sections
|
| 248 |
+
|
| 249 |
+
def _load_custom_sections(self):
|
| 250 |
+
self._sections['config'] = partial(self._parse_config_section, 'config')
|
| 251 |
+
self._sections['options'] = partial(self._parse_config_section, 'option')
|
| 252 |
+
return original_loader(self)
|
| 253 |
+
|
| 254 |
+
GoogleDocstring._parse_config_section = _parse_config_section
|
| 255 |
+
GoogleDocstring._load_custom_sections = _load_custom_sections
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
_monkey_patch_napoleon()
|
| 259 |
+
|
| 260 |
+
# -- Options for HTML output ----------------------------------------------
|
| 261 |
+
|
| 262 |
+
# The theme to use for HTML and HTML Help pages. See the documentation for
|
| 263 |
+
# a list of builtin themes.
|
| 264 |
+
#
|
| 265 |
+
# html_theme = 'alabaster'
|
| 266 |
+
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
| 267 |
+
|
| 268 |
+
html_theme = 'sphinx_rtd_theme'
|
| 269 |
+
|
| 270 |
+
if not on_rtd: # only import and set the theme if we're building docs locally
|
| 271 |
+
import sphinx_rtd_theme
|
| 272 |
+
|
| 273 |
+
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
| 274 |
+
|
| 275 |
+
# Theme options are theme-specific and customize the look and feel of a theme
|
| 276 |
+
# further. For a list of options available for each theme, see the
|
| 277 |
+
# documentation.
|
| 278 |
+
#
|
| 279 |
+
html_theme_options = {'navigation_depth': 6, 'titles_only': True}
|
| 280 |
+
|
| 281 |
+
# Add any paths that contain custom static files (such as style sheets) here,
|
| 282 |
+
# relative to this directory. They are copied after the builtin static files,
|
| 283 |
+
# so a file named "default.css" will overwrite the builtin "default.css".
|
| 284 |
+
html_static_path = ['_static']
|
| 285 |
+
html_css_files = ['theme_overrides.css']
|
| 286 |
+
|
| 287 |
+
html_favicon = "../logos/pyomo/favicon.ico"
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
# -- Options for HTMLHelp output ------------------------------------------
|
| 291 |
+
|
| 292 |
+
# Output file base name for HTML help builder.
|
| 293 |
+
htmlhelp_basename = 'pyomo'
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
# -- Options for LaTeX output ---------------------------------------------
|
| 297 |
+
|
| 298 |
+
latex_elements = {
|
| 299 |
+
# The paper size ('letterpaper' or 'a4paper').
|
| 300 |
+
#
|
| 301 |
+
# 'papersize': 'letterpaper',
|
| 302 |
+
# The font size ('10pt', '11pt' or '12pt').
|
| 303 |
+
#
|
| 304 |
+
# 'pointsize': '10pt',
|
| 305 |
+
# Additional stuff for the LaTeX preamble.
|
| 306 |
+
#
|
| 307 |
+
'preamble': r'''
|
| 308 |
+
\usepackage{enumitem}
|
| 309 |
+
\setlistdepth{99}
|
| 310 |
+
\DeclareUnicodeCharacter{2227}{$\wedge$}
|
| 311 |
+
\DeclareUnicodeCharacter{2228}{$\vee$}
|
| 312 |
+
\DeclareUnicodeCharacter{22BB}{$\veebar$}
|
| 313 |
+
''',
|
| 314 |
+
# Latex figure (float) alignment
|
| 315 |
+
#
|
| 316 |
+
# 'figure_align': 'htbp',
|
| 317 |
+
# necessary for unicode charactacters in pdf output
|
| 318 |
+
'inputenc': '',
|
| 319 |
+
'utf8extra': '',
|
| 320 |
+
# remove blank pages (e.g., between chapters)
|
| 321 |
+
'classoptions': ',openany,oneside',
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
# Grouping the document tree into LaTeX files. List of tuples
|
| 325 |
+
# (source start file, target name, title,
|
| 326 |
+
# author, documentclass [howto, manual, or own class]).
|
| 327 |
+
latex_documents = [(master_doc, 'pyomo.tex', 'Pyomo Documentation', author, 'manual')]
|
| 328 |
+
if not on_rtd:
|
| 329 |
+
latex_documents.append(
|
| 330 |
+
('code', 'pyomo_reference.tex', 'Pyomo Code Reference', author, 'manual')
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
# The name of an image file (relative to this directory) to place at the top of
|
| 334 |
+
# the title page.
|
| 335 |
+
latex_logo = '../logos/pyomo/PyomoNewBlue.jpg'
|
| 336 |
+
|
| 337 |
+
# Disable the domain indices (i.e., the module index) for LaTeX targets:
|
| 338 |
+
# because we are splitting the documentation, the module index in the
|
| 339 |
+
# main document would be completely broken, and having one in the
|
| 340 |
+
# reference document seems redundant (JDS: and I haven't figured out how
|
| 341 |
+
# to have it in only one of the documents)
|
| 342 |
+
latex_domain_indices = False
|
| 343 |
+
|
| 344 |
+
# -- Options for manual page output ---------------------------------------
|
| 345 |
+
|
| 346 |
+
# One entry per manual page. List of tuples
|
| 347 |
+
# (source start file, name, description, authors, manual section).
|
| 348 |
+
man_pages = []
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
# -- Options for Texinfo output -------------------------------------------
|
| 352 |
+
|
| 353 |
+
# Grouping the document tree into Texinfo files. List of tuples
|
| 354 |
+
# (source start file, target name, title, author,
|
| 355 |
+
# dir menu entry, description, category)
|
| 356 |
+
texinfo_documents = []
|
| 357 |
+
|
| 358 |
+
# autodoc_member_order = 'bysource'
|
| 359 |
+
autodoc_member_order = 'groupwise'
|
| 360 |
+
# Starting in Sphinx 9.1, the new implementation of autodoc isn't
|
| 361 |
+
# compatible with our autosummary extension (See
|
| 362 |
+
# https://github.com/sphinx-doc/sphinx/issues/14089)
|
| 363 |
+
autodoc_use_legacy_class_based = True
|
| 364 |
+
|
| 365 |
+
autosummary_generate = True
|
| 366 |
+
autosummary_ignore_module_all = True
|
| 367 |
+
|
| 368 |
+
# -- Check which conditional dependencies are available ------------------
|
| 369 |
+
# Used for skipping certain doctests
|
| 370 |
+
from sphinx.ext.doctest import doctest
|
| 371 |
+
|
| 372 |
+
doctest_default_flags = (
|
| 373 |
+
doctest.ELLIPSIS
|
| 374 |
+
+ doctest.NORMALIZE_WHITESPACE
|
| 375 |
+
+ doctest.IGNORE_EXCEPTION_DETAIL
|
| 376 |
+
+ doctest.DONT_ACCEPT_TRUE_FOR_1
|
| 377 |
+
)
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
class IgnoreResultOutputChecker(doctest.OutputChecker):
|
| 381 |
+
IGNORE_RESULT = doctest.register_optionflag('IGNORE_RESULT')
|
| 382 |
+
|
| 383 |
+
def check_output(self, want, got, optionflags):
|
| 384 |
+
if optionflags & self.IGNORE_RESULT:
|
| 385 |
+
return True
|
| 386 |
+
return super().check_output(want, got, optionflags)
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
doctest.OutputChecker = IgnoreResultOutputChecker
|
| 390 |
+
|
| 391 |
+
doctest_global_setup = '''
|
| 392 |
+
import os, platform, sys
|
| 393 |
+
on_github_actions = bool(os.environ.get('GITHUB_ACTIONS', ''))
|
| 394 |
+
system_info = (
|
| 395 |
+
sys.platform,
|
| 396 |
+
platform.machine(),
|
| 397 |
+
platform.python_implementation()
|
| 398 |
+
)
|
| 399 |
+
|
| 400 |
+
# Mark that we are testing code (in this case, testing the documentation)
|
| 401 |
+
from pyomo.common.flags import in_testing_environment
|
| 402 |
+
in_testing_environment(True)
|
| 403 |
+
|
| 404 |
+
# We need multiprocessing because some doctests must be skipped if the
|
| 405 |
+
# start method is not "fork"
|
| 406 |
+
import multiprocessing
|
| 407 |
+
|
| 408 |
+
# (register plugins, make environ available to tests)
|
| 409 |
+
import pyomo.environ as pyo
|
| 410 |
+
|
| 411 |
+
from pyomo.common.dependencies import (
|
| 412 |
+
attempt_import, numpy_available, scipy_available, pandas_available,
|
| 413 |
+
yaml_available, networkx_available, matplotlib_available,
|
| 414 |
+
pympler_available, dill_available, pint_available,
|
| 415 |
+
numpy as np,
|
| 416 |
+
)
|
| 417 |
+
from pyomo.contrib.parmest.parmest import parmest_available
|
| 418 |
+
|
| 419 |
+
# Ensure that the matplotlib import has been resolved (and the backend changed)
|
| 420 |
+
bool(matplotlib_available)
|
| 421 |
+
|
| 422 |
+
# Not using SolverFactory to check solver availability because
|
| 423 |
+
# as of June 2020 there is no way to suppress warnings when
|
| 424 |
+
# solvers are not available
|
| 425 |
+
import pyomo.opt as _opt
|
| 426 |
+
ipopt_available = bool(_opt.check_available_solvers('ipopt'))
|
| 427 |
+
sipopt_available = bool(_opt.check_available_solvers('ipopt_sens'))
|
| 428 |
+
k_aug_available = bool(_opt.check_available_solvers('k_aug'))
|
| 429 |
+
dot_sens_available = bool(_opt.check_available_solvers('dot_sens'))
|
| 430 |
+
baron_available = bool(_opt.check_available_solvers('baron'))
|
| 431 |
+
glpk_available = bool(_opt.check_available_solvers('glpk'))
|
| 432 |
+
gurobipy_available = bool(_opt.check_available_solvers('gurobi_direct'))
|
| 433 |
+
|
| 434 |
+
baron = _opt.SolverFactory('baron')
|
| 435 |
+
|
| 436 |
+
if numpy_available:
|
| 437 |
+
# Recent changes on GHA seem to have dropped the default precision
|
| 438 |
+
# from 8 to 4; restore the default.
|
| 439 |
+
np.set_printoptions(precision=8)
|
| 440 |
+
|
| 441 |
+
if numpy_available and scipy_available:
|
| 442 |
+
import pyomo.contrib.pynumero.asl as _asl
|
| 443 |
+
asl_available = _asl.AmplInterface.available()
|
| 444 |
+
import pyomo.contrib.pynumero.linalg.ma27 as _ma27
|
| 445 |
+
ma27_available = _ma27.MA27Interface.available()
|
| 446 |
+
from pyomo.contrib.pynumero.linalg.mumps_interface import mumps_available
|
| 447 |
+
else:
|
| 448 |
+
asl_available = False
|
| 449 |
+
ma27_available = False
|
| 450 |
+
mumps_available = False
|
| 451 |
+
|
| 452 |
+
# Prevent any Pyomo logs from propagating up to the doctest logger
|
| 453 |
+
import logging
|
| 454 |
+
logging.getLogger('pyomo').propagate = False
|
| 455 |
+
'''
|
pyomo/source/doc/OnlineDocs/contribution_guide.rst
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Contributing to Pyomo
|
| 2 |
+
=====================
|
| 3 |
+
|
| 4 |
+
We welcome all contributions including bug fixes, feature enhancements,
|
| 5 |
+
and documentation improvements. Pyomo manages source code contributions
|
| 6 |
+
via GitHub pull requests (PRs).
|
| 7 |
+
|
| 8 |
+
Contribution Requirements
|
| 9 |
+
-------------------------
|
| 10 |
+
|
| 11 |
+
A PR should be 1 set of related changes. PRs for large-scale
|
| 12 |
+
non-functional changes (i.e. PEP8, comments) should be
|
| 13 |
+
separated from functional changes. This simplifies the review process
|
| 14 |
+
and ensures that functional changes aren't obscured by large amounts of
|
| 15 |
+
non-functional changes.
|
| 16 |
+
|
| 17 |
+
We do not squash and merge PRs so all commits in your branch will appear
|
| 18 |
+
in the main history. In addition to well-documented PR descriptions,
|
| 19 |
+
we encourage modular/targeted commits with descriptive commit messages.
|
| 20 |
+
|
| 21 |
+
Coding Standards
|
| 22 |
+
++++++++++++++++
|
| 23 |
+
|
| 24 |
+
* Required: `black <https://black.readthedocs.io/en/stable/>`_
|
| 25 |
+
* No use of ``__author__``
|
| 26 |
+
* Inside ``pyomo.contrib``: Contact information for the contribution
|
| 27 |
+
maintainer (such as a Github ID) should be included in the Sphinx
|
| 28 |
+
documentation
|
| 29 |
+
|
| 30 |
+
The first step of Pyomo's GitHub Actions workflow is to run
|
| 31 |
+
`black <https://black.readthedocs.io/en/stable/>`_ and a
|
| 32 |
+
`spell-checker <https://github.com/crate-ci/typos>`_ to ensure style
|
| 33 |
+
guide compliance and minimize typos. Before opening a pull request, please
|
| 34 |
+
run:
|
| 35 |
+
|
| 36 |
+
::
|
| 37 |
+
|
| 38 |
+
# Auto-apply correct formatting
|
| 39 |
+
pip install black
|
| 40 |
+
black <path>
|
| 41 |
+
# Find typos in files
|
| 42 |
+
conda install typos
|
| 43 |
+
typos --config .github/workflows/typos.toml <path>
|
| 44 |
+
|
| 45 |
+
If the spell-checker returns a failure for a word that is spelled
|
| 46 |
+
correctly, please add the word to the ``.github/workflows/typos.toml``
|
| 47 |
+
file. Note also that ``black`` reads from ``pyproject.toml`` to
|
| 48 |
+
determine correct configuration, so if you are running ``black``
|
| 49 |
+
indirectly (for example, using an IDE integration), please ensure you
|
| 50 |
+
are not overriding the project-level configuration set in that file.
|
| 51 |
+
|
| 52 |
+
Online Pyomo documentation is generated using `Sphinx <https://www.sphinx-doc.org/en/master/>`_
|
| 53 |
+
with the ``napoleon`` extension enabled. For API documentation we use of one of these
|
| 54 |
+
`supported styles for docstrings <https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html>`_,
|
| 55 |
+
but we prefer the NumPy standard. Whichever you choose, we require compliant docstrings for:
|
| 56 |
+
|
| 57 |
+
* Modules
|
| 58 |
+
* Public and Private Classes
|
| 59 |
+
* Public and Private Functions
|
| 60 |
+
|
| 61 |
+
We also encourage you to include examples, especially for new features
|
| 62 |
+
and contributions to ``pyomo.contrib``.
|
| 63 |
+
|
| 64 |
+
Testing
|
| 65 |
+
+++++++
|
| 66 |
+
|
| 67 |
+
Pyomo uses `unittest <https://docs.python.org/3/library/unittest.html>`_,
|
| 68 |
+
`pytest <https://docs.pytest.org/>`_,
|
| 69 |
+
`GitHub Actions <https://docs.github.com/en/free-pro-team@latest/actions>`_,
|
| 70 |
+
and Jenkins
|
| 71 |
+
for testing and continuous integration. Submitted code should include
|
| 72 |
+
tests to establish the validity of its results and/or effects. Unit
|
| 73 |
+
tests are preferred but we also accept integration tests. We require
|
| 74 |
+
at least 70% coverage of the lines modified in the PR and prefer coverage
|
| 75 |
+
closer to 90%. We also require that all tests pass before a PR will be
|
| 76 |
+
merged.
|
| 77 |
+
|
| 78 |
+
.. note::
|
| 79 |
+
If you are having issues getting tests to pass on your Pull Request,
|
| 80 |
+
please tag any of the core developers to ask for help.
|
| 81 |
+
|
| 82 |
+
The Pyomo main branch provides a Github Actions workflow (configured
|
| 83 |
+
in the ``.github/`` directory) that will test any changes pushed to
|
| 84 |
+
a branch with a subset of the complete test harness that includes
|
| 85 |
+
multiple virtual machines (``ubuntu``, ``mac-os``, ``windows``)
|
| 86 |
+
and multiple Python versions. For existing forks, fetch and merge
|
| 87 |
+
your fork (and branches) with Pyomo's main. For new forks, you will
|
| 88 |
+
need to enable GitHub Actions in the 'Actions' tab on your fork.
|
| 89 |
+
This will enable the tests to run automatically with each push to your fork.
|
| 90 |
+
|
| 91 |
+
At any point in the development cycle, a "work in progress" pull request
|
| 92 |
+
may be opened by including '[WIP]' at the beginning of the PR
|
| 93 |
+
title. Any pull requests marked '[WIP]' or draft will not be
|
| 94 |
+
reviewed or merged by the core development team. However, any
|
| 95 |
+
'[WIP]' pull request left open for an extended period of time without
|
| 96 |
+
active development may be marked 'stale' and closed.
|
| 97 |
+
|
| 98 |
+
.. note::
|
| 99 |
+
Draft and WIP Pull Requests will **NOT** trigger tests. This is an effort to
|
| 100 |
+
reduce our CI backlog. Please make use of the provided
|
| 101 |
+
branch test suite for evaluating / testing draft functionality.
|
| 102 |
+
|
| 103 |
+
Python Version Support
|
| 104 |
+
++++++++++++++++++++++
|
| 105 |
+
|
| 106 |
+
By policy, Pyomo supports and tests the currently supported Python versions,
|
| 107 |
+
as can be seen on `Status of Python Versions <https://devguide.python.org/versions/>`_.
|
| 108 |
+
It is expected that tests will pass for all of the supported and tested
|
| 109 |
+
versions of Python, unless otherwise stated.
|
| 110 |
+
|
| 111 |
+
At the time of the first Pyomo release after the end-of-life of a minor Python
|
| 112 |
+
version, we will remove testing and support for that Python version.
|
| 113 |
+
|
| 114 |
+
This will also result in a bump in the minor Pyomo version.
|
| 115 |
+
|
| 116 |
+
For example, assume Python 3.A is declared end-of-life while Pyomo is on
|
| 117 |
+
version 6.3.Y. After the release of Pyomo 6.3.(Y+1), Python 3.A will be removed,
|
| 118 |
+
and the next Pyomo release will be 6.4.0.
|
| 119 |
+
|
| 120 |
+
Working on Forks and Branches
|
| 121 |
+
-----------------------------
|
| 122 |
+
|
| 123 |
+
All Pyomo development should be done on forks of the Pyomo
|
| 124 |
+
repository. In order to fork the Pyomo repository, visit
|
| 125 |
+
https://github.com/Pyomo/pyomo, click the "Fork" button in the
|
| 126 |
+
upper right corner, and follow the instructions.
|
| 127 |
+
|
| 128 |
+
This section discusses two recommended workflows for contributing
|
| 129 |
+
pull-requests to Pyomo. The first workflow, labeled
|
| 130 |
+
:ref:`Working with my fork and the GitHub Online UI <forksgithubui>`,
|
| 131 |
+
does not require the use of 'remotes', and
|
| 132 |
+
suggests updating your fork using the GitHub online UI. The second
|
| 133 |
+
workflow, labeled
|
| 134 |
+
:ref:`Working with remotes and the git command-line <forksremotes>`, outlines
|
| 135 |
+
a process that defines separate remotes for your fork and the main
|
| 136 |
+
Pyomo repository.
|
| 137 |
+
|
| 138 |
+
More information on git can be found at
|
| 139 |
+
https://git-scm.com/book/en/v2. Section 2.5 has information on working
|
| 140 |
+
with remotes.
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
.. _forksgithubui:
|
| 144 |
+
|
| 145 |
+
Working with my fork and the GitHub Online UI
|
| 146 |
+
+++++++++++++++++++++++++++++++++++++++++++++
|
| 147 |
+
|
| 148 |
+
After creating your fork (per the instructions above), you can
|
| 149 |
+
then clone your fork of the repository with
|
| 150 |
+
|
| 151 |
+
::
|
| 152 |
+
|
| 153 |
+
git clone https://github.com/<username>/pyomo.git
|
| 154 |
+
|
| 155 |
+
For new development, we strongly recommend working on feature
|
| 156 |
+
branches. When you have a new feature to implement, create
|
| 157 |
+
the branch with the following.
|
| 158 |
+
|
| 159 |
+
::
|
| 160 |
+
|
| 161 |
+
cd pyomo/ # to make sure you are in the folder managed by git
|
| 162 |
+
git branch <branch_name>
|
| 163 |
+
git checkout <branch_name>
|
| 164 |
+
|
| 165 |
+
Development can now be performed. When you are ready, commit
|
| 166 |
+
any changes you make to your local repository. This can be
|
| 167 |
+
done multiple times with informative commit messages for
|
| 168 |
+
different tasks in the feature development.
|
| 169 |
+
|
| 170 |
+
::
|
| 171 |
+
|
| 172 |
+
git add <filename>
|
| 173 |
+
git status # to check that you have added the correct files
|
| 174 |
+
git commit -m 'informative commit message to describe changes'
|
| 175 |
+
|
| 176 |
+
In order to push the changes in your local branch to a branch on your fork, use
|
| 177 |
+
|
| 178 |
+
::
|
| 179 |
+
|
| 180 |
+
git push origin <branch_name>
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
When you have completed all the changes and are ready for a pull request, make
|
| 184 |
+
sure all the changes have been pushed to the branch <branch_name> on your fork.
|
| 185 |
+
|
| 186 |
+
* visit https://github.com/<username>/pyomo.
|
| 187 |
+
* Just above the list of files and directories in the repository,
|
| 188 |
+
you should see a button that says "Branch: main". Click on
|
| 189 |
+
this button, and choose the correct branch.
|
| 190 |
+
* Click the "New pull request" button just to the right of the
|
| 191 |
+
"Branch: <branch_name>" button.
|
| 192 |
+
* Fill out the pull request template and click the green "Create
|
| 193 |
+
pull request" button.
|
| 194 |
+
|
| 195 |
+
At times during your development, you may want to merge changes from
|
| 196 |
+
the Pyomo main development branch into the feature branch on your
|
| 197 |
+
fork and in your local clone of the repository.
|
| 198 |
+
|
| 199 |
+
Using GitHub UI to merge Pyomo main into a branch on your fork
|
| 200 |
+
****************************************************************
|
| 201 |
+
|
| 202 |
+
To update your fork, you will actually be merging a pull-request from
|
| 203 |
+
the head Pyomo repository into your fork.
|
| 204 |
+
|
| 205 |
+
* Visit https://github.com/Pyomo/pyomo.
|
| 206 |
+
* Click on the "New pull request" button just above the list of
|
| 207 |
+
files and directories.
|
| 208 |
+
* You will see the title "Compare changes" with some small text
|
| 209 |
+
below it which says "Compare changes across branches, commits,
|
| 210 |
+
tags, and more below. If you need to, you can also compare
|
| 211 |
+
across forks." Click the last part of this: "compare across
|
| 212 |
+
forks".
|
| 213 |
+
* You should now see four buttons just below this: "base
|
| 214 |
+
repository: Pyomo/pyomo", "base: main", "head repository:
|
| 215 |
+
Pyomo/pyomo", and "compare: main". Click the leftmost button
|
| 216 |
+
and choose "<username>/Pyomo".
|
| 217 |
+
* Then click the button which is second to the left, and choose
|
| 218 |
+
the branch which you want to merge Pyomo main into. The four
|
| 219 |
+
buttons should now read: "base repository: <username>/pyomo",
|
| 220 |
+
"base: <branch_name>", "head repository: Pyomo/pyomo", and
|
| 221 |
+
"compare: main". This is setting you up to merge a pull-request
|
| 222 |
+
from Pyomo's main branch into your fork's <branch_name> branch.
|
| 223 |
+
* You should also now see a pull request template. If you fill out
|
| 224 |
+
the pull request template and click "Create pull request", this
|
| 225 |
+
will create a pull request which will update your fork and
|
| 226 |
+
branch with any changes that have been made to the main branch
|
| 227 |
+
of Pyomo.
|
| 228 |
+
* You can then merge the pull request by clicking the green "Merge
|
| 229 |
+
pull request" button from your fork on GitHub.
|
| 230 |
+
|
| 231 |
+
.. _forksremotes:
|
| 232 |
+
|
| 233 |
+
Working with remotes and the git command-line
|
| 234 |
+
+++++++++++++++++++++++++++++++++++++++++++++
|
| 235 |
+
|
| 236 |
+
After you have created your fork, you can clone the fork and setup
|
| 237 |
+
git 'remotes' that allow you to merge changes from (and to) different
|
| 238 |
+
remote repositories. Below, we have included a set of recommendations,
|
| 239 |
+
but, of course, there are other valid GitHub workflows that you can
|
| 240 |
+
adopt.
|
| 241 |
+
|
| 242 |
+
The following commands show how to clone your fork and setup
|
| 243 |
+
two remotes, one for your fork, and one for the head Pyomo repository.
|
| 244 |
+
|
| 245 |
+
::
|
| 246 |
+
|
| 247 |
+
git clone https://github.com/<username>/pyomo.git
|
| 248 |
+
git remote rename origin my-fork
|
| 249 |
+
git remote add head-pyomo https://github.com/pyomo/pyomo.git
|
| 250 |
+
|
| 251 |
+
Note, you can see a list of your remotes with
|
| 252 |
+
|
| 253 |
+
::
|
| 254 |
+
|
| 255 |
+
git remote -v
|
| 256 |
+
|
| 257 |
+
The commands for creating a local branch and performing local commits
|
| 258 |
+
are the same as those listed in the previous section above. Below are
|
| 259 |
+
some common tasks based on this multi-remote setup.
|
| 260 |
+
|
| 261 |
+
If you have changes that have been committed to a local feature branch
|
| 262 |
+
(<branch_name>), you can push these changes to the branch on your fork
|
| 263 |
+
with,
|
| 264 |
+
|
| 265 |
+
::
|
| 266 |
+
|
| 267 |
+
git push my-fork <branch_name>
|
| 268 |
+
|
| 269 |
+
In order to update a local branch with changes from a branch of the
|
| 270 |
+
Pyomo repository,
|
| 271 |
+
|
| 272 |
+
::
|
| 273 |
+
|
| 274 |
+
git checkout <branch_to_update>
|
| 275 |
+
git fetch head-pyomo
|
| 276 |
+
git merge head-pyomo/<branch_to_update_from> --ff-only
|
| 277 |
+
|
| 278 |
+
The "--ff-only" only allows a merge if the merge can be done by a
|
| 279 |
+
fast-forward. If you do not require a fast-forward, you can drop this
|
| 280 |
+
option. The most common concrete example of this would be
|
| 281 |
+
|
| 282 |
+
::
|
| 283 |
+
|
| 284 |
+
git checkout main
|
| 285 |
+
git fetch head-pyomo
|
| 286 |
+
git merge head-pyomo/main --ff-only
|
| 287 |
+
|
| 288 |
+
The above commands pull changes from the main branch of the head
|
| 289 |
+
Pyomo repository into the main branch of your local clone. To push
|
| 290 |
+
these changes to the main branch on your fork,
|
| 291 |
+
|
| 292 |
+
::
|
| 293 |
+
|
| 294 |
+
git push my-fork main
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
Setting up your development environment
|
| 298 |
+
+++++++++++++++++++++++++++++++++++++++
|
| 299 |
+
|
| 300 |
+
After cloning your fork, you will want to install Pyomo from source.
|
| 301 |
+
|
| 302 |
+
Step 1 (recommended): Create a new ``conda`` environment.
|
| 303 |
+
|
| 304 |
+
::
|
| 305 |
+
|
| 306 |
+
conda create --name pyomodev
|
| 307 |
+
|
| 308 |
+
You may change the environment name from ``pyomodev`` as you see fit.
|
| 309 |
+
Then activate the environment:
|
| 310 |
+
|
| 311 |
+
::
|
| 312 |
+
|
| 313 |
+
conda activate pyomodev
|
| 314 |
+
|
| 315 |
+
Step 2 (optional): Install PyUtilib
|
| 316 |
+
|
| 317 |
+
The hard dependency on PyUtilib was removed in Pyomo 6.0.0. There is still a
|
| 318 |
+
soft dependency for any code related to ``pyomo.dataportal.plugins.sheet``.
|
| 319 |
+
|
| 320 |
+
If your contribution requires PyUtilib, you will likely need the main branch of
|
| 321 |
+
PyUtilib to contribute. Clone a copy of the repository in a new directory:
|
| 322 |
+
|
| 323 |
+
::
|
| 324 |
+
|
| 325 |
+
git clone https://github.com/PyUtilib/pyutilib
|
| 326 |
+
|
| 327 |
+
Then in the directory containing the clone of PyUtilib run:
|
| 328 |
+
|
| 329 |
+
::
|
| 330 |
+
|
| 331 |
+
python setup.py develop
|
| 332 |
+
|
| 333 |
+
Step 3: Install Pyomo
|
| 334 |
+
|
| 335 |
+
Finally, move to the directory containing the clone of your Pyomo fork and run:
|
| 336 |
+
|
| 337 |
+
::
|
| 338 |
+
|
| 339 |
+
pip install -e .
|
| 340 |
+
|
| 341 |
+
These commands register the cloned code with the active python environment
|
| 342 |
+
(``pyomodev``). This way, your changes to the source code for ``pyomo`` are
|
| 343 |
+
automatically used by the active environment. You can create another conda
|
| 344 |
+
environment to switch to alternate versions of pyomo (e.g., stable).
|
| 345 |
+
|
| 346 |
+
Review Process
|
| 347 |
+
--------------
|
| 348 |
+
|
| 349 |
+
After a PR is opened it will be reviewed by at least two members of the
|
| 350 |
+
core development team. The core development team consists of anyone with
|
| 351 |
+
write-access to the Pyomo repository. Pull requests opened by a core
|
| 352 |
+
developer only require one review. The reviewers will decide if they
|
| 353 |
+
think a PR should be merged or if more changes are necessary.
|
| 354 |
+
|
| 355 |
+
Reviewers look for:
|
| 356 |
+
|
| 357 |
+
* Outside of ``pyomo.contrib``: Code rigor and standards, edge cases,
|
| 358 |
+
side effects, etc.
|
| 359 |
+
* Inside of ``pyomo.contrib``: No “glaringly obvious” problems with
|
| 360 |
+
the code
|
| 361 |
+
* Documentation and tests
|
| 362 |
+
|
| 363 |
+
The core development team tries to review pull requests in a timely
|
| 364 |
+
manner but we make no guarantees on review timeframes. In addition, PRs
|
| 365 |
+
might not be reviewed in the order they are opened in.
|
| 366 |
+
|
| 367 |
+
Where to put contributed code
|
| 368 |
+
-----------------------------
|
| 369 |
+
|
| 370 |
+
In order to contribute to Pyomo, you must first make a fork of the Pyomo
|
| 371 |
+
git repository. Next, you should create a branch on your fork dedicated
|
| 372 |
+
to the development of the new feature or bug fix you're interested
|
| 373 |
+
in. Once you have this branch checked out, you can start coding. Bug
|
| 374 |
+
fixes and minor enhancements to existing Pyomo functionality should be
|
| 375 |
+
made in the appropriate files in the Pyomo code base. New examples,
|
| 376 |
+
features, and packages built on Pyomo should be placed in
|
| 377 |
+
``pyomo.contrib``. Follow the link below to find out if
|
| 378 |
+
``pyomo.contrib`` is right for your code.
|
| 379 |
+
|
| 380 |
+
``pyomo.contrib``
|
| 381 |
+
-----------------
|
| 382 |
+
|
| 383 |
+
Pyomo uses the ``pyomo.contrib`` package to facilitate the inclusion
|
| 384 |
+
of third-party contributions that enhance Pyomo's core functionality.
|
| 385 |
+
The are two ways that ``pyomo.contrib`` can be used to integrate
|
| 386 |
+
third-party packages:
|
| 387 |
+
|
| 388 |
+
* ``pyomo.contrib`` can provide wrappers for separate Python packages, thereby
|
| 389 |
+
allowing these packages to be imported as subpackages of pyomo.
|
| 390 |
+
|
| 391 |
+
* ``pyomo.contrib`` can include contributed packages that are developed and
|
| 392 |
+
maintained outside of the Pyomo developer team.
|
| 393 |
+
|
| 394 |
+
Including contrib packages in the Pyomo source tree provides a
|
| 395 |
+
convenient mechanism for defining new functionality that can be
|
| 396 |
+
optionally deployed by users. We expect this mechanism to include
|
| 397 |
+
Pyomo extensions and experimental modeling capabilities. However,
|
| 398 |
+
contrib packages are treated as optional packages, which are not
|
| 399 |
+
maintained by the Pyomo developer team. Thus, it is the responsibility
|
| 400 |
+
of the code contributor to keep these packages up-to-date.
|
| 401 |
+
|
| 402 |
+
Contrib package contributions will be considered as pull-requests,
|
| 403 |
+
which will be reviewed by the Pyomo developer team. Specifically,
|
| 404 |
+
this review will consider the suitability of the proposed capability,
|
| 405 |
+
whether tests are available to check the execution of the code, and
|
| 406 |
+
whether documentation is available to describe the capability.
|
| 407 |
+
Contrib packages will be tested along with Pyomo. If test failures
|
| 408 |
+
arise, then these packages will be disabled and an issue will be
|
| 409 |
+
created to resolve these test failures.
|
| 410 |
+
|
| 411 |
+
Contrib Packages within Pyomo
|
| 412 |
+
+++++++++++++++++++++++++++++
|
| 413 |
+
|
| 414 |
+
Third-party contributions can be included directly within the
|
| 415 |
+
``pyomo.contrib`` package. The ``pyomo/contrib/example`` package
|
| 416 |
+
provides an example of how this can be done, including a directory
|
| 417 |
+
for plugins and package tests. For example, this package can be
|
| 418 |
+
imported as a subpackage of ``pyomo.contrib``::
|
| 419 |
+
|
| 420 |
+
import pyomo.environ as pyo
|
| 421 |
+
from pyomo.contrib.example import a
|
| 422 |
+
|
| 423 |
+
# Print the value of 'a' defined by this package
|
| 424 |
+
print(a)
|
| 425 |
+
|
| 426 |
+
Although ``pyomo.contrib.example`` is included in the Pyomo source
|
| 427 |
+
tree, it is treated as an optional package. Pyomo will attempt to
|
| 428 |
+
import this package, but if an import failure occurs, Pyomo will
|
| 429 |
+
silently ignore it. Otherwise, this pyomo package will be treated
|
| 430 |
+
like any other. Specifically:
|
| 431 |
+
|
| 432 |
+
* Plugin classes defined in this package are loaded when ``pyomo.environ`` is loaded.
|
| 433 |
+
|
| 434 |
+
* Tests in this package are run with other Pyomo tests.
|
| 435 |
+
|
pyomo/source/doc/OnlineDocs/docutils.conf
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[writers]
|
| 2 |
+
table_style=colwidths-auto
|
pyomo/source/doc/OnlineDocs/errors.rst
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Common Warnings/Errors
|
| 2 |
+
======================
|
| 3 |
+
|
| 4 |
+
..
|
| 5 |
+
NOTE to developers: as we use section links to direct users, it is
|
| 6 |
+
critical that the "IDs" are unique. When adding a new extended
|
| 7 |
+
warning / error description, DO NOT renumber existing entries. Also,
|
| 8 |
+
for backwards compatibility, DO NOT recycle old ID (no longer used)
|
| 9 |
+
numbers.
|
| 10 |
+
|
| 11 |
+
.. testsetup::
|
| 12 |
+
|
| 13 |
+
import pyomo.environ as pyo
|
| 14 |
+
# Ensure that all logged messages are sent to stdout
|
| 15 |
+
# (so they show up in the doctest output and can be tested)
|
| 16 |
+
import pyomo.common.log as _log
|
| 17 |
+
_log.pyomo_handler.__class__ = _log.StdoutHandler
|
| 18 |
+
|
| 19 |
+
.. py:currentmodule:: pyomo.environ
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
.. ===================================================================
|
| 23 |
+
.. Extended descriptions for Pyomo warnings
|
| 24 |
+
.. ===================================================================
|
| 25 |
+
|
| 26 |
+
Warnings
|
| 27 |
+
--------
|
| 28 |
+
|
| 29 |
+
.. _W1001:
|
| 30 |
+
|
| 31 |
+
W1001: Setting Var value not in domain
|
| 32 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 33 |
+
|
| 34 |
+
When setting :class:`Var` values (by either calling :meth:`Var.set_value()`
|
| 35 |
+
or setting the :attr:`value` attribute), Pyomo will validate the
|
| 36 |
+
incoming value by checking that the value is ``in`` the
|
| 37 |
+
:attr:`Var.domain`. Any values not in the domain will generate this
|
| 38 |
+
warning:
|
| 39 |
+
|
| 40 |
+
.. doctest::
|
| 41 |
+
|
| 42 |
+
>>> m = pyo.ConcreteModel()
|
| 43 |
+
>>> m.x = pyo.Var(domain=pyo.Integers)
|
| 44 |
+
>>> m.x = 0.5
|
| 45 |
+
WARNING (W1001): Setting Var 'x' to a value `0.5` (float) not in domain
|
| 46 |
+
Integers.
|
| 47 |
+
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1001
|
| 48 |
+
>>> print(m.x.value)
|
| 49 |
+
0.5
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
Users can bypass all domain validation by setting the value using:
|
| 53 |
+
|
| 54 |
+
.. doctest::
|
| 55 |
+
|
| 56 |
+
>>> m.x.set_value(0.75, skip_validation=True)
|
| 57 |
+
>>> print(m.x.value)
|
| 58 |
+
0.75
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
.. _W1002:
|
| 63 |
+
|
| 64 |
+
W1002: Setting Var value outside the bounds
|
| 65 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 66 |
+
|
| 67 |
+
When setting :py:class:`Var` values (by either calling :meth:`set_value()`
|
| 68 |
+
or setting the :attr:`value` attribute), Pyomo will validate the
|
| 69 |
+
incoming value by checking that the value is within the range specified by
|
| 70 |
+
:attr:`Var.bounds`. Any values outside the bounds will generate this
|
| 71 |
+
warning:
|
| 72 |
+
|
| 73 |
+
.. doctest::
|
| 74 |
+
|
| 75 |
+
>>> m = pyo.ConcreteModel()
|
| 76 |
+
>>> m.x = pyo.Var(domain=pyo.Integers, bounds=(1, 5))
|
| 77 |
+
>>> m.x = 0
|
| 78 |
+
WARNING (W1002): Setting Var 'x' to a numeric value `0` outside the bounds
|
| 79 |
+
(1, 5).
|
| 80 |
+
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
|
| 81 |
+
>>> print(m.x.value)
|
| 82 |
+
0
|
| 83 |
+
|
| 84 |
+
Users can bypass all domain validation by setting the value using:
|
| 85 |
+
|
| 86 |
+
.. doctest::
|
| 87 |
+
|
| 88 |
+
>>> m.x.set_value(10, skip_validation=True)
|
| 89 |
+
>>> print(m.x.value)
|
| 90 |
+
10
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
.. _W1003:
|
| 95 |
+
|
| 96 |
+
W1003: Unexpected RecursionError walking an expression tree
|
| 97 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 98 |
+
|
| 99 |
+
Pyomo leverages a recursive walker (the
|
| 100 |
+
:py:class:`~pyomo.core.expr.visitor.StreamBasedExpressionVisitor`) to
|
| 101 |
+
traverse (walk) expression trees. For most expressions, this recursive
|
| 102 |
+
walker is the most efficient. However, Python has a relatively shallow
|
| 103 |
+
recursion limit (generally, 1000 frames). The recursive walker is
|
| 104 |
+
designed to monitor the stack depth and cleanly switch to a nonrecursive
|
| 105 |
+
walker before hitting the stack limit. However, there are two (rare)
|
| 106 |
+
cases where the Python stack limit can still generate a
|
| 107 |
+
:py:exc:`RecursionError` exception:
|
| 108 |
+
|
| 109 |
+
#. Starting the walker with fewer than
|
| 110 |
+
:py:data:`pyomo.core.expr.visitor.RECURSION_LIMIT` available frames.
|
| 111 |
+
#. Callbacks that require more than 2 *
|
| 112 |
+
:py:data:`pyomo.core.expr.visitor.RECURSION_LIMIT` frames.
|
| 113 |
+
|
| 114 |
+
The (default) recursive walker will catch the exception and restart the
|
| 115 |
+
walker from the beginning in non-recursive mode, issuing this warning.
|
| 116 |
+
The caution is that any partial work done by the walker before the
|
| 117 |
+
exception was raised will be lost, potentially leaving the walker in an
|
| 118 |
+
inconsistent state. Users can avoid this by
|
| 119 |
+
|
| 120 |
+
- avoiding recursive callbacks
|
| 121 |
+
- restructuring the system design to avoid triggering the walker with
|
| 122 |
+
few available stack frames
|
| 123 |
+
- directly calling the
|
| 124 |
+
:py:meth:`~pyomo.core.expr.visitor.StreamBasedExpressionVisitor.walk_expression_nonrecursive()`
|
| 125 |
+
walker method
|
| 126 |
+
|
| 127 |
+
.. doctest::
|
| 128 |
+
:skipif: (on_github_actions and system_info[0].startswith('win')) \
|
| 129 |
+
or system_info[2] == 'PyPy'
|
| 130 |
+
|
| 131 |
+
>>> import sys
|
| 132 |
+
>>> import pyomo.core.expr.visitor as visitor
|
| 133 |
+
>>> from pyomo.core.tests.unit.test_visitor import fill_stack
|
| 134 |
+
>>> expression_depth = visitor.StreamBasedExpressionVisitor(
|
| 135 |
+
... exitNode=lambda node, data: max(data) + 1 if data else 1)
|
| 136 |
+
>>> m = pyo.ConcreteModel()
|
| 137 |
+
>>> m.x = pyo.Var()
|
| 138 |
+
>>> @m.Expression(range(35))
|
| 139 |
+
... def e(m, i):
|
| 140 |
+
... return m.e[i-1] if i else m.x
|
| 141 |
+
>>> expression_depth.walk_expression(m.e[34])
|
| 142 |
+
36
|
| 143 |
+
>>> fill_stack(sys.getrecursionlimit() - visitor.get_stack_depth() - 30,
|
| 144 |
+
... expression_depth.walk_expression,
|
| 145 |
+
... m.e[34])
|
| 146 |
+
WARNING (W1003): Unexpected RecursionError walking an expression tree.
|
| 147 |
+
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1003
|
| 148 |
+
36
|
| 149 |
+
>>> fill_stack(sys.getrecursionlimit() - visitor.get_stack_depth() - 30,
|
| 150 |
+
... expression_depth.walk_expression_nonrecursive,
|
| 151 |
+
... m.e[34])
|
| 152 |
+
36
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
.. ===================================================================
|
| 156 |
+
.. Extended descriptions for Pyomo errors
|
| 157 |
+
.. ===================================================================
|
| 158 |
+
|
| 159 |
+
Errors
|
| 160 |
+
------
|
| 161 |
+
|
| 162 |
+
.. _E2001:
|
| 163 |
+
|
| 164 |
+
E2001: Variable domains must be an instance of a Pyomo Set
|
| 165 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 166 |
+
|
| 167 |
+
Variable domains are always Pyomo :class:`Set` or :class:`RangeSet`
|
| 168 |
+
objects. This includes global sets like ``Reals``, ``Integers``,
|
| 169 |
+
``Binary``, ``NonNegativeReals``, etc., as well as model-specific
|
| 170 |
+
:class:`Set` instances. The :attr:`Var.domain` setter will attempt to
|
| 171 |
+
convert assigned values to a Pyomo `Set`, with any failures leading to
|
| 172 |
+
this warning (and an exception from the converter):
|
| 173 |
+
|
| 174 |
+
.. doctest::
|
| 175 |
+
|
| 176 |
+
>>> m = pyo.ConcreteModel()
|
| 177 |
+
>>> m.x = pyo.Var()
|
| 178 |
+
>>> m.x.domain = 5
|
| 179 |
+
Traceback (most recent call last):
|
| 180 |
+
...
|
| 181 |
+
TypeError: Cannot create a Set from data that does not support __contains__...
|
| 182 |
+
ERROR (E2001): 5 is not a valid domain. Variable domains must be an instance
|
| 183 |
+
of a Pyomo Set or convertible to a Pyomo Set.
|
| 184 |
+
See also https://pyomo.readthedocs.io/en/stable/errors.html#e2001
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
.. ===================================================================
|
| 189 |
+
.. Extended descriptions for Pyomo exceptions
|
| 190 |
+
.. ===================================================================
|
| 191 |
+
|
| 192 |
+
.. Exceptions
|
| 193 |
+
.. ----------
|
| 194 |
+
|
| 195 |
+
.. .. _X101:
|
pyomo/source/doc/OnlineDocs/explanation/analysis/alternative_solutions.rst
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
###############################################
|
| 2 |
+
Generating Alternative (Near-)Optimal Solutions
|
| 3 |
+
###############################################
|
| 4 |
+
|
| 5 |
+
Optimization solvers are generally designed to return a feasible solution
|
| 6 |
+
to the user. However, there are many applications where a user needs
|
| 7 |
+
more context than this result. For example,
|
| 8 |
+
|
| 9 |
+
* alternative solutions can support an assessment of trade-offs between
|
| 10 |
+
competing objectives;
|
| 11 |
+
|
| 12 |
+
* if the optimization formulation may be inaccurate or untrustworthy,
|
| 13 |
+
then comparisons amongst alternative solutions provide additional
|
| 14 |
+
insights into the reliability of these model predictions; or
|
| 15 |
+
|
| 16 |
+
* the user may have unexpressed objectives or constraints, which only
|
| 17 |
+
are realized in later stages of model analysis.
|
| 18 |
+
|
| 19 |
+
The *alternative-solutions library* provides a variety of functions that
|
| 20 |
+
can be used to generate optimal or near-optimal solutions for a pyomo
|
| 21 |
+
model. Conceptually, these functions are like pyomo solvers. They can
|
| 22 |
+
be configured with solver names and options, and they return a list of
|
| 23 |
+
solutions for the pyomo model. However, these functions are independent
|
| 24 |
+
of pyomo's solver interface because they return a custom solution object.
|
| 25 |
+
|
| 26 |
+
The following functions are defined in the alternative-solutions library:
|
| 27 |
+
|
| 28 |
+
* ``enumerate_binary_solutions``
|
| 29 |
+
|
| 30 |
+
* Finds alternative optimal solutions for a binary problem using no-good cuts.
|
| 31 |
+
|
| 32 |
+
* ``enumerate_linear_solutions``
|
| 33 |
+
|
| 34 |
+
* Finds alternative optimal solutions for a (mixed-integer) linear program.
|
| 35 |
+
|
| 36 |
+
* ``enumerate_linear_solutions_soln_pool``
|
| 37 |
+
|
| 38 |
+
* Finds alternative optimal solutions for a (mixed-binary) linear
|
| 39 |
+
program using Gurobi's solution pool feature.
|
| 40 |
+
|
| 41 |
+
* ``gurobi_generate_solutions``
|
| 42 |
+
|
| 43 |
+
* Finds alternative optimal solutions for discrete variables using
|
| 44 |
+
Gurobi's built-in solution pool capability.
|
| 45 |
+
|
| 46 |
+
* ``obbt_analysis_bounds_and_solutions``
|
| 47 |
+
|
| 48 |
+
* Calculates the bounds on each variable by solving a series of min
|
| 49 |
+
and max optimization problems where each variable is used as the
|
| 50 |
+
objective function. This can be applied to any class of problem
|
| 51 |
+
supported by the selected solver.
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
Basic Usage Example
|
| 55 |
+
-------------------
|
| 56 |
+
|
| 57 |
+
Many of the functions in the alternative-solutions library have similar
|
| 58 |
+
options, so we simply illustrate the ``enumerate_binary_solutions``
|
| 59 |
+
function. We define a simple knapsack example whose alternative
|
| 60 |
+
solutions have integer objective values ranging from 0 to 90.
|
| 61 |
+
|
| 62 |
+
.. doctest::
|
| 63 |
+
|
| 64 |
+
>>> import pyomo.environ as pyo
|
| 65 |
+
|
| 66 |
+
>>> values = [10, 40, 30, 50]
|
| 67 |
+
>>> weights = [5, 4, 6, 3]
|
| 68 |
+
>>> capacity = 10
|
| 69 |
+
|
| 70 |
+
>>> m = pyo.ConcreteModel()
|
| 71 |
+
>>> m.x = pyo.Var(range(4), within=pyo.Binary)
|
| 72 |
+
>>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(4)), sense=pyo.maximize)
|
| 73 |
+
>>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(4)) <= capacity)
|
| 74 |
+
|
| 75 |
+
We can execute the ``enumerate_binary_solutions`` function to generate a
|
| 76 |
+
list of ``Solution`` objects that represent alternative optimal
|
| 77 |
+
solutions:
|
| 78 |
+
|
| 79 |
+
.. doctest::
|
| 80 |
+
:skipif: not glpk_available
|
| 81 |
+
|
| 82 |
+
>>> import pyomo.contrib.alternative_solutions as aos
|
| 83 |
+
>>> solns = aos.enumerate_binary_solutions(m, num_solutions=100, solver="glpk")
|
| 84 |
+
>>> assert len(solns) == 10
|
| 85 |
+
|
| 86 |
+
Each ``Solution`` object contains information about the objective and
|
| 87 |
+
variables, and it includes various methods to access this information.
|
| 88 |
+
For example:
|
| 89 |
+
|
| 90 |
+
.. doctest::
|
| 91 |
+
:skipif: not glpk_available
|
| 92 |
+
|
| 93 |
+
>>> print(solns[0])
|
| 94 |
+
{
|
| 95 |
+
"fixed_variables": [],
|
| 96 |
+
"objective": "o",
|
| 97 |
+
"objective_value": 90.0,
|
| 98 |
+
"solution": {
|
| 99 |
+
"x[0]": 0,
|
| 100 |
+
"x[1]": 1,
|
| 101 |
+
"x[2]": 0,
|
| 102 |
+
"x[3]": 1
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
Gap Usage Example
|
| 108 |
+
-----------------
|
| 109 |
+
|
| 110 |
+
When we only want some of the solutions based off a tolerance away from
|
| 111 |
+
optimal, this can be done using the ``abs_opt_gap`` parameter. This is
|
| 112 |
+
shown in the following simple knapsack examples where the weights and
|
| 113 |
+
values are the same.
|
| 114 |
+
|
| 115 |
+
.. doctest::
|
| 116 |
+
:skipif: not glpk_available
|
| 117 |
+
|
| 118 |
+
>>> import pyomo.environ as pyo
|
| 119 |
+
>>> import pyomo.contrib.alternative_solutions as aos
|
| 120 |
+
|
| 121 |
+
>>> values = [10,9,2,1,1]
|
| 122 |
+
>>> weights = [10,9,2,1,1]
|
| 123 |
+
|
| 124 |
+
>>> K = len(values)
|
| 125 |
+
>>> capacity = 12
|
| 126 |
+
|
| 127 |
+
>>> m = pyo.ConcreteModel()
|
| 128 |
+
>>> m.x = pyo.Var(range(K), within=pyo.Binary)
|
| 129 |
+
>>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(K)), sense=pyo.maximize)
|
| 130 |
+
>>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(K)) <= capacity)
|
| 131 |
+
|
| 132 |
+
>>> solns = aos.enumerate_binary_solutions(m, num_solutions=10, solver="glpk", abs_opt_gap = 0.0)
|
| 133 |
+
>>> assert(len(solns) == 4)
|
| 134 |
+
|
| 135 |
+
In this example, we only get the four ``Solution`` objects that have an
|
| 136 |
+
``objective_value`` of 12. Note that while we wanted only those four
|
| 137 |
+
solutions with no optimality gap, using a gap of half the smallest value
|
| 138 |
+
(in this case .5) will return the same solutions and avoids any machine
|
| 139 |
+
precision issues.
|
| 140 |
+
|
| 141 |
+
.. doctest::
|
| 142 |
+
:skipif: not glpk_available
|
| 143 |
+
|
| 144 |
+
>>> import pyomo.environ as pyo
|
| 145 |
+
>>> import pyomo.contrib.alternative_solutions as aos
|
| 146 |
+
|
| 147 |
+
>>> values = [10,9,2,1,1]
|
| 148 |
+
>>> weights = [10,9,2,1,1]
|
| 149 |
+
|
| 150 |
+
>>> K = len(values)
|
| 151 |
+
>>> capacity = 12
|
| 152 |
+
|
| 153 |
+
>>> m = pyo.ConcreteModel()
|
| 154 |
+
>>> m.x = pyo.Var(range(K), within=pyo.Binary)
|
| 155 |
+
>>> m.o = pyo.Objective(expr=sum(values[i] * m.x[i] for i in range(K)), sense=pyo.maximize)
|
| 156 |
+
>>> m.c = pyo.Constraint(expr=sum(weights[i] * m.x[i] for i in range(K)) <= capacity)
|
| 157 |
+
|
| 158 |
+
>>> solns = aos.enumerate_binary_solutions(m, num_solutions=10, solver="glpk", abs_opt_gap = 0.5)
|
| 159 |
+
>>> assert(len(solns) == 4)
|
| 160 |
+
>>> for soln in sorted(solns, key=lambda s: str(s.get_variable_name_values())):
|
| 161 |
+
... print(soln)
|
| 162 |
+
{
|
| 163 |
+
"fixed_variables": [],
|
| 164 |
+
"objective": "o",
|
| 165 |
+
"objective_value": 12.0,
|
| 166 |
+
"solution": {
|
| 167 |
+
"x[0]": 0,
|
| 168 |
+
"x[1]": 1,
|
| 169 |
+
"x[2]": 1,
|
| 170 |
+
"x[3]": 0,
|
| 171 |
+
"x[4]": 1
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
{
|
| 175 |
+
"fixed_variables": [],
|
| 176 |
+
"objective": "o",
|
| 177 |
+
"objective_value": 12.0,
|
| 178 |
+
"solution": {
|
| 179 |
+
"x[0]": 0,
|
| 180 |
+
"x[1]": 1,
|
| 181 |
+
"x[2]": 1,
|
| 182 |
+
"x[3]": 1,
|
| 183 |
+
"x[4]": 0
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
{
|
| 187 |
+
"fixed_variables": [],
|
| 188 |
+
"objective": "o",
|
| 189 |
+
"objective_value": 12.0,
|
| 190 |
+
"solution": {
|
| 191 |
+
"x[0]": 1,
|
| 192 |
+
"x[1]": 0,
|
| 193 |
+
"x[2]": 0,
|
| 194 |
+
"x[3]": 1,
|
| 195 |
+
"x[4]": 1
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
{
|
| 199 |
+
"fixed_variables": [],
|
| 200 |
+
"objective": "o",
|
| 201 |
+
"objective_value": 12.0,
|
| 202 |
+
"solution": {
|
| 203 |
+
"x[0]": 1,
|
| 204 |
+
"x[1]": 0,
|
| 205 |
+
"x[2]": 1,
|
| 206 |
+
"x[3]": 0,
|
| 207 |
+
"x[4]": 0
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
Interface Documentation
|
| 213 |
+
-----------------------
|
| 214 |
+
|
| 215 |
+
.. currentmodule:: pyomo.contrib.alternative_solutions
|
| 216 |
+
|
| 217 |
+
.. autofunction:: enumerate_binary_solutions
|
| 218 |
+
:noindex:
|
| 219 |
+
|
| 220 |
+
.. autofunction:: enumerate_linear_solutions
|
| 221 |
+
:noindex:
|
| 222 |
+
|
| 223 |
+
.. autofunction:: pyomo.contrib.alternative_solutions.lp_enum_solnpool.enumerate_linear_solutions_soln_pool
|
| 224 |
+
:noindex:
|
| 225 |
+
|
| 226 |
+
.. autofunction:: gurobi_generate_solutions
|
| 227 |
+
:noindex:
|
| 228 |
+
|
| 229 |
+
.. autofunction:: obbt_analysis_bounds_and_solutions
|
| 230 |
+
:noindex:
|
| 231 |
+
|
| 232 |
+
.. autoclass:: Solution
|
| 233 |
+
:noindex:
|
| 234 |
+
|
pyomo/source/doc/OnlineDocs/explanation/analysis/communities_8pp.png
ADDED
|
Git LFS Details
|
pyomo/source/doc/OnlineDocs/explanation/analysis/communities_decode_1.png
ADDED
|
Git LFS Details
|
pyomo/source/doc/OnlineDocs/explanation/analysis/community.rst
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Community Detection for Pyomo models
|
| 2 |
+
====================================
|
| 3 |
+
|
| 4 |
+
This package separates model components (variables, constraints, and objectives) into different communities
|
| 5 |
+
distinguished by the degree of connectivity between community members.
|
| 6 |
+
|
| 7 |
+
Description of Package and ``detect_communities`` function
|
| 8 |
+
----------------------------------------------------------
|
| 9 |
+
The community detection package allows users to obtain a community map of a Pyomo model - a Python dictionary-like
|
| 10 |
+
object that maps sequential integer values to communities within the Pyomo model. The package
|
| 11 |
+
takes in a model, organizes the model components into a graph of nodes and edges, then uses Louvain
|
| 12 |
+
community detection (`Blondel et al, 2008`_) to determine the communities that exist within the model.
|
| 13 |
+
|
| 14 |
+
.. _Blondel et al, 2008: https://dx.doi.org/10.1088/1742-5468/2008/10/P10008
|
| 15 |
+
|
| 16 |
+
In graph theory, a community is defined as a subset of nodes that have a greater degree of connectivity within
|
| 17 |
+
themselves than they do with the rest of the nodes in the graph. In the context of Pyomo models, a community
|
| 18 |
+
represents a subproblem within the overall optimization problem. Identifying these subproblems and then solving them
|
| 19 |
+
independently can save computational work compared with trying to solve the entire model at once. Thus, it
|
| 20 |
+
can be very useful to know the communities that exist in a model.
|
| 21 |
+
|
| 22 |
+
The manner in which the graph of nodes and edges is constructed from the model directly affects the community
|
| 23 |
+
detection. Thus, this package provides the user with a lot of control over the construction of the graph. The
|
| 24 |
+
function we use for this community detection is shown below:
|
| 25 |
+
|
| 26 |
+
.. autofunction:: pyomo.contrib.community_detection.detection.detect_communities
|
| 27 |
+
:noindex:
|
| 28 |
+
|
| 29 |
+
As stated above, the characteristics of the NetworkX graph of the Pyomo model are very important to the
|
| 30 |
+
community detection. The main graph features the user can specify are the type of community map,
|
| 31 |
+
whether the graph is weighted or unweighted, and whether the objective function(s) is included
|
| 32 |
+
in the graph generation. Below, the significance and reasoning behind including each of these options are
|
| 33 |
+
explained in greater depth.
|
| 34 |
+
|
| 35 |
+
Type of Community Map (`type_of_community_map`)
|
| 36 |
+
In this package's main function (``detect_communities``), the user can select ``'bipartite'``, ``'constraint'``,
|
| 37 |
+
or ``'variable'`` as an input for the 'type_of_community_map' argument, and these result in a community map
|
| 38 |
+
based on a bipartite graph, a constraint node graph, or a variable node graph (respectively).
|
| 39 |
+
|
| 40 |
+
If the user sets ``type_of_community_map='constraint'``, then each entry in the community map (which is a dictionary) contains
|
| 41 |
+
a list of all the constraints in the community as well as all the variables contained in those constraints.
|
| 42 |
+
For the model graph, a node is created for every active constraint in the model, an edge between two
|
| 43 |
+
constraint nodes is created only if those two constraint equations share a variable, and the
|
| 44 |
+
weight of each edge is equal to the number of variables the two constraint equations have in common.
|
| 45 |
+
|
| 46 |
+
If the user sets ``type_of_community_map='variable'``, then each entry in the community map (which is a dictionary) contains
|
| 47 |
+
a list of all the variables in the community as well as all the constraints that contain those variables.
|
| 48 |
+
For the model graph, a node is created for every variable in the model, an edge between two variable nodes is
|
| 49 |
+
created only if those two variables occur in the same constraint equation, and the weight of each edge is equal
|
| 50 |
+
to the number of constraint equations in which the two variables occur together.
|
| 51 |
+
|
| 52 |
+
If the user sets ``type_of_community_map='bipartite'``, then each entry in the community map (which is a dictionary) is
|
| 53 |
+
simply all of the nodes in the community but split into a list of constraints and a list of variables.
|
| 54 |
+
For the model graph, a node is created for every variable and every constraint in the model. An edge is created
|
| 55 |
+
between a constraint node and a variable node only if the constraint equation contains the variable. (Edges are
|
| 56 |
+
not drawn between nodes of the same type in a bipartite graph.) And as for the edge weights, the edges in the
|
| 57 |
+
bipartite graph are unweighted regardless of what the user specifies for the ``weighted_graph`` parameter. (This is
|
| 58 |
+
because for our purposes, the number of times a variable appears in a constraint is not particularly
|
| 59 |
+
useful.)
|
| 60 |
+
|
| 61 |
+
Weighted Graph/Unweighted Graph (`weighted_graph`)
|
| 62 |
+
The Louvain community detection algorithm takes edge weights into account, so depending on whether the graph is
|
| 63 |
+
weighted or unweighted, the communities that are found will vary. This can be valuable depending on how
|
| 64 |
+
the user intends to use the community detection information. For example, if a user plans on feeding that
|
| 65 |
+
information into an algorithm, the algorithm may be better suited to the communities detected in a weighted
|
| 66 |
+
graph (or vice versa).
|
| 67 |
+
|
| 68 |
+
With/Without Objective in the Graph (`with_objective`)
|
| 69 |
+
This argument determines whether the objective function(s) will be included when creating the graphical
|
| 70 |
+
representation of the model and thus whether the objective function(s) will be included in the community map.
|
| 71 |
+
Some models have an objective function that contains so many of the model variables that it obscures potential
|
| 72 |
+
communities within a model. Thus, it can be useful to call ``detect_communities(model, with_objective=False)``
|
| 73 |
+
on such a model to see whether isolating the other components of the model provides any new insights.
|
| 74 |
+
|
| 75 |
+
External Packages
|
| 76 |
+
-----------------
|
| 77 |
+
* NetworkX
|
| 78 |
+
* Python-Louvain
|
| 79 |
+
|
| 80 |
+
The community detection package relies on two external packages, the NetworkX package and the Louvain community
|
| 81 |
+
detection package. Both of these packages can be installed at the following URLs (respectively):
|
| 82 |
+
|
| 83 |
+
https://pypi.org/project/networkx/
|
| 84 |
+
|
| 85 |
+
https://pypi.org/project/python-louvain/
|
| 86 |
+
|
| 87 |
+
The pip install and conda install commands are included below as well::
|
| 88 |
+
|
| 89 |
+
pip install networkx
|
| 90 |
+
pip install python-louvain
|
| 91 |
+
|
| 92 |
+
conda install -c anaconda networkx
|
| 93 |
+
conda install -c conda-forge python-louvain
|
| 94 |
+
|
| 95 |
+
Usage Examples
|
| 96 |
+
--------------
|
| 97 |
+
|
| 98 |
+
Let's start off by taking a look at how we can use ``detect_communities`` to create a CommunityMap object.
|
| 99 |
+
We'll first use a model from `Allman et al, 2019`_ :
|
| 100 |
+
|
| 101 |
+
.. _Allman et al, 2019: https://doi.org/10.1007/s11081-019-09450-5
|
| 102 |
+
|
| 103 |
+
.. doctest::
|
| 104 |
+
:skipif: not networkx_available
|
| 105 |
+
|
| 106 |
+
Required Imports
|
| 107 |
+
>>> from pyomo.contrib.community_detection.detection import detect_communities, CommunityMap, generate_model_graph
|
| 108 |
+
>>> from pyomo.contrib.mindtpy.tests.eight_process_problem import EightProcessFlowsheet
|
| 109 |
+
>>> from pyomo.core import ConcreteModel, Var, Constraint
|
| 110 |
+
>>> import networkx as nx
|
| 111 |
+
|
| 112 |
+
Let's define a model for our use
|
| 113 |
+
>>> def decode_model_1():
|
| 114 |
+
... model = m = ConcreteModel()
|
| 115 |
+
... m.x1 = Var(initialize=-3)
|
| 116 |
+
... m.x2 = Var(initialize=-1)
|
| 117 |
+
... m.x3 = Var(initialize=-3)
|
| 118 |
+
... m.x4 = Var(initialize=-1)
|
| 119 |
+
... m.c1 = Constraint(expr=m.x1 + m.x2 <= 0)
|
| 120 |
+
... m.c2 = Constraint(expr=m.x1 - 3 * m.x2 <= 0)
|
| 121 |
+
... m.c3 = Constraint(expr=m.x2 + m.x3 + 4 * m.x4 ** 2 == 0)
|
| 122 |
+
... m.c4 = Constraint(expr=m.x3 + m.x4 <= 0)
|
| 123 |
+
... m.c5 = Constraint(expr=m.x3 ** 2 + m.x4 ** 2 - 10 == 0)
|
| 124 |
+
... return model
|
| 125 |
+
>>> model = m = decode_model_1()
|
| 126 |
+
>>> seed = 5 # To be used as a random seed value for the heuristic Louvain community detection
|
| 127 |
+
|
| 128 |
+
Let's create an instance of the CommunityMap class (which is what gets returned by the
|
| 129 |
+
function detect_communities):
|
| 130 |
+
>>> community_map_object = detect_communities(model, type_of_community_map='bipartite', random_seed=seed)
|
| 131 |
+
|
| 132 |
+
This community map object has many attributes that contain the relevant information about the
|
| 133 |
+
community map itself (such as the parameters used to create it, the networkX representation, and other useful
|
| 134 |
+
information).
|
| 135 |
+
|
| 136 |
+
An important point to note is that the community_map attribute of the CommunityMap class is the
|
| 137 |
+
actual dictionary that maps integers to the communities within the model. It is expected that the user will be
|
| 138 |
+
most interested in the actual dictionary itself, so dict-like usage is permitted.
|
| 139 |
+
|
| 140 |
+
If a user wishes to modify the actual dictionary (the community_map attribute of the CommunityMap object),
|
| 141 |
+
creating a deep copy is highly recommended (or else any destructive modifications could
|
| 142 |
+
have unintended consequences): ``new_community_map = copy.deepcopy(community_map_object.community_map)``
|
| 143 |
+
|
| 144 |
+
Let's take a closer look at the actual community map object generated by `detect_communities`:
|
| 145 |
+
|
| 146 |
+
.. doctest::
|
| 147 |
+
:skipif: not networkx_available
|
| 148 |
+
:hide:
|
| 149 |
+
|
| 150 |
+
>>> from pyomo.common.formatting import tostr
|
| 151 |
+
>>> if tostr(community_map_object[0]) == "([c3, c4, c5], [x3, x4])":
|
| 152 |
+
... _ = community_map_object.community_map
|
| 153 |
+
... _[0], _[1] = _[1], _[0]
|
| 154 |
+
|
| 155 |
+
.. doctest::
|
| 156 |
+
:skipif: not networkx_available
|
| 157 |
+
|
| 158 |
+
>>> print(community_map_object)
|
| 159 |
+
{0: (['c1', 'c2'], ['x1', 'x2']), 1: (['c3', 'c4', 'c5'], ['x3', 'x4'])}
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
Printing a community map object is made to be user-friendly (by showing the community map with components
|
| 164 |
+
replaced by their strings). However, if the default Pyomo representation of components is desired, then the
|
| 165 |
+
community_map attribute or the `repr()` function can be used:
|
| 166 |
+
|
| 167 |
+
.. doctest::
|
| 168 |
+
:skipif: not networkx_available
|
| 169 |
+
|
| 170 |
+
>>> print(community_map_object.community_map)
|
| 171 |
+
{0: ([<pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>], [<pyomo.core.base.var.ScalarVar object at ...>, <pyomo.core.base.var.ScalarVar object at ...>]), 1: ([<pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>], [<pyomo.core.base.var.ScalarVar object at ...>, <pyomo.core.base.var.ScalarVar object at ...>])}
|
| 172 |
+
>>> print(repr(community_map_object))
|
| 173 |
+
{0: ([<pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>], [<pyomo.core.base.var.ScalarVar object at ...>, <pyomo.core.base.var.ScalarVar object at ...>]), 1: ([<pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>, <pyomo.core.base.constraint.ScalarConstraint object at ...>], [<pyomo.core.base.var.ScalarVar object at ...>, <pyomo.core.base.var.ScalarVar object at ...>])}
|
| 174 |
+
|
| 175 |
+
`generate_structured_model` method of CommunityMap objects
|
| 176 |
+
It may be useful to create a new model based on the communities found in the model - we can use the
|
| 177 |
+
``generate_structured_model`` method of the CommunityMap class to do this. Calling this method on a CommunityMap object
|
| 178 |
+
returns a new model made up of blocks that correspond to each of the communities found in the original model. Let's
|
| 179 |
+
take a look at the example below:
|
| 180 |
+
|
| 181 |
+
.. doctest::
|
| 182 |
+
:skipif: not networkx_available
|
| 183 |
+
|
| 184 |
+
Use the CommunityMap object made from the first code example
|
| 185 |
+
>>> structured_model = community_map_object.generate_structured_model() # doctest: +SKIP
|
| 186 |
+
>>> structured_model.pprint() # doctest: +SKIP
|
| 187 |
+
2 Set Declarations
|
| 188 |
+
b_index : Size=1, Index=None, Ordered=Insertion
|
| 189 |
+
Key : Dimen : Domain : Size : Members
|
| 190 |
+
None : 1 : Any : 2 : {0, 1}
|
| 191 |
+
equality_constraint_list_index : Size=1, Index=None, Ordered=Insertion
|
| 192 |
+
Key : Dimen : Domain : Size : Members
|
| 193 |
+
None : 1 : Any : 1 : {1,}
|
| 194 |
+
<BLANKLINE>
|
| 195 |
+
1 Var Declarations
|
| 196 |
+
x2 : Size=1, Index=None
|
| 197 |
+
Key : Lower : Value : Upper : Fixed : Stale : Domain
|
| 198 |
+
None : None : None : None : False : True : Reals
|
| 199 |
+
<BLANKLINE>
|
| 200 |
+
1 Constraint Declarations
|
| 201 |
+
equality_constraint_list : Equality Constraints for the different forms of a given variable
|
| 202 |
+
Size=1, Index=equality_constraint_list_index, Active=True
|
| 203 |
+
Key : Lower : Body : Upper : Active
|
| 204 |
+
1 : 0.0 : b[0].x2 - x2 : 0.0 : True
|
| 205 |
+
<BLANKLINE>
|
| 206 |
+
1 Block Declarations
|
| 207 |
+
b : Size=2, Index=b_index, Active=True
|
| 208 |
+
b[0] : Active=True
|
| 209 |
+
2 Var Declarations
|
| 210 |
+
x1 : Size=1, Index=None
|
| 211 |
+
Key : Lower : Value : Upper : Fixed : Stale : Domain
|
| 212 |
+
None : None : None : None : False : True : Reals
|
| 213 |
+
x2 : Size=1, Index=None
|
| 214 |
+
Key : Lower : Value : Upper : Fixed : Stale : Domain
|
| 215 |
+
None : None : None : None : False : True : Reals
|
| 216 |
+
<BLANKLINE>
|
| 217 |
+
2 Constraint Declarations
|
| 218 |
+
c1 : Size=1, Index=None, Active=True
|
| 219 |
+
Key : Lower : Body : Upper : Active
|
| 220 |
+
None : -Inf : b[0].x1 + b[0].x2 : 0.0 : True
|
| 221 |
+
c2 : Size=1, Index=None, Active=True
|
| 222 |
+
Key : Lower : Body : Upper : Active
|
| 223 |
+
None : -Inf : b[0].x1 - 3*b[0].x2 : 0.0 : True
|
| 224 |
+
<BLANKLINE>
|
| 225 |
+
4 Declarations: x1 x2 c1 c2
|
| 226 |
+
b[1] : Active=True
|
| 227 |
+
2 Var Declarations
|
| 228 |
+
x3 : Size=1, Index=None
|
| 229 |
+
Key : Lower : Value : Upper : Fixed : Stale : Domain
|
| 230 |
+
None : None : None : None : False : True : Reals
|
| 231 |
+
x4 : Size=1, Index=None
|
| 232 |
+
Key : Lower : Value : Upper : Fixed : Stale : Domain
|
| 233 |
+
None : None : None : None : False : True : Reals
|
| 234 |
+
<BLANKLINE>
|
| 235 |
+
3 Constraint Declarations
|
| 236 |
+
c3 : Size=1, Index=None, Active=True
|
| 237 |
+
Key : Lower : Body : Upper : Active
|
| 238 |
+
None : 0.0 : x2 + b[1].x3 + 4*b[1].x4**2 : 0.0 : True
|
| 239 |
+
c4 : Size=1, Index=None, Active=True
|
| 240 |
+
Key : Lower : Body : Upper : Active
|
| 241 |
+
None : -Inf : b[1].x3 + b[1].x4 : 0.0 : True
|
| 242 |
+
c5 : Size=1, Index=None, Active=True
|
| 243 |
+
Key : Lower : Body : Upper : Active
|
| 244 |
+
None : 0.0 : b[1].x3**2 + b[1].x4**2 - 10 : 0.0 : True
|
| 245 |
+
<BLANKLINE>
|
| 246 |
+
5 Declarations: x3 x4 c3 c4 c5
|
| 247 |
+
<BLANKLINE>
|
| 248 |
+
5 Declarations: b_index b x2 equality_constraint_list_index equality_constraint_list
|
| 249 |
+
|
| 250 |
+
We see that there is an equality constraint list (`equality_constraint_list`) that has been created. This is due to
|
| 251 |
+
the fact that the ``detect_communities`` function can return a community map that has Pyomo components (variables,
|
| 252 |
+
constraints, or objectives) in more than one community, and thus, an equality_constraint_list is created to ensure that
|
| 253 |
+
the new model still corresponds to the original model. This is explained in more detail below.
|
| 254 |
+
|
| 255 |
+
Consider the case where community detection is done on a constraint node graph - this would result in communities
|
| 256 |
+
that are made up of the corresponding constraints as well as all the variables that occur in the given constraints.
|
| 257 |
+
Thus, it is possible for certain Pyomo components to be in multiple communities (and a similar argument exists
|
| 258 |
+
for community detection done on a variable node graph). As a result, our structured model (the model returned by
|
| 259 |
+
the ``generate_structured_model`` method) may need to have several "copies" of a certain component. For example,
|
| 260 |
+
a variable `original_model.x1` that exists in the original model may have corresponding forms
|
| 261 |
+
`structured_model.b[0].x1`, `structured_model.b[0].x1`, `structured_model.x1`. In order for these components to
|
| 262 |
+
meaningfully correspond to their counterparts in the original model, they must be bounded by equality constraints.
|
| 263 |
+
Thus, we use an `equality_constraint_list` to bind different forms of a component from the original model.
|
| 264 |
+
|
| 265 |
+
The last point to make about this method is that variables will be created outside of blocks if (1) an objective
|
| 266 |
+
is not inside a block (for example if the community detection is done `with_objective=False`) or if (2) an
|
| 267 |
+
objective/constraint contains a variable that is not in the same block as the given objective/constraint.
|
| 268 |
+
|
| 269 |
+
`visualize_model_graph` method of CommunityMap objects
|
| 270 |
+
If we want a visualization of the communities within the Pyomo model, we can use ``visualize_model_graph`` to do
|
| 271 |
+
so. Let's take a look at how this can be done in the following example:
|
| 272 |
+
|
| 273 |
+
.. doctest::
|
| 274 |
+
:skipif: not matplotlib_available or not networkx_available
|
| 275 |
+
|
| 276 |
+
Create a CommunityMap object (so we can demonstrate the visualize_model_graph method)
|
| 277 |
+
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='bipartite', random_seed=seed)
|
| 278 |
+
|
| 279 |
+
Generate a matplotlib figure (left_figure) - a constraint graph of the community map
|
| 280 |
+
>>> left_figure, _ = cmo.visualize_model_graph(type_of_graph='constraint')
|
| 281 |
+
>>> left_figure.show() # doctest: +SKIP
|
| 282 |
+
|
| 283 |
+
Now, we will generate the figure on the right (a bipartite graph of the community map)
|
| 284 |
+
>>> right_figure, _ = cmo.visualize_model_graph(type_of_graph='bipartite')
|
| 285 |
+
>>> right_figure.show() # doctest: +SKIP
|
| 286 |
+
|
| 287 |
+
An example of the two separate graphs created for these two function calls is shown below:
|
| 288 |
+
.. image:: communities_decode_1.png
|
| 289 |
+
:width: 100%
|
| 290 |
+
:alt: Graphical representation of the communities in the model 'decode_model_1' for two different types of graphs
|
| 291 |
+
|
| 292 |
+
These graph drawings very clearly demonstrate the communities within this model. The constraint graph (which is colored
|
| 293 |
+
using the bipartite community map) shows a very simple illustration - one node for each constraint, with only one edge
|
| 294 |
+
connecting the two communities (which represents the variable `m.x2` common to `m.c2` and `m.c3` in separate
|
| 295 |
+
communities)
|
| 296 |
+
The bipartite graph is slightly more complicated and we can see again how there is only one edge between the two
|
| 297 |
+
communities and more edges within each community. This is an ideal situation for breaking a
|
| 298 |
+
model into separate communities since there is little connectivity between the communities. Also, note that we can
|
| 299 |
+
choose different graph types (such as a variable node graph, constraint node graph, or bipartite graph) for a given
|
| 300 |
+
community map.
|
| 301 |
+
|
| 302 |
+
Let's try a more complicated model (taken from `Duran & Grossmann, 1986`_) - this example will demonstrate how the same
|
| 303 |
+
graph can be illustrated using different community maps (in the previous example we illustrated different graphs with a
|
| 304 |
+
single community map):
|
| 305 |
+
|
| 306 |
+
.. _Duran & Grossmann, 1986: https://dx.doi.org/10.1007/BF02592064
|
| 307 |
+
|
| 308 |
+
.. doctest::
|
| 309 |
+
:skipif: not matplotlib_available or not networkx_available
|
| 310 |
+
|
| 311 |
+
Define the model
|
| 312 |
+
>>> model = EightProcessFlowsheet()
|
| 313 |
+
|
| 314 |
+
Now, we follow steps similar to the example above (see above for explanations)
|
| 315 |
+
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='constraint', random_seed=seed)
|
| 316 |
+
>>> left_fig, pos = cmo.visualize_model_graph(type_of_graph='variable')
|
| 317 |
+
>>> left_fig.show() # doctest: +SKIP
|
| 318 |
+
|
| 319 |
+
As we did before, we will use the returned 'pos' to create a consistent graph layout
|
| 320 |
+
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='bipartite')
|
| 321 |
+
>>> middle_fig, _ = cmo.visualize_model_graph(type_of_graph='variable', pos=pos)
|
| 322 |
+
>>> middle_fig.show() # doctest: +SKIP
|
| 323 |
+
|
| 324 |
+
>>> community_map_object = cmo = detect_communities(model, type_of_community_map='variable')
|
| 325 |
+
>>> right_fig, _ = cmo.visualize_model_graph(type_of_graph='variable', pos=pos)
|
| 326 |
+
>>> right_fig.show() # doctest: +SKIP
|
| 327 |
+
|
| 328 |
+
We can see an example for the three separate graphs created by these three function calls below:
|
| 329 |
+
.. image:: communities_8pp.png
|
| 330 |
+
:width: 100%
|
| 331 |
+
:alt: Graphical representation of the communities in the model 'decode_model_1' for slightly different function calls
|
| 332 |
+
|
| 333 |
+
The three graphs above are all variable graphs - which means the nodes represent variables in the model, and the edges
|
| 334 |
+
represent constraint equations. The coloring differs because the three graphs rely on community maps that were
|
| 335 |
+
created based on a constraint node graph, a bipartite graph, and a variable node graph (from left to right). For
|
| 336 |
+
example, the community map that was generated from a constraint node graph (``type_of_community_map='constraint'``)
|
| 337 |
+
resulted in three communities (as seen by the purple, yellow, and blue nodes).
|
| 338 |
+
|
| 339 |
+
`generate_model_graph` function
|
| 340 |
+
Now, we will take a look at ``generate_model_graph`` - this function can be used to create a NetworkX
|
| 341 |
+
graph for a Pyomo model (and is used in `detect_communities`). Here, we will create a NetworkX graph from
|
| 342 |
+
the model in our first example and then create the edge and adjacency list for the graph.
|
| 343 |
+
|
| 344 |
+
``generate_model_graph`` returns three things:
|
| 345 |
+
|
| 346 |
+
* a NetworkX graph of the given model
|
| 347 |
+
* a dictionary that maps the numbers used to represent the model components to
|
| 348 |
+
the actual components (because Pyomo components cannot be directly added to a NetworkX graph)
|
| 349 |
+
* a dictionary that maps constraints to the variables in them.
|
| 350 |
+
|
| 351 |
+
For this example, we will only need the NetworkX graph of the model and the number-to-component mapping.
|
| 352 |
+
|
| 353 |
+
.. doctest::
|
| 354 |
+
:skipif: not networkx_available
|
| 355 |
+
|
| 356 |
+
Define the model
|
| 357 |
+
>>> model = decode_model_1()
|
| 358 |
+
|
| 359 |
+
See above for the description of the items returned by 'generate_model_graph'
|
| 360 |
+
>>> model_graph, number_component_map, constr_var_map = generate_model_graph(model, type_of_graph='constraint')
|
| 361 |
+
|
| 362 |
+
The next two lines create and implement a mapping to change the node values from numbers into
|
| 363 |
+
strings. The second line uses this mapping to create string_model_graph, which has
|
| 364 |
+
the relabeled nodes (strings instead of numbers).
|
| 365 |
+
|
| 366 |
+
>>> string_map = dict((number, str(comp)) for number, comp in number_component_map.items())
|
| 367 |
+
>>> string_model_graph = nx.relabel_nodes(model_graph, string_map)
|
| 368 |
+
|
| 369 |
+
Now, we print the edge list and the adjacency list:
|
| 370 |
+
Edge List:
|
| 371 |
+
>>> for line in nx.generate_edgelist(string_model_graph): print(line) # doctest: +SKIP
|
| 372 |
+
c1 c2 {'weight': 2}
|
| 373 |
+
c1 c3 {'weight': 1}
|
| 374 |
+
c2 c3 {'weight': 1}
|
| 375 |
+
c3 c5 {'weight': 2}
|
| 376 |
+
c3 c4 {'weight': 2}
|
| 377 |
+
c4 c5 {'weight': 2}
|
| 378 |
+
|
| 379 |
+
Adjacency List:
|
| 380 |
+
>>> print(list(nx.generate_adjlist(string_model_graph))) # doctest: +SKIP
|
| 381 |
+
['c1 c2 c3', 'c2 c3', 'c3 c5 c4', 'c4 c5', 'c5']
|
| 382 |
+
|
| 383 |
+
It's worth mentioning that in the code above, we do not have to create ``string_map`` to create an edge list
|
| 384 |
+
or adjacency list, but for the sake of having an easily understandable output, it is quite helpful. (Without
|
| 385 |
+
relabeling the nodes, the output below would not have the strings of the components but instead would have
|
| 386 |
+
integer values.) This code will hopefully make it easier for a user to do the same.
|
| 387 |
+
|
| 388 |
+
Functions in this Package
|
| 389 |
+
-------------------------
|
| 390 |
+
.. automodule:: pyomo.contrib.community_detection.detection
|
| 391 |
+
:noindex:
|
| 392 |
+
:members:
|
| 393 |
+
|
| 394 |
+
.. automodule:: pyomo.contrib.community_detection.community_graph
|
| 395 |
+
:noindex:
|
| 396 |
+
:members:
|
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/CCSI-license.txt
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Pyomo.DoE was originally developed as part of the Carbon Capture Simulation for Industry
|
| 2 |
+
# Impact (CCSI2) project under the following license:
|
| 3 |
+
#
|
| 4 |
+
# *** License Agreement ***
|
| 5 |
+
#
|
| 6 |
+
# Pyomo.DoE Copyright (c) 2022, by the software owners: TRIAD National Security, LLC., Lawrence
|
| 7 |
+
# Livermore National Security, LLC., Lawrence Berkeley National Laboratory,
|
| 8 |
+
# Pacific Northwest National Laboratory, Battelle Memorial Institute, University of Notre Dame,
|
| 9 |
+
# The University of Pittsburgh, The University of Texas at Austin, University of Toledo,
|
| 10 |
+
# West Virginia University, et al. All rights reserved.
|
| 11 |
+
#
|
| 12 |
+
# Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
| 13 |
+
# that the following conditions are met:
|
| 14 |
+
# (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
| 15 |
+
# following disclaimer.
|
| 16 |
+
# (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
| 17 |
+
# the following disclaimer in the documentation and/or other materials provided with the distribution.
|
| 18 |
+
# (3) Neither the name of the Carbon Capture Simulation for Industry Impact,
|
| 19 |
+
# TRIAD National Security, LLC., Lawrence Livermore National Security, LLC.,
|
| 20 |
+
# Lawrence Berkeley National Laboratory, Pacific Northwest National Laboratory,
|
| 21 |
+
# Battelle Memorial Institute, University of Notre Dame, The University of Pittsburgh,
|
| 22 |
+
# U.S. Dept. of Energy nor the names of its contributors may be used to endorse or promote products
|
| 23 |
+
# derived from this software without specific prior written permission.
|
| 24 |
+
#
|
| 25 |
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
| 26 |
+
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
| 27 |
+
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
| 28 |
+
# THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 29 |
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| 30 |
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 31 |
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
| 32 |
+
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
| 33 |
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 34 |
+
#
|
| 35 |
+
# You are under no obligation whatsoever to provide any bug fixes, patches, or upgrades to the features,
|
| 36 |
+
# functionality or performance of the source code ("Enhancements") to anyone; however, if you choose to
|
| 37 |
+
# make your Enhancements available either publicly, or directly to Lawrence Berkeley National Laboratory,
|
| 38 |
+
# without imposing a separate written license agreement for such Enhancements, then you hereby grant
|
| 39 |
+
# the following license: a non-exclusive, royalty-free perpetual license to install, use, modify, prepare
|
| 40 |
+
# derivative works, incorporate into other computer software, distribute, and sublicense such
|
| 41 |
+
# enhancements or derivative works thereof, in binary and source code form.
|
| 42 |
+
#
|
| 43 |
+
# Lead Developers: Jialu Wang and Alexander Dowling, University of Notre Dame
|
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/FIM_sensitivity.png
ADDED
|
Git LFS Details
|
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/doe.rst
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Pyomo.DoE
|
| 2 |
+
=========
|
| 3 |
+
|
| 4 |
+
**Pyomo.DoE** (Pyomo Design of Experiments) is a Python library for model-based design of experiments using science-based models.
|
| 5 |
+
|
| 6 |
+
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) <https://github.com/CCSI-Toolset/>`_.
|
| 7 |
+
project, funded through the U.S. Department Of Energy Office of Fossil Energy.
|
| 8 |
+
|
| 9 |
+
If you use Pyomo.DoE, please cite:
|
| 10 |
+
|
| 11 |
+
[Wang and Dowling, 2022] Wang, Jialu, and Alexander W. Dowling.
|
| 12 |
+
"Pyomo.DOE: An open‐source package for model‐based design of experiments in Python."
|
| 13 |
+
AIChE Journal 68.12 (2022): e17813. `https://doi.org/10.1002/aic.17813`
|
| 14 |
+
|
| 15 |
+
Methodology Overview
|
| 16 |
+
---------------------
|
| 17 |
+
|
| 18 |
+
Model-based Design of Experiments (MBDoE) is a technique to maximize the information gain of experiments by directly using science-based models with physically meaningful parameters. It is one key component in the model calibration and uncertainty quantification workflow shown below:
|
| 19 |
+
|
| 20 |
+
.. figure:: flowchart.png
|
| 21 |
+
:scale: 25 %
|
| 22 |
+
|
| 23 |
+
The exploratory analysis, parameter estimation, uncertainty analysis, and MBDoE are combined into an iterative framework to select, refine, and calibrate science-based mathematical models with quantified uncertainty. Currently, Pyomo.DoE focuses on increasing parameter precision.
|
| 24 |
+
|
| 25 |
+
Pyomo.DoE provides the exploratory analysis and MBDoE capabilities to the Pyomo ecosystem. The user provides one Pyomo model, a set of parameter nominal values,
|
| 26 |
+
the allowable design spaces for design variables, and the assumed observation error model.
|
| 27 |
+
During exploratory analysis, Pyomo.DoE checks if the model parameters can be inferred from the postulated measurements or preliminary data.
|
| 28 |
+
MBDoE then recommends optimized experimental conditions for collecting more data.
|
| 29 |
+
Parameter estimation packages such as :ref:`Parmest <parmest>` can perform parameter estimation using the available data to infer values for parameters,
|
| 30 |
+
and facilitate an uncertainty analysis to approximate the parameter covariance matrix.
|
| 31 |
+
If the parameter uncertainties are sufficiently small, the workflow terminates and returns the final model with quantified parametric uncertainty.
|
| 32 |
+
If not, MBDoE recommends optimized experimental conditions to generate new data.
|
| 33 |
+
|
| 34 |
+
Below is an overview of the type of optimization models Pyomo.DoE can accommodate:
|
| 35 |
+
|
| 36 |
+
* Pyomo.DoE is suitable for optimization models of **continuous** variables
|
| 37 |
+
* Pyomo.DoE can handle **equality constraints** defining state variables
|
| 38 |
+
* Pyomo.DoE supports (Partial) Differential-Algebraic Equations (PDAE) models via Pyomo.DAE
|
| 39 |
+
* Pyomo.DoE also supports models with only algebraic constraints
|
| 40 |
+
|
| 41 |
+
The general form of a DAE problem that can be passed into Pyomo.DoE is shown below:
|
| 42 |
+
|
| 43 |
+
.. math::
|
| 44 |
+
:nowrap:
|
| 45 |
+
|
| 46 |
+
\[\begin{array}{l}
|
| 47 |
+
\dot{\mathbf{x}}(t) = \mathbf{f}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}}, \boldsymbol{\theta}) \\
|
| 48 |
+
\mathbf{g}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta})=\mathbf{0} \\
|
| 49 |
+
\mathbf{y} =\mathbf{h}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta}) \\
|
| 50 |
+
\mathbf{f}^{\mathbf{0}}\left(\dot{\mathbf{x}}\left(t_{0}\right), \mathbf{x}\left(t_{0}\right), \mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta})\right)=\mathbf{0} \\
|
| 51 |
+
\mathbf{g}^{\mathbf{0}}\left( \mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)=\mathbf{0}\\
|
| 52 |
+
\mathbf{y}^{\mathbf{0}}\left(t_{0}\right)=\mathbf{h}\left(\mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)
|
| 53 |
+
\end{array}\]
|
| 54 |
+
|
| 55 |
+
where:
|
| 56 |
+
|
| 57 |
+
* :math:`\boldsymbol{\theta} \in \mathbb{R}^{N_p}` are unknown model parameters.
|
| 58 |
+
* :math:`\mathbf{x} \subseteq \mathcal{X}` are dynamic state variables which characterize trajectory of the system, :math:`\mathcal{X} \in \mathbb{R}^{N_x \times N_t}`.
|
| 59 |
+
* :math:`\mathbf{z} \subseteq \mathcal{Z}` are algebraic state variables, :math:`\mathcal{Z} \in \mathbb{R}^{N_z \times N_t}`.
|
| 60 |
+
* :math:`\mathbf{u} \subseteq \mathcal{U}` are time-varying decision variables, :math:`\mathcal{U} \in \mathbb{R}^{N_u \times N_t}`.
|
| 61 |
+
* :math:`\overline{\mathbf{w}} \in \mathbb{R}^{N_w}` are time-invariant decision variables.
|
| 62 |
+
* :math:`\mathbf{y} \subseteq \mathcal{Y}` are measurement response variables, :math:`\mathcal{Y} \in \mathbb{R}^{N_r \times N_t}`.
|
| 63 |
+
* :math:`\mathbf{f}(\cdot)` are differential equations.
|
| 64 |
+
* :math:`\mathbf{g}(\cdot)` are algebraic equations.
|
| 65 |
+
* :math:`\mathbf{h}(\cdot)` are measurement functions.
|
| 66 |
+
* :math:`\mathbf{t} \in \mathbb{R}^{N_t \times 1}` is a union of all time sets.
|
| 67 |
+
|
| 68 |
+
.. note::
|
| 69 |
+
* Parameters and design variables should be defined as Pyomo ``Var`` components on the model to use ``direct_kaug`` mode, and can be defined as Pyomo ``Param`` object if not using ``direct_kaug``.
|
| 70 |
+
|
| 71 |
+
Based on the above notation, the form of the MBDoE problem addressed in Pyomo.DoE is shown below:
|
| 72 |
+
|
| 73 |
+
.. math::
|
| 74 |
+
:nowrap:
|
| 75 |
+
|
| 76 |
+
\begin{equation}
|
| 77 |
+
\begin{aligned}
|
| 78 |
+
\underset{\boldsymbol{\varphi}}{\max} \quad & \Psi (\mathbf{M}(\mathbf{\hat{y}}, \boldsymbol{\varphi})) \\
|
| 79 |
+
\text{s.t.} \quad & \mathbf{M}(\boldsymbol{\hat{\theta}}, \boldsymbol{\varphi}) = \sum_r^{N_r} \sum_{r'}^{N_r} \tilde{\sigma}_{(r,r')}\mathbf{Q}_r^\mathbf{T} \mathbf{Q}_{r'} + \mathbf{V}^{-1}_{\boldsymbol{\theta}}(\boldsymbol{\hat{\theta}}) \\
|
| 80 |
+
& \dot{\mathbf{x}}(t) = \mathbf{f}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}}, \boldsymbol{\theta}) \\
|
| 81 |
+
& \mathbf{g}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{y}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta})=\mathbf{0} \\
|
| 82 |
+
& \mathbf{y} =\mathbf{h}(\mathbf{x}(t), \mathbf{z}(t), \mathbf{u}(t), \overline{\mathbf{w}},\boldsymbol{\theta}) \\
|
| 83 |
+
& \mathbf{f}^{\mathbf{0}}\left(\dot{\mathbf{x}}\left(t_{0}\right), \mathbf{x}\left(t_{0}\right), \mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta})\right)=\mathbf{0} \\
|
| 84 |
+
& \mathbf{g}^{\mathbf{0}}\left( \mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{y}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)=\mathbf{0}\\
|
| 85 |
+
&\mathbf{y}^{\mathbf{0}}\left(t_{0}\right)=\mathbf{h}\left(\mathbf{x}\left(t_{0}\right),\mathbf{z}(t_0), \mathbf{u}\left(t_{0}\right), \overline{\mathbf{w}}, \boldsymbol{\theta}\right)
|
| 86 |
+
\end{aligned}
|
| 87 |
+
\end{equation}
|
| 88 |
+
|
| 89 |
+
where:
|
| 90 |
+
|
| 91 |
+
* :math:`\boldsymbol{\varphi}` are design variables, which are manipulated to maximize the information content of experiments. It should consist of one or more of :math:`\mathbf{u}(t), \mathbf{y}^{\mathbf{0}}({t_0}),\overline{\mathbf{w}}`. With a proper model formulation, the timepoints for control or measurements :math:`\mathbf{t}` can also be degrees of freedom.
|
| 92 |
+
* :math:`\mathbf{M}` is the Fisher information matrix (FIM), estimated as the inverse of the covariance matrix of parameter estimates :math:`\boldsymbol{\hat{\theta}}`. A large FIM indicates more information contained in the experiment for parameter estimation.
|
| 93 |
+
* :math:`\mathbf{Q}` is the dynamic sensitivity matrix, containing the partial derivatives of :math:`\mathbf{y}` with respect to :math:`\boldsymbol{\theta}`.
|
| 94 |
+
* :math:`\Psi` is the design criteria to measure FIM.
|
| 95 |
+
* :math:`\mathbf{V}_{\boldsymbol{\theta}}(\boldsymbol{\hat{\theta}})^{-1}` is the FIM of previous experiments.
|
| 96 |
+
|
| 97 |
+
Pyomo.DoE provides four design criteria :math:`\Psi` to measure the size of FIM:
|
| 98 |
+
|
| 99 |
+
.. list-table:: Pyomo.DoE design criteria
|
| 100 |
+
:header-rows: 1
|
| 101 |
+
:class: tight-table
|
| 102 |
+
|
| 103 |
+
* - Design criterion
|
| 104 |
+
- Computation
|
| 105 |
+
- Geometrical meaning
|
| 106 |
+
* - A-optimality
|
| 107 |
+
- :math:`\text{trace}({\mathbf{M}})`
|
| 108 |
+
- Dimensions of the enclosing box of the confidence ellipse
|
| 109 |
+
* - D-optimality
|
| 110 |
+
- :math:`\text{det}({\mathbf{M}})`
|
| 111 |
+
- Volume of the confidence ellipse
|
| 112 |
+
* - E-optimality
|
| 113 |
+
- :math:`\text{min eig}({\mathbf{M}})`
|
| 114 |
+
- Size of the longest axis of the confidence ellipse
|
| 115 |
+
* - Modified E-optimality
|
| 116 |
+
- :math:`\text{cond}({\mathbf{M}})`
|
| 117 |
+
- Ratio of the longest axis to the shortest axis of the confidence ellipse
|
| 118 |
+
|
| 119 |
+
In order to solve problems of the above, Pyomo.DoE implements the 2-stage stochastic program. Please see Wang and Dowling (2022) for details.
|
| 120 |
+
|
| 121 |
+
Pyomo.DoE Required Inputs
|
| 122 |
+
--------------------------------
|
| 123 |
+
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 <parmest>`. The four ``Suffix`` components are:
|
| 124 |
+
|
| 125 |
+
* ``experiment_inputs`` - The experimental design decisions
|
| 126 |
+
* ``experiment_outputs`` - The values measured during the experiment
|
| 127 |
+
* ``measurement_error`` - The error associated with individual values measured during the experiment
|
| 128 |
+
* ``unknown_parameters`` - Those parameters in the model that are estimated using the measured values during the experiment
|
| 129 |
+
|
| 130 |
+
An example ``Experiment`` object that builds and labels the model is shown in the next few sections.
|
| 131 |
+
|
| 132 |
+
Pyomo.DoE Usage Example
|
| 133 |
+
-----------------------
|
| 134 |
+
|
| 135 |
+
We illustrate the use of Pyomo.DoE using a reaction kinetics example (Wang and Dowling, 2022).
|
| 136 |
+
The Arrhenius equations model the temperature dependence of the reaction rate coefficient :math:`k_1, k_2`. Assuming a first-order reaction mechanism gives the reaction rate model. Further, we assume only species A is fed to the reactor.
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
.. math::
|
| 140 |
+
:nowrap:
|
| 141 |
+
|
| 142 |
+
\begin{equation}
|
| 143 |
+
\begin{aligned}
|
| 144 |
+
k_1 & = A_1 e^{-\frac{E_1}{RT}} \\
|
| 145 |
+
k_2 & = A_2 e^{-\frac{E_2}{RT}} \\
|
| 146 |
+
\frac{d{C_A}}{dt} & = -k_1{C_A} \\
|
| 147 |
+
\frac{d{C_B}}{dt} & = k_1{C_A} - k_2{C_B} \\
|
| 148 |
+
C_{A0}& = C_A + C_B + C_C \\
|
| 149 |
+
C_B(t_0) & = 0 \\
|
| 150 |
+
C_C(t_0) & = 0 \\
|
| 151 |
+
\end{aligned}
|
| 152 |
+
\end{equation}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
:math:`C_A(t), C_B(t), C_C(t)` are the time-varying concentrations of the species A, B, C, respectively.
|
| 157 |
+
:math:`k_1, k_2` are the rates for the two chemical reactions using an Arrhenius equation with activation energies :math:`E_1, E_2` and pre-exponential factors :math:`A_1, A_2`.
|
| 158 |
+
The goal of MBDoE is to optimize the experiment design variables :math:`\boldsymbol{\varphi} = (C_{A0}, T(t))`, where :math:`C_{A0},T(t)` are the initial concentration of species A and the time-varying reactor temperature, to maximize the precision of unknown model parameters :math:`\boldsymbol{\theta} = (A_1, E_1, A_2, E_2)` by measuring :math:`\mathbf{y}(t)=(C_A(t), C_B(t), C_C(t))`.
|
| 159 |
+
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.
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
Step 0: Import Pyomo and the Pyomo.DoE module and create an ``Experiment`` class
|
| 163 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 164 |
+
|
| 165 |
+
.. doctest::
|
| 166 |
+
|
| 167 |
+
>>> # === Required import ===
|
| 168 |
+
>>> import pyomo.environ as pyo
|
| 169 |
+
>>> from pyomo.contrib.doe import DesignOfExperiments
|
| 170 |
+
>>> import numpy as np
|
| 171 |
+
|
| 172 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
|
| 173 |
+
:start-after: ========================
|
| 174 |
+
:end-before: End constructor definition
|
| 175 |
+
|
| 176 |
+
Step 1: Define the Pyomo process model
|
| 177 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 178 |
+
|
| 179 |
+
The process model for the reaction kinetics problem is shown below. We build the model without any data or discretization.
|
| 180 |
+
|
| 181 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
|
| 182 |
+
:start-after: Create flexible model without data
|
| 183 |
+
:end-before: End equation definition
|
| 184 |
+
|
| 185 |
+
Step 2: Finalize the Pyomo process model
|
| 186 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 187 |
+
|
| 188 |
+
Here we add data to the model and finalize the discretization. This step is required before the model can be labeled.
|
| 189 |
+
|
| 190 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
|
| 191 |
+
:start-after: End equation definition
|
| 192 |
+
:end-before: End model finalization
|
| 193 |
+
|
| 194 |
+
Step 3: Label the information needed for DoE analysis
|
| 195 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 196 |
+
|
| 197 |
+
We label the four important groups as defined before.
|
| 198 |
+
|
| 199 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
|
| 200 |
+
:start-after: End model finalization
|
| 201 |
+
:end-before: End model labeling
|
| 202 |
+
|
| 203 |
+
Step 4: Implement the ``get_labeled_model`` method
|
| 204 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 205 |
+
|
| 206 |
+
This method utilizes the previous 3 steps and is used by `Pyomo.DoE` to build the model to perform optimal experimental design.
|
| 207 |
+
|
| 208 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_experiment.py
|
| 209 |
+
:start-after: End constructor definition
|
| 210 |
+
:end-before: Create flexible model without data
|
| 211 |
+
|
| 212 |
+
Step 5: Exploratory analysis (Enumeration)
|
| 213 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 214 |
+
|
| 215 |
+
Exploratory analysis is suggested to enumerate the design space to check if the problem is identifiable,
|
| 216 |
+
i.e., ensure that D-, E-optimality metrics are not small numbers near zero, and Modified E-optimality is not a big number.
|
| 217 |
+
|
| 218 |
+
Pyomo.DoE can perform exploratory sensitivity analysis with the ``compute_FIM_full_factorial`` function.
|
| 219 |
+
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.
|
| 220 |
+
|
| 221 |
+
The following code executes the above problem description:
|
| 222 |
+
|
| 223 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_example.py
|
| 224 |
+
:start-after: Read in file
|
| 225 |
+
:end-before: End sensitivity analysis
|
| 226 |
+
|
| 227 |
+
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:
|
| 228 |
+
|
| 229 |
+
.. figure:: FIM_sensitivity.png
|
| 230 |
+
:scale: 50 %
|
| 231 |
+
|
| 232 |
+
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.
|
| 233 |
+
|
| 234 |
+
Step 6: Performing an optimal experimental design
|
| 235 |
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| 236 |
+
|
| 237 |
+
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.
|
| 238 |
+
|
| 239 |
+
.. literalinclude:: /../../pyomo/contrib/doe/examples/reactor_example.py
|
| 240 |
+
:start-after: Begin optimal DoE
|
| 241 |
+
:end-before: Print out a results summary
|
| 242 |
+
|
| 243 |
+
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
|
| 244 |
+
|
| 245 |
+
|
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/flowchart.png
ADDED
|
Git LFS Details
|
pyomo/source/doc/OnlineDocs/explanation/analysis/doe/grid-1.png
ADDED
|
Git LFS Details
|