Skip to content
blegatPublic

About

JuMP extension for constraint and term generators

Resources

Stars

9 stars

Watchers

3 watching

Forks

Latest commit

 

History

70 Commits

Folders and files

Repository files navigation

GenOpt.jl

Build Status codecov

Pack groups of similar constraints of sum of similar terms into lightweight generators. The ExaModels extension passes these generators to ExaModels to accelerate automatic differentiation on CPU or GPU. See the presentation at JuMP-dev 2025.

License

GenOpt.jl is licensed under the MIT license.

Installation

Install GenOpt as follows:

import Pkg
Pkg.add("GenOpt")

Use with JuMP

To create a group of constraints, give ParametrizedArray as container keyword:

using GenOpt
@constraint(
    model,
    [i in 1:n],
    x[1, i] == x0[i],
    container = ParametrizedArray,
)

To create a grouped sum, use lazy_sum as follows:

@objective(
    model,
    Min,
    lazy_sum(0.5 * R[j] * (u[i, j]^2) for i in 1:N, j in 1:p),
)

Solve polynomial models with HiGHS

Register the generator and scalar polynomial bridges to use affine and quadratic lazy sums with HiGHS:

using JuMP, GenOpt
import HiGHS

model = Model(HiGHS.Optimizer)
add_bridge(model, GenOpt.FunctionGeneratorBridge)
add_bridge(model, GenOpt.PolynomialFunctionBridge)
@variable(model, x[1:4])
@constraint(model, [i in 1:4], x[i] >= 0, container = ParametrizedArray)
@constraint(model, lazy_sum(x[i] + 1 for i in 1:4) <= 12)
@objective(model, Min, lazy_sum((x[i] - i)^2 for i in 1:4))
optimize!(model)

GenOpt tracks known polynomial expressions using PolynomialFunction{F}, where F is the affine or quadratic output type. The shared builders accumulate lazy sum terms directly into that type when the optimizer needs it. HiGHS supports quadratic objectives, but not quadratic constraints. Ordinary, untagged MOI.ScalarNonlinearFunction inputs are not handled by these polynomial bridges.

Polynomial lowering currently requires filters to refer only to the iterators bound by their sum. A filter depending on an enclosing generator raises an explicit error.

Affine and quadratic constraint families are prepared once before their rows are expanded. GenOpt resolves coefficient and index columns, then fills independent scalar functions using typed loops. Functions are processed in blocks of 65,536 rows to bound temporary function storage. Forms that cannot be prepared use the scalar expansion path. Preparation supports common arithmetic, literal unit and square powers, and dense arrays with up to two dimensions. Other nonlinear numeric expressions keep MOI's scalar evaluation semantics.

Solve with ExaModels

Install ExaModels and a solver such as MadNLP:

import Pkg
Pkg.add(["ExaModels", "MadNLP"])

Loading both GenOpt and ExaModels automatically enables the extension. Use ExaModels.Optimizer to solve a JuMP model while preserving its grouped constraints and sums:

using JuMP, GenOpt
import ExaModels
import MadNLP

model = Model(() -> ExaModels.Optimizer(MadNLP.madnlp))
@variable(model, x[1:4])
@constraint(model, [i in 1:4], x[i] >= 2, container = ParametrizedArray)
@constraint(model, [i in 1:4], x[i] <= 3, container = ParametrizedArray)
@objective(model, Min, lazy_sum((x[i] - i)^2 for i in 1:4))
optimize!(model)

value.(x) # approximately [2, 2, 3, 3]
objective_value(model) # approximately 2

For an NVIDIA GPU, install and load CUDA, then pass its backend to the optimizer:

import Pkg
Pkg.add("CUDA")
using CUDA

set_optimizer(model, () -> ExaModels.Optimizer(MadNLP.madnlp, CUDABackend()))
optimize!(model)

See the quadrotor and optimal power flow examples for larger models.

About

JuMP extension for constraint and term generators

Resources

Stars

9 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages