Skip to main content

A Python implementation of Augmented Lagrangian Coordination for decomposition-based and multidisciplinary design optimization

Project description

Python implementation of Augmented Lagrangian Coordination framework for decomposition-based and multidisciplinary design optimization

Installation

PyPI Installation

The package can easily be installed from PyPI:

pip install alcoord

Optimization Solver Installation

Depending on the optimization models you solve, you may need external optimization solvers such as Gurobi, BARON, CPLEX, SCIP, and IPOPT. Optimization problems are modeled using Pyomo, so solver availability depends on your environment and Pyomo configuration. To see available solvers, run:

pyomo help --solvers

Note that solvers need to be visible to Pyomo in addition to being installed system-wide, which may require configuring environment variables.

Development Installation

This project uses poetry for development. If you want to work on the source code, you can install from source (e.g., with conda):

git clone https://github.com/masaisaji/alcoord.git
cd alcoord
conda create -n alcoord python=3.11
conda activate alcoord
poetry install

If virtualenv or similar is preferred, run poetry install in the newly created virtual environment with Python version 3.11 or later. During development, it is recommended to run tests to ensure that the code works correctly after modifications:

poetry run pytest

Usage Pattern

The following skeleton illustrates the expected structure. Let's say you have the following problem you want to decompose

$$ \begin{aligned} \min & f_1(x_1,x_2,x_3) + f_2(x_2,x_3,x_4,x_5)\ \text{s.t.} & g_1(x_1, x_2, x_3) \leq 0\ & g_{21}(x_2, x_5) \leq 0 \ & g_{22}(x_3, x_4) \leq 0 \end{aligned} $$

into two subproblems such as

$$ \begin{aligned} \min & f_1(x_1,x_2,x_3) + \phi(x_1,x_2,x_3)\ \text{s.t.} & g_1(x_1, x_2, x_3) \leq 0 \end{aligned} $$ $$ \begin{aligned} \min & f_2(x_2,x_3,x_4,x_5) + \phi(x_2,x_3,x_4,x_5)\ \text{s.t.} & g_{21}(x_2, x_5) \leq 0 \ & g_{22}(x_3, x_4) \leq 0 \end{aligned} $$

where $\phi$ is the augmented Lagrangian term for the corresponding subproblem. To solve such problems with the augmented Lagrangian coordination method implemented in this codebase, you need:

  • a method that builds and solves each subproblem modeled with pyomo
  • an initial guess (for nonlinear programming (NLP) subproblems)

High-Level Flow and a Skeleton Code

Assuming that you already have the subproblem solve methods and an initial guess, the overall usage flow is as follows

  1. Create a "dependency matrix" with 1/0 or True/False. For example, the dependency of subproblem 1 above would be [1, 1, 1, 0, 0] since it depends on $x_1, x_2, x_3$ but not on $x_4, x_5$.
  2. In a dict, specify the following for each subproblem:
    • the optimization type ("MIP" or "NLP"),
    • the function that returns the subproblem solve result (to be detailed later), and
    • optional arguments needed for the solve function
  3. Build instances of the alcoord classes (DimensionConverter, InnerLoop, and OuterLoop)
  4. Run the algorithm and retrieve the results

A skeleton script for the above example:

from alcoord import (
    InnerLoop,
    OuterLoop,
    DimensionConverter,
    AllSubpDict,
)
import numpy as np
from example_subproblem import solve_subproblem_1, solve_subproblem_2

initial_guess: np.ndarray = np.array(
    [
        # define initial guess here
    ]
)

# Indicate subproblem's variable dependency with 1/0 or True/False
depen_matrix: list[list[int]] = [
    [1, 1, 1, 0, 0],
    [0, 1, 1, 1, 1],
]
dim_all_var = 5

# Create a dict including:
# the optimization type ("MIP" or "NLP"),
# function returning subproblem solve results,
# and optional arguments
# for each subproblem
all_subprob_dict: AllSubpDict = {
    0: {"optim type": "NLP", "function": solve_subproblem_1, "args": None},
    1: {"optim type": "NLP", "function": solve_subproblem_2, "args": None},
}

# Build necessary objects/instances
# See docs of each class for additional parameter settings
dim_conv = DimensionConverter(
    dependency_matrix=depen_matrix,
    dim_all_var=dim_all_var,
)
inner_loop = InnerLoop(
    dc=dim_conv,
    all_subprob_dict=all_subprob_dict,
    initial_guess=initial_guess,
)
outer_loop = OuterLoop(
    inner_loop=inner_loop,
)

# Run the algorithm/routine and retrieve results
res = outer_loop.run()
obj = res["objectives"]
var = res["design vars"]

Subproblem Solve Function

A function that solves a subproblem and returns its solution is expected to take the following arguments:

  • local_shared_var_target
  • lagrange_est
  • penalty_weight
  • local_var_idx
  • local_shared_var_idx
  • args
  • initial_guess

Except for args and initial_guess, these arguments are mostly used to reflect the subproblem's relation with the other subproblems, which is captured through the augmented Lagrangian terms in the objective. The augmented Lagrangian term can be obtained using a helper function get_aug_lag_term_for_pyomo, which returns a Pyomo expression you can use directly when defining the objective.

Once the subproblem optimization model is built and solved, the function is expected to return a SubproblemResult object, which is a simple dict with "objective" and "design var" keys.

A skeleton script for the above example is as follows:

from alcoord import (
    SubproblemResult,
    get_aug_lag_term_for_pyomo,
)
import pyomo.environ as pyo
import numpy as np


def solve_subproblem_1(
    local_shared_var_target: np.ndarray,
    lagrange_est: np.ndarray,
    penalty_weight: np.ndarray,
    local_var_idx: list[int],
    local_shared_var_idx: list[int],
    args=None,
    initial_guess=None,
) -> SubproblemResult:
    model = pyo.ConcreteModel()
    #
    # define indices, variables, constraints, etc
    #

    penalty_term = get_aug_lag_term_for_pyomo(
        local_shared_var_target=local_shared_var_target,
        lagrange_est=lagrange_est,
        penalty_weight=penalty_weight,
        pyomo_local_shared_var_ls=[
            model.x2, model.x3
        ],
    )
    original_objective = ... # objective expression w/o penalty
    model.obj = pyo.Objective(
        expr=original_objective + penalty_term
    )

    pyo.SolverFactory("ipopt").solve(model, tee=False)
    obj = float(pyo.value(model.obj))
    design_var = np.array(
        [
            # extract design variable values...
        ]
    )

    subp_res: SubproblemResult = {"objective": obj, "design var": design_var}
    return subp_res

Module Dependencies Map

Note: $\fbox{calling module} \rightarrow \fbox{called module}$

graph TD
    inner_loop.py --> dimension_converter.py
    inner_loop.py --> subproblems.py
    inner_loop.py --> type_defs.py
    subproblems.py --> type_defs.py
    outer_loop.py --> inner_loop.py
    outer_loop.py --> type_defs.py

Legacy version for Linux

On Linux, the legacy version lets you use pygmo and its compatible solvers for continuous nonlinear programming (NLP) problems. To install the dependency for this legacy version, run

poetry install -E legacy

for development, or

pip install "alcoord[legacy]"

for PyPI installation.

A separate set of tests for the legacy version can be run with:

poetry run pytest -m legacy

This version is unsupported on other platforms.

References

Acknowledgment

This material is based upon work supported by the National Science Foundation under Award No. 1942559. Any opinions, findings and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

alcoord-0.1.0.tar.gz (17.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

alcoord-0.1.0-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file alcoord-0.1.0.tar.gz.

File metadata

  • Download URL: alcoord-0.1.0.tar.gz
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.11.2 Linux/6.18.33.1-microsoft-standard-WSL2

File hashes

Hashes for alcoord-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b3243c928f7d96def3a84f225fda3fcef79e28cf826a4636042649216c0b1ade
MD5 931d2ed10e73e60fed95856992f37012
BLAKE2b-256 1a1da7970426c56d0a10a2097b7d6ef888f87e53361be973704c77ad40c2c5d1

See more details on using hashes here.

File details

Details for the file alcoord-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: alcoord-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.11.2 Linux/6.18.33.1-microsoft-standard-WSL2

File hashes

Hashes for alcoord-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7106703a31fa391b59d456f34d099678783cb0da5b007c397ef9cf135028a40a
MD5 c25c2b780f74e9ec38b52731f93d680c
BLAKE2b-256 b480e116b2c5337084a9692c42510ca35aa41490821b5cc445d28551c1db720b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page