pyaugmecon


Namepyaugmecon JSON
Version 1.0.8 PyPI version JSON
download
home_page
SummaryAn AUGMECON based multi-objective optimization solver for Pyomo.
upload_time2024-02-26 15:52:41
maintainer
docs_urlNone
author
requires_python>=3.8
licenseMIT License Copyright (c) 2021-2024 Electrical Energy Systems Group, Department of Electrical Engineering, Eindhoven University of Technology. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords python pyomo optimization multi-objective-optimization augmecon
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">
<img src="https://raw.githubusercontent.com/wouterbles/pyaugmecon/main/logo.png" alt="Logo" width="330">
</div>

## An AUGMECON based multi-objective optimization solver for Pyomo

[![Tests](https://github.com/wouterbles/pyaugmecon/actions/workflows/main.yml/badge.svg)](https://github.com/wouterbles/pyaugmecon/actions/workflows/main.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/wouterbles/pyaugmecon/blob/main/LICENSE)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![PyPI](https://img.shields.io/pypi/v/pyaugmecon)](https://pypi.org/project/pyaugmecon)
[![Downloads](https://pepy.tech/badge/pyaugmecon)](https://pepy.tech/project/pyaugmecon)
[![DOI](https://zenodo.org/badge/336300468.svg)](https://zenodo.org/badge/latestdoi/336300468)

This is a [Python](https://www.python.org/) and [Pyomo](http://www.pyomo.org/) based implementation of the augmented ε-constraint (AUGMECON) method and its variants which can be used to solve multi-objective optimization problems, i.e., to return an approximation of the exact Pareto front.

It currently supports:

- Inner loop early exit (AUGMECON)
- Bypass coefficient (AUGMECON2)
- Flag array (AUGMECON-R)
- Processs-based parallelization

[GAMS implementations](#useful-resources) of the method and its variants were provided by the authors of the papers. To the best of our knowledge, this is the first publicly available [Python](https://www.python.org/) implementation.

## Contents

- [Installation](#installation)
- [Usage](#usage)
- [Tests](#tests)
- [Useful resources](#useful-resources)
- [Notes](#notes)
- [Known limitations](#known-limitations)

## Installation

PyAUGMECON can be installed from [PyPI](https://pypi.org/) using `pip install pyaugmecon`. Detailed installation instructions for both [Anaconda](<#anaconda-installation-(advised)>) and [PyPI](#pypi-installation) installations are available below.

### Requirements

- [Python](https://www.python.org/)
- [Pyomo](http://www.pyomo.org/)
- [Numpy](https://numpy.org/)
- [Pandas](https://pandas.pydata.org/)
- [Cloudpickle](https://github.com/cloudpipe/cloudpickle)
- [Pymoo](https://pymoo.org/)
- [Gurobi](https://www.gurobi.com/) (other sovlers supported as well)

> The [Gurobi Python bindings](https://www.gurobi.com/documentation/9.1/quickstart_mac/cs_python.html) are significantly faster than using the executable. So even if you have already installed Gurobi, please still install the Python version for an optimal experience.

### Anaconda installation (advised)

This installation is advised as the PyPI installation of Gurobi does not include the licensing tools. Only Gurobi needs to be installed as other tools are by default included in Anaconda or will be automatically installed as dependencies of PyAUGMECON.

```bash
# Install Anaconda from https://www.anaconda.com

# Install Gurobi
conda config --add channels http://conda.anaconda.org/gurobi
conda install gurobi

# Install PyAUGMECON, and dependencies
pip install pyaugmecon
```

### PyPI installation

For a PyPI installation, only Gurobi needs to be installed, other requirements will automatically be installed as dependencies of PyAUGMECON. As mentioned above, the PyPI version of Gurobi does not include licensing tools, see [Gurobi documentation](https://support.gurobi.com/hc/en-us/articles/360044290292-How-do-I-install-Gurobi-for-Python-) on how to install these.

```bash
# Install Gurobi, PYAUGMECON, and dependencies
pip install gurobipy pyaugmecon
```

### Other solvers
The installation instructions above describe an installation with Gurobi, since this is the solver that has been used for testing. However, other solvers should work as well. The only requirement is that the solver is supported by Pyomo. An example of the GLPK solver can be found [in the test folder](https://github.com/wouterbles/pyaugmecon/blob/main/tests/ga/test_two_objectives.py).

## Usage

First, an optimization model generator function needs to be created to pass the model to PyAUGMECON. This function should return an unsolved instance of the optimization problem, see [Pyomo model](#pyomo-model). Essentially, the only difference in comparison with creating a single objective Pyomo optimization model is the fact that multiple objectives are defined using Pyomo's `ObjectiveList()`.

The rest of the process is automatically being taken care of by instantiating a `PyAugmecon()` object and solving it afterward with `PyAugmecon.solve()`.

### PyAugmecon parameters

Instantiating a `PyAugmecon(model, opts, solver_opts)` object requires the following parameters:

| Name          | Description                                                                                             | Required |
| ------------- | ------------------------------------------------------------------------------------------------------- | -------- |
| `model`       | Function that returns an unsolved instance of the optimization problem, see [Pyomo model](#pyomo-model) | Yes      |
| `opts`        | Dictionary of PyAUGMECON related options, see [PyAugmecon options](#pyaugmecon-options)                 | Yes      |
| `solver_opts` | Dictionary of solver (Gurobi) options, see [solver options](#solver-options)                            | No       |

### Example 3kp40

The following snippet shows how to solve the `3kp40` model from the `tests` folder:

```python
from pyaugmecon import PyAugmecon
from tests.optimization_models import three_kp_model

# Multiprocessing requires this If statement (on Windows)
if __name__ == "__main__":
    model_type = "3kp40"

    # AUGMECON related options
    opts = {
        "name": model_type,
        "grid_points": 540,
        "nadir_points": [1031, 1069],
    }

    pyaugmecon = PyAugmecon(three_kp_model(model_type), opts)  # instantiate  PyAugmecon
    pyaugmecon.solve()  # solve PyAugmecon multi-objective optimization problem
    sols = pyaugmecon.get_pareto_solutions()  # get all pareto solutions
    payoff = pyaugmecon.get_payoff_table()  # get the payoff table
    decision_vars = pyaugmecon.get_decision_variables(sols[0])  # get the decision variables
```

### PyAugmecon methods

| Name                     | Description                                                                                                                                             |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_pareto_solutions()`    | Get a list of Pareto-optimal solutions (`list[tuple]`) |
| `get_decision_variables(pareto_solution)` | Get a dictionary of decision variables for a given Pareto-optimal solution. Where the key represents the decision variable name and the value is a pd.Series with the values. |
| `get_payoff_table()`  | Get the payoff table from the model. |

### PyAugmecon attributes

After solving the model with `PyAugmecon.solve()`, the following object attributes are available:

| Name                     | Description                                                                                                                                             |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sols`                   | Full unprocessed solutions, only checked for uniqueness                                                                                                 |
| `unique_sols`            | Unique solutions, rounded to `round_decimals` and checked for uniqueness                                                                                |
| `unique_pareto_sols`     | Unique Pareto solutions, only dominant solutions, rounded to `round_deicmals` and checked for uniqueness                                                |
| `num_sols`               | Number of solutions                                                                                                                                     |
| `num_unique_sols`        | Number of unique solutions                                                                                                                              |
| `num_unique_pareto_sols` | Number of unique Pareto solutions                                                                                                                       |
| `model.models_solved`    | Number of models solved (excluding solves for payoff table)                                                                                             |
| `model.infeasibilites`   | Number of models solved that were infeasible                                                                                                            |
| `model.to_solve`         | Total number of models to solve (including payoff table)                                                                                                |
| `model.model`            | Pyomo model instance                                                                                                                                    |
| `model.payoff`           | Payoff table                                                                                                                                            |
| `model.e`                | Gridpoints of p-1 objective functions that are used as constraints                                                                                      |
| `hv_indicator`           | The hypervolume indicator of the unique Pareto solutions, [see Pymoo documentation](https://pymoo.org/misc/performance_indicator.html) for more details |
| `runtime`                | Total runtime in seconds                                                                                                                                |

### PyAugmecon solutions details

The solutions are stored in the `sols`, `unique_sols`, and `unique_pareto_sols` attributes. These differ in the following ways:

- `sols` contains all solutions, including duplicates and non-Pareto solutions
- `unique_sols` contains all unique solutions, including non-Pareto solutions
- `unique_pareto_sols` contains all unique Pareto solutions

The solutions are stored dictionary, where each dictionary contains the objective values (keys) and the decision variables (values). The objective values are stored as a tuple, where the first element is the objective value of the first objective function, the second element is the objective value of the second objective function, and so on. The decision variables are stored as a dictionary, where the keys are the names of the decision variables and the values are the values of the decision variables.

This is an example of the `unique_pareto_sols` attribute:

```python
{
    (3, 5): {'x': pd.Series([1, 2]), 'y': pd.Series([2, 3])},
    (4, 4): {'x': pd.Series([3, 4]), 'y': pd.Series([1, 2])},
    (5, 3): {'x': pd.Series([2, 4]), 'y': pd.Series([1, 3])},
}
```

### PyAugmecon options

The following PyAUGMECON related options can be passed as a dictionary to the solver:

| Option               | Description                                                                                                                                                                                                                                                                                                                        | Default                       |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| `name`               | Name of the model, used in logging output                                                                                                                                                                                                                                                                                          | `Undefined`                   |
| `grid_points`        | Number of grid points (if X grid points in GAMS, X+1 grid points are needed in order to exactly replicate results)                                                                                                                                                                                                                 |                               |
| `nadir_points`       | If the exact nadir points are known — these can be provided, otherwise they will be taken from the payoff table                                                                                                                                                                                                                    | `True`                        |
| `early_exit`         | Use inner loop early-exit (AUGMECON) — exit the inner loop when the model result becomes infeasible                                                                                                                                                                                                                                | `True`                        |
| `bypass_coefficient` | Use bypass coefficient (AUGMECON2) — utilize slack variables to skip redundant iterations                                                                                                                                                                                                                                          | `True`                        |
| `flag_array`         | Use flag array (AUGMECON-R) — store early exit and bypass coefficients for upcoming iterations                                                                                                                                                                                                                                     | `True`                        |
| `penalty_weight`     | The penalty by which other terms in the objective are multiplied, usually between `10e-3` and `10e-6`                                                                                                                                                                                                                              | `1e-3`                        |
| `nadir_ratio`        | For problems with three or more objective functions, the payoff table minima do not guarantee the exact nadir. This factor scales the payoff minima. By providing a value lower than one, lower bounds of the minima can be estimated                                                                                              | `1`                           |
| `logging_folder`     | Folder to store log files (relative to the root directory)                                                                                                                                                                                                                                                                         | `logs`                        |
| `cpu_count`          | Specify over how many processes the work should be divided. Use `1` to disable parallelization                                                                                                                                                                                                                                     | `multiprocessing.cpu_count()` |
| `redivide_work`      | Have processes take work from unfinished processes when their queue is empty                                                                                                                                                                                                                                                       | `True`                        |
| `shared_flag`        | Share the flag array between processes. If false, each process will have its own flag array                                                                                                                                                                                                                                        | `True`                        |
| `round_decimals`     | The number of decimals to which the solutions are rounded before checking for uniqueness                                                                                                                                                                                                                                           | `9`                           |
| `pickle_file`        | Filename of the pickled [Pyomo](http://www.pyomo.org/) model for [cloudpickle](https://github.com/cloudpipe/cloudpickle)                                                                                                                                                                                                           | `model.p`                     |
| `solver_name`        | Name of the solver provided to [Pyomo](http://www.pyomo.org/)                                                                                                                                                                                                                                                                      | `gurobi`                      |
| `solver_io`          | Name of the solver interface provided to [Pyomo](http://www.pyomo.org/). As the [Gurobi Python bindings](https://www.gurobi.com/documentation/9.1/quickstart_mac/cs_python.html) are significantly faster than using the executable, they are set by default. If you still prefer to use the executable, set this option to `None` | `python`                      |
| `output_excel`       | Create an excel with solver output in the `logging_folder` containing the payoff table, e-points, solutions, unique solutions, and unique Pareto solutions                                                                                                                                                                         | `True`                        |
| `process_logging`    | Outputs solution process information from sub-processes to the log file. This significantly reduces performances and does not work on Windows. Don't enable this unless necessary                                                                                                                                                  | `False`                       |
| `process_timeout`    | Gracefully stops all processes after `process_timeout` in seconds. As processes are stopped gracefully they will be allowed to finish their assigned work and not stop exactly after `process_timeout`                                                                                                                             | `None`                        |

### Solver options

To solve the single-objective optimization problems generated by the AUGMECON method they are passed to Gurobi, an external solver. All [Gurobi solver parameters](https://www.gurobi.com/documentation/9.1/refman/parameters.html) can be passed to Gurobi with this dictionary. Two parameters are already set by default, but can be overridden:

| Option      | Description                                                                                          | Default |
| ----------- | ---------------------------------------------------------------------------------------------------- | ------- |
| `MIPGap`    | See Gurobi documentation: [MIPGap](https://www.gurobi.com/documentation/9.1/refman/mipgap2.html)     | `0.0`   |
| `NonConvex` | See Gurobi documentation [NonConvex](https://www.gurobi.com/documentation/9.1/refman/nonconvex.html) | `2`     |

### Pyomo model

A multi-objective Pyomo model is similar to a single-objective model, except that the objectives should be defined using Pyomo's `ObjectiveList()` and attached to the model by an attribute named `obj_list`. Multiple example models can be found in the `tests` folder and a simple model can be found below:

```python
def two_objective_model():
    model = ConcreteModel()

    # Define variables
    model.x1 = Var(within=NonNegativeReals)
    model.x2 = Var(within=NonNegativeReals)

    # --------------------------------------
    #   Define the objective functions
    # --------------------------------------

    def objective1(model):
        return model.x1

    def objective2(model):
        return 3 * model.x1 + 4 * model.x2

    # --------------------------------------
    #   Define the regular constraints
    # --------------------------------------

    def constraint1(model):
        return model.x1 <= 20

    def constraint2(model):
        return model.x2 <= 40

    def constraint3(model):
        return 5 * model.x1 + 4 * model.x2 <= 200

    # --------------------------------------
    #   Add components to the model
    # --------------------------------------

    # Add the constraints to the model
    model.con1 = Constraint(rule=constraint1)
    model.con2 = Constraint(rule=constraint2)
    model.con3 = Constraint(rule=constraint3)

    # Add the objective functions to the model using ObjectiveList(). Note
    # that the first index is 1 instead of 0!
    model.obj_list = ObjectiveList()
    model.obj_list.add(expr=objective1(model), sense=maximize)
    model.obj_list.add(expr=objective2(model), sense=maximize)

    # By default deactivate all the objective functions
    for o in range(len(model.obj_list)):
        model.obj_list[o + 1].deactivate()

    return model
```

## Tests

To test the correctness of the proposed approach, the following optimization models have been tested both using the GAMS and the proposed implementations:

- Sample bi-objective problem of the original paper
- Sample three-objective problem of the original implementation/presentation
- Multi-objective multidimensional knapsack (MOMKP) problems: 2kp50, 2kp100, 2kp250, 3kp40, 3kp50, 4kp40 and 4kp50
- Multi-objective economic dispatch (minimize cost, emissions and unmet demand)

These models can be found in the **tests** folder and run with [PyTest](https://pytest.org) to test for the correctness of the payoff table and the Pareto solutions. Example: `pytest tests/test_3kp40.py`

> Despite the extensive testing, the PyAUGMECON implementation is provided without any warranty. Use it at your own risk!

## Useful resources

### Original AUGMECON

- G. Mavrotas, “Effective implementation of the ε-constraint methodin Multi-Objective Mathematical Programming problems,” _Applied Mathematics and Computation_, vol. 213, no. 2, pp. 455–465, 2009
- [GAMS implementation](https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_epscm.html)

### Improved AUGMECON2

- Mavrotas and K. Florios, “An improved version of the augmented ε-constraint method (AUGMECON2) for finding the exact pareto set in multi-objective integer programming problems,” _Applied Mathematics and Computation_, vol. 219, no. 18, pp. 9652–9669, 2013.
- [GAMS implementation](https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_epscmmip.html)

### Further improved AUGMECON-R

- A. Nikas, A. Fountoulakis, A. Forouli, and H. Doukas, _A robust augmented ε-constraint method (AUGMECON-R) for finding exact solutions of multi-objective linear programming problems._ Springer Berlin Heidelberg, 2020, no. 0123456789.
- [GAMS implementation](https://github.com/KatforEpu/Augmecon-R)

### Other resources

- [The following PhD thesis is also very useful](https://www.chemeng.ntua.gr/gm/gmsite_gre/index_files/PHD_mavrotas_text.pdf)
- [This presentation provides a quick overview](https://www.chemeng.ntua.gr/gm/gmsite_eng/index_files/mavrotas_MCDA64_2006.pdf)

## Notes

- The choice of the objective function(s) to add as constraints affects the mapping of the Pareto front. Empirically, having one of the objective functions with a large range in the constraint set tends to result in a denser representation of the Pareto front. Nevertheless, despite the choice of which objectives to add in the constraint set, the solutions belong to the same Pareto front (obviously).

- If X grid points in GAMS, X+1 grid points are needed in PyAUGMECON in order to exactly replicate results

- For some models, it is beneficial to runtime to reduce the number of solver (Gurobi) threads. More details: [Gurobi documentation](https://www.gurobi.com/documentation/9.1/refman/threads.html)

## Known limitations

- For relatively small models (most of the knapsack problems), disabling `redivide_work` and `shared_flag` should lead to slightly lower runtimes. This is due to the overhead of sharing the flag array between processes that don't have a shared memory space. Redividing the work results in additional models solved with duplicate solutions, leading to longer runtime. By sharing the flag array in a different way and dividing the work more smartly these limitations might be solved in the future.

- To parallelize the solution process, the grid is divided into blocks with a minimum length of the inner loop (number of grid points) over the processes. With fewer than three objectives, there is only one dimension to iterate over, and as such no parallelization possible. This is something that can be improved in the future.

## Changelog

See [Changelog](CHANGELOG.md)

## Citing

If you use PyAUGMECON for academic work, please cite the following [DOI (Zenodo)](https://zenodo.org/badge/latestdoi/336300468).

## Credit

This software was developed at the Electricity Markets & Power System Optimization Laboratory (EMPSOLab), [Electrical Energy Systems Group](https://www.tue.nl/en/research/research-groups/electrical-energy-systems/), [Department of Electrical Engineering](https://www.tue.nl/en/our-university/departments/electrical-engineering/), [Eindhoven University of Technology](https://www.tue.nl/en/).

Contributors:

- Wouter Bles (current version of the package)
- Nikolaos Paterakis (initial implementation)

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "pyaugmecon",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "python,pyomo,optimization,multi-objective-optimization,augmecon",
    "author": "",
    "author_email": "Wouter Bles <whbles@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/21/c9/1e79e3e1bafdcdd1e11a8791f4c6141edeed11ac7396821c53fc5c3e4ae5/pyaugmecon-1.0.8.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n<img src=\"https://raw.githubusercontent.com/wouterbles/pyaugmecon/main/logo.png\" alt=\"Logo\" width=\"330\">\n</div>\n\n## An AUGMECON based multi-objective optimization solver for Pyomo\n\n[![Tests](https://github.com/wouterbles/pyaugmecon/actions/workflows/main.yml/badge.svg)](https://github.com/wouterbles/pyaugmecon/actions/workflows/main.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-purple.svg)](https://github.com/wouterbles/pyaugmecon/blob/main/LICENSE)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![PyPI](https://img.shields.io/pypi/v/pyaugmecon)](https://pypi.org/project/pyaugmecon)\n[![Downloads](https://pepy.tech/badge/pyaugmecon)](https://pepy.tech/project/pyaugmecon)\n[![DOI](https://zenodo.org/badge/336300468.svg)](https://zenodo.org/badge/latestdoi/336300468)\n\nThis is a [Python](https://www.python.org/) and [Pyomo](http://www.pyomo.org/) based implementation of the augmented \u03b5-constraint (AUGMECON) method and its variants which can be used to solve multi-objective optimization problems, i.e., to return an approximation of the exact Pareto front.\n\nIt currently supports:\n\n- Inner loop early exit (AUGMECON)\n- Bypass coefficient (AUGMECON2)\n- Flag array (AUGMECON-R)\n- Processs-based parallelization\n\n[GAMS implementations](#useful-resources) of the method and its variants were provided by the authors of the papers. To the best of our knowledge, this is the first publicly available [Python](https://www.python.org/) implementation.\n\n## Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Tests](#tests)\n- [Useful resources](#useful-resources)\n- [Notes](#notes)\n- [Known limitations](#known-limitations)\n\n## Installation\n\nPyAUGMECON can be installed from [PyPI](https://pypi.org/) using `pip install pyaugmecon`. Detailed installation instructions for both [Anaconda](<#anaconda-installation-(advised)>) and [PyPI](#pypi-installation) installations are available below.\n\n### Requirements\n\n- [Python](https://www.python.org/)\n- [Pyomo](http://www.pyomo.org/)\n- [Numpy](https://numpy.org/)\n- [Pandas](https://pandas.pydata.org/)\n- [Cloudpickle](https://github.com/cloudpipe/cloudpickle)\n- [Pymoo](https://pymoo.org/)\n- [Gurobi](https://www.gurobi.com/) (other sovlers supported as well)\n\n> The [Gurobi Python bindings](https://www.gurobi.com/documentation/9.1/quickstart_mac/cs_python.html) are significantly faster than using the executable. So even if you have already installed Gurobi, please still install the Python version for an optimal experience.\n\n### Anaconda installation (advised)\n\nThis installation is advised as the PyPI installation of Gurobi does not include the licensing tools. Only Gurobi needs to be installed as other tools are by default included in Anaconda or will be automatically installed as dependencies of PyAUGMECON.\n\n```bash\n# Install Anaconda from https://www.anaconda.com\n\n# Install Gurobi\nconda config --add channels http://conda.anaconda.org/gurobi\nconda install gurobi\n\n# Install PyAUGMECON, and dependencies\npip install pyaugmecon\n```\n\n### PyPI installation\n\nFor a PyPI installation, only Gurobi needs to be installed, other requirements will automatically be installed as dependencies of PyAUGMECON. As mentioned above, the PyPI version of Gurobi does not include licensing tools, see [Gurobi documentation](https://support.gurobi.com/hc/en-us/articles/360044290292-How-do-I-install-Gurobi-for-Python-) on how to install these.\n\n```bash\n# Install Gurobi, PYAUGMECON, and dependencies\npip install gurobipy pyaugmecon\n```\n\n### Other solvers\nThe installation instructions above describe an installation with Gurobi, since this is the solver that has been used for testing. However, other solvers should work as well. The only requirement is that the solver is supported by Pyomo. An example of the GLPK solver can be found [in the test folder](https://github.com/wouterbles/pyaugmecon/blob/main/tests/ga/test_two_objectives.py).\n\n## Usage\n\nFirst, an optimization model generator function needs to be created to pass the model to PyAUGMECON. This function should return an unsolved instance of the optimization problem, see [Pyomo model](#pyomo-model). Essentially, the only difference in comparison with creating a single objective Pyomo optimization model is the fact that multiple objectives are defined using Pyomo's `ObjectiveList()`.\n\nThe rest of the process is automatically being taken care of by instantiating a `PyAugmecon()` object and solving it afterward with `PyAugmecon.solve()`.\n\n### PyAugmecon parameters\n\nInstantiating a `PyAugmecon(model, opts, solver_opts)` object requires the following parameters:\n\n| Name          | Description                                                                                             | Required |\n| ------------- | ------------------------------------------------------------------------------------------------------- | -------- |\n| `model`       | Function that returns an unsolved instance of the optimization problem, see [Pyomo model](#pyomo-model) | Yes      |\n| `opts`        | Dictionary of PyAUGMECON related options, see [PyAugmecon options](#pyaugmecon-options)                 | Yes      |\n| `solver_opts` | Dictionary of solver (Gurobi) options, see [solver options](#solver-options)                            | No       |\n\n### Example 3kp40\n\nThe following snippet shows how to solve the `3kp40` model from the `tests` folder:\n\n```python\nfrom pyaugmecon import PyAugmecon\nfrom tests.optimization_models import three_kp_model\n\n# Multiprocessing requires this If statement (on Windows)\nif __name__ == \"__main__\":\n    model_type = \"3kp40\"\n\n    # AUGMECON related options\n    opts = {\n        \"name\": model_type,\n        \"grid_points\": 540,\n        \"nadir_points\": [1031, 1069],\n    }\n\n    pyaugmecon = PyAugmecon(three_kp_model(model_type), opts)  # instantiate  PyAugmecon\n    pyaugmecon.solve()  # solve PyAugmecon multi-objective optimization problem\n    sols = pyaugmecon.get_pareto_solutions()  # get all pareto solutions\n    payoff = pyaugmecon.get_payoff_table()  # get the payoff table\n    decision_vars = pyaugmecon.get_decision_variables(sols[0])  # get the decision variables\n```\n\n### PyAugmecon methods\n\n| Name                     | Description                                                                                                                                             |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `get_pareto_solutions()`    | Get a list of Pareto-optimal solutions (`list[tuple]`) |\n| `get_decision_variables(pareto_solution)` | Get a dictionary of decision variables for a given Pareto-optimal solution. Where the key represents the decision variable name and the value is a pd.Series with the values. |\n| `get_payoff_table()`  | Get the payoff table from the model. |\n\n### PyAugmecon attributes\n\nAfter solving the model with `PyAugmecon.solve()`, the following object attributes are available:\n\n| Name                     | Description                                                                                                                                             |\n| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `sols`                   | Full unprocessed solutions, only checked for uniqueness                                                                                                 |\n| `unique_sols`            | Unique solutions, rounded to `round_decimals` and checked for uniqueness                                                                                |\n| `unique_pareto_sols`     | Unique Pareto solutions, only dominant solutions, rounded to `round_deicmals` and checked for uniqueness                                                |\n| `num_sols`               | Number of solutions                                                                                                                                     |\n| `num_unique_sols`        | Number of unique solutions                                                                                                                              |\n| `num_unique_pareto_sols` | Number of unique Pareto solutions                                                                                                                       |\n| `model.models_solved`    | Number of models solved (excluding solves for payoff table)                                                                                             |\n| `model.infeasibilites`   | Number of models solved that were infeasible                                                                                                            |\n| `model.to_solve`         | Total number of models to solve (including payoff table)                                                                                                |\n| `model.model`            | Pyomo model instance                                                                                                                                    |\n| `model.payoff`           | Payoff table                                                                                                                                            |\n| `model.e`                | Gridpoints of p-1 objective functions that are used as constraints                                                                                      |\n| `hv_indicator`           | The hypervolume indicator of the unique Pareto solutions, [see Pymoo documentation](https://pymoo.org/misc/performance_indicator.html) for more details |\n| `runtime`                | Total runtime in seconds                                                                                                                                |\n\n### PyAugmecon solutions details\n\nThe solutions are stored in the `sols`, `unique_sols`, and `unique_pareto_sols` attributes. These differ in the following ways:\n\n- `sols` contains all solutions, including duplicates and non-Pareto solutions\n- `unique_sols` contains all unique solutions, including non-Pareto solutions\n- `unique_pareto_sols` contains all unique Pareto solutions\n\nThe solutions are stored dictionary, where each dictionary contains the objective values (keys) and the decision variables (values). The objective values are stored as a tuple, where the first element is the objective value of the first objective function, the second element is the objective value of the second objective function, and so on. The decision variables are stored as a dictionary, where the keys are the names of the decision variables and the values are the values of the decision variables.\n\nThis is an example of the `unique_pareto_sols` attribute:\n\n```python\n{\n    (3, 5): {'x': pd.Series([1, 2]), 'y': pd.Series([2, 3])},\n    (4, 4): {'x': pd.Series([3, 4]), 'y': pd.Series([1, 2])},\n    (5, 3): {'x': pd.Series([2, 4]), 'y': pd.Series([1, 3])},\n}\n```\n\n### PyAugmecon options\n\nThe following PyAUGMECON related options can be passed as a dictionary to the solver:\n\n| Option               | Description                                                                                                                                                                                                                                                                                                                        | Default                       |\n| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |\n| `name`               | Name of the model, used in logging output                                                                                                                                                                                                                                                                                          | `Undefined`                   |\n| `grid_points`        | Number of grid points (if X grid points in GAMS, X+1 grid points are needed in order to exactly replicate results)                                                                                                                                                                                                                 |                               |\n| `nadir_points`       | If the exact nadir points are known \u2014 these can be provided, otherwise they will be taken from the payoff table                                                                                                                                                                                                                    | `True`                        |\n| `early_exit`         | Use inner loop early-exit (AUGMECON) \u2014 exit the inner loop when the model result becomes infeasible                                                                                                                                                                                                                                | `True`                        |\n| `bypass_coefficient` | Use bypass coefficient (AUGMECON2) \u2014 utilize slack variables to skip redundant iterations                                                                                                                                                                                                                                          | `True`                        |\n| `flag_array`         | Use flag array (AUGMECON-R) \u2014 store early exit and bypass coefficients for upcoming iterations                                                                                                                                                                                                                                     | `True`                        |\n| `penalty_weight`     | The penalty by which other terms in the objective are multiplied, usually between `10e-3` and `10e-6`                                                                                                                                                                                                                              | `1e-3`                        |\n| `nadir_ratio`        | For problems with three or more objective functions, the payoff table minima do not guarantee the exact nadir. This factor scales the payoff minima. By providing a value lower than one, lower bounds of the minima can be estimated                                                                                              | `1`                           |\n| `logging_folder`     | Folder to store log files (relative to the root directory)                                                                                                                                                                                                                                                                         | `logs`                        |\n| `cpu_count`          | Specify over how many processes the work should be divided. Use `1` to disable parallelization                                                                                                                                                                                                                                     | `multiprocessing.cpu_count()` |\n| `redivide_work`      | Have processes take work from unfinished processes when their queue is empty                                                                                                                                                                                                                                                       | `True`                        |\n| `shared_flag`        | Share the flag array between processes. If false, each process will have its own flag array                                                                                                                                                                                                                                        | `True`                        |\n| `round_decimals`     | The number of decimals to which the solutions are rounded before checking for uniqueness                                                                                                                                                                                                                                           | `9`                           |\n| `pickle_file`        | Filename of the pickled [Pyomo](http://www.pyomo.org/) model for [cloudpickle](https://github.com/cloudpipe/cloudpickle)                                                                                                                                                                                                           | `model.p`                     |\n| `solver_name`        | Name of the solver provided to [Pyomo](http://www.pyomo.org/)                                                                                                                                                                                                                                                                      | `gurobi`                      |\n| `solver_io`          | Name of the solver interface provided to [Pyomo](http://www.pyomo.org/). As the [Gurobi Python bindings](https://www.gurobi.com/documentation/9.1/quickstart_mac/cs_python.html) are significantly faster than using the executable, they are set by default. If you still prefer to use the executable, set this option to `None` | `python`                      |\n| `output_excel`       | Create an excel with solver output in the `logging_folder` containing the payoff table, e-points, solutions, unique solutions, and unique Pareto solutions                                                                                                                                                                         | `True`                        |\n| `process_logging`    | Outputs solution process information from sub-processes to the log file. This significantly reduces performances and does not work on Windows. Don't enable this unless necessary                                                                                                                                                  | `False`                       |\n| `process_timeout`    | Gracefully stops all processes after `process_timeout` in seconds. As processes are stopped gracefully they will be allowed to finish their assigned work and not stop exactly after `process_timeout`                                                                                                                             | `None`                        |\n\n### Solver options\n\nTo solve the single-objective optimization problems generated by the AUGMECON method they are passed to Gurobi, an external solver. All [Gurobi solver parameters](https://www.gurobi.com/documentation/9.1/refman/parameters.html) can be passed to Gurobi with this dictionary. Two parameters are already set by default, but can be overridden:\n\n| Option      | Description                                                                                          | Default |\n| ----------- | ---------------------------------------------------------------------------------------------------- | ------- |\n| `MIPGap`    | See Gurobi documentation: [MIPGap](https://www.gurobi.com/documentation/9.1/refman/mipgap2.html)     | `0.0`   |\n| `NonConvex` | See Gurobi documentation [NonConvex](https://www.gurobi.com/documentation/9.1/refman/nonconvex.html) | `2`     |\n\n### Pyomo model\n\nA multi-objective Pyomo model is similar to a single-objective model, except that the objectives should be defined using Pyomo's `ObjectiveList()` and attached to the model by an attribute named `obj_list`. Multiple example models can be found in the `tests` folder and a simple model can be found below:\n\n```python\ndef two_objective_model():\n    model = ConcreteModel()\n\n    # Define variables\n    model.x1 = Var(within=NonNegativeReals)\n    model.x2 = Var(within=NonNegativeReals)\n\n    # --------------------------------------\n    #   Define the objective functions\n    # --------------------------------------\n\n    def objective1(model):\n        return model.x1\n\n    def objective2(model):\n        return 3 * model.x1 + 4 * model.x2\n\n    # --------------------------------------\n    #   Define the regular constraints\n    # --------------------------------------\n\n    def constraint1(model):\n        return model.x1 <= 20\n\n    def constraint2(model):\n        return model.x2 <= 40\n\n    def constraint3(model):\n        return 5 * model.x1 + 4 * model.x2 <= 200\n\n    # --------------------------------------\n    #   Add components to the model\n    # --------------------------------------\n\n    # Add the constraints to the model\n    model.con1 = Constraint(rule=constraint1)\n    model.con2 = Constraint(rule=constraint2)\n    model.con3 = Constraint(rule=constraint3)\n\n    # Add the objective functions to the model using ObjectiveList(). Note\n    # that the first index is 1 instead of 0!\n    model.obj_list = ObjectiveList()\n    model.obj_list.add(expr=objective1(model), sense=maximize)\n    model.obj_list.add(expr=objective2(model), sense=maximize)\n\n    # By default deactivate all the objective functions\n    for o in range(len(model.obj_list)):\n        model.obj_list[o + 1].deactivate()\n\n    return model\n```\n\n## Tests\n\nTo test the correctness of the proposed approach, the following optimization models have been tested both using the GAMS and the proposed implementations:\n\n- Sample bi-objective problem of the original paper\n- Sample three-objective problem of the original implementation/presentation\n- Multi-objective multidimensional knapsack (MOMKP) problems: 2kp50, 2kp100, 2kp250, 3kp40, 3kp50, 4kp40 and 4kp50\n- Multi-objective economic dispatch (minimize cost, emissions and unmet demand)\n\nThese models can be found in the **tests** folder and run with [PyTest](https://pytest.org) to test for the correctness of the payoff table and the Pareto solutions. Example: `pytest tests/test_3kp40.py`\n\n> Despite the extensive testing, the PyAUGMECON implementation is provided without any warranty. Use it at your own risk!\n\n## Useful resources\n\n### Original AUGMECON\n\n- G. Mavrotas, \u201cEffective implementation of the \u03b5-constraint methodin Multi-Objective Mathematical Programming problems,\u201d _Applied Mathematics and Computation_, vol. 213, no. 2, pp. 455\u2013465, 2009\n- [GAMS implementation](https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_epscm.html)\n\n### Improved AUGMECON2\n\n- Mavrotas and K. Florios, \u201cAn improved version of the augmented \u03b5-constraint method (AUGMECON2) for finding the exact pareto set in multi-objective integer programming problems,\u201d _Applied Mathematics and Computation_, vol. 219, no. 18, pp. 9652\u20139669, 2013.\n- [GAMS implementation](https://www.gams.com/latest/gamslib_ml/libhtml/gamslib_epscmmip.html)\n\n### Further improved AUGMECON-R\n\n- A. Nikas, A. Fountoulakis, A. Forouli, and H. Doukas, _A robust augmented \u03b5-constraint method (AUGMECON-R) for finding exact solutions of multi-objective linear programming problems._ Springer Berlin Heidelberg, 2020, no. 0123456789.\n- [GAMS implementation](https://github.com/KatforEpu/Augmecon-R)\n\n### Other resources\n\n- [The following PhD thesis is also very useful](https://www.chemeng.ntua.gr/gm/gmsite_gre/index_files/PHD_mavrotas_text.pdf)\n- [This presentation provides a quick overview](https://www.chemeng.ntua.gr/gm/gmsite_eng/index_files/mavrotas_MCDA64_2006.pdf)\n\n## Notes\n\n- The choice of the objective function(s) to add as constraints affects the mapping of the Pareto front. Empirically, having one of the objective functions with a large range in the constraint set tends to result in a denser representation of the Pareto front. Nevertheless, despite the choice of which objectives to add in the constraint set, the solutions belong to the same Pareto front (obviously).\n\n- If X grid points in GAMS, X+1 grid points are needed in PyAUGMECON in order to exactly replicate results\n\n- For some models, it is beneficial to runtime to reduce the number of solver (Gurobi) threads. More details: [Gurobi documentation](https://www.gurobi.com/documentation/9.1/refman/threads.html)\n\n## Known limitations\n\n- For relatively small models (most of the knapsack problems), disabling `redivide_work` and `shared_flag` should lead to slightly lower runtimes. This is due to the overhead of sharing the flag array between processes that don't have a shared memory space. Redividing the work results in additional models solved with duplicate solutions, leading to longer runtime. By sharing the flag array in a different way and dividing the work more smartly these limitations might be solved in the future.\n\n- To parallelize the solution process, the grid is divided into blocks with a minimum length of the inner loop (number of grid points) over the processes. With fewer than three objectives, there is only one dimension to iterate over, and as such no parallelization possible. This is something that can be improved in the future.\n\n## Changelog\n\nSee [Changelog](CHANGELOG.md)\n\n## Citing\n\nIf you use PyAUGMECON for academic work, please cite the following [DOI (Zenodo)](https://zenodo.org/badge/latestdoi/336300468).\n\n## Credit\n\nThis software was developed at the Electricity Markets & Power System Optimization Laboratory (EMPSOLab), [Electrical Energy Systems Group](https://www.tue.nl/en/research/research-groups/electrical-energy-systems/), [Department of Electrical Engineering](https://www.tue.nl/en/our-university/departments/electrical-engineering/), [Eindhoven University of Technology](https://www.tue.nl/en/).\n\nContributors:\n\n- Wouter Bles (current version of the package)\n- Nikolaos Paterakis (initial implementation)\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2021-2024 Electrical Energy Systems Group, Department of Electrical Engineering, Eindhoven University of Technology.  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "An AUGMECON based multi-objective optimization solver for Pyomo.",
    "version": "1.0.8",
    "project_urls": {
        "Changelog": "https://github.com/wouterbles/pyaugmecon/blob/main/CHANGELOG.md",
        "Homepage": "https://github.com/wouterbles/pyaugmecon"
    },
    "split_keywords": [
        "python",
        "pyomo",
        "optimization",
        "multi-objective-optimization",
        "augmecon"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4e66f434d2ec0fd2cd2d4b45f9b7a0a761968c191eef3ad71c92747f28d45365",
                "md5": "e581a46a84528d0dc7452178c6f1a50e",
                "sha256": "e0a86a54a72d84d94258463060e99c6f696039912eb40e823369887b48e6c100"
            },
            "downloads": -1,
            "filename": "pyaugmecon-1.0.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e581a46a84528d0dc7452178c6f1a50e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 24474,
            "upload_time": "2024-02-26T15:52:39",
            "upload_time_iso_8601": "2024-02-26T15:52:39.296355Z",
            "url": "https://files.pythonhosted.org/packages/4e/66/f434d2ec0fd2cd2d4b45f9b7a0a761968c191eef3ad71c92747f28d45365/pyaugmecon-1.0.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "21c91e79e3e1bafdcdd1e11a8791f4c6141edeed11ac7396821c53fc5c3e4ae5",
                "md5": "e6d472b692f17f95e1e2d3e02767be1b",
                "sha256": "039046b32cfb8f5eeecf0b8dbd828df98c5fe308df2d0423d070c984550b428c"
            },
            "downloads": -1,
            "filename": "pyaugmecon-1.0.8.tar.gz",
            "has_sig": false,
            "md5_digest": "e6d472b692f17f95e1e2d3e02767be1b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 29563,
            "upload_time": "2024-02-26T15:52:41",
            "upload_time_iso_8601": "2024-02-26T15:52:41.479347Z",
            "url": "https://files.pythonhosted.org/packages/21/c9/1e79e3e1bafdcdd1e11a8791f4c6141edeed11ac7396821c53fc5c3e4ae5/pyaugmecon-1.0.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-26 15:52:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "wouterbles",
    "github_project": "pyaugmecon",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pyaugmecon"
}
        
Elapsed time: 0.39416s