Solve unit commitment in Python (MINLP)

Unit commitment is the classic power-systems planning problem: given several generating units, decide which to switch on and how much each should produce to meet demand at minimum cost. It mixes binary on/off decisions with a nonlinear cost curve — a mixed-integer nonlinear program (MINLP). With quicopt it is a short Pyomo model.

Why it's hard

An off unit costs nothing and produces nothing; an on unit pays a fixed start cost plus a fuel cost that grows with output (here, quadratically). The on/off choices are discrete and the cost is nonlinear, so neither an LP nor a plain nonlinear solver fits — you need MINLP.

Model it

Binary on[i] switches unit i; continuous p[i] is its output, capped at zero unless the unit is on. Meet demand, minimize fixed + fuel cost. Modeled in Pyomo (pip install "quicopt[pyomo]"):

unit_commitment.py
import pyomo.environ as pyo
from quicopt import Client
caps, fixed, a = [50.0, 60.0, 40.0], [100.0, 120.0, 80.0], [0.010, 0.008, 0.012]
demand = 100.0
m = pyo.ConcreteModel()
m.on = pyo.Var(range(3), domain=pyo.Binary)
m.p = pyo.Var(range(3), bounds=(0, None))
m.cap = pyo.Constraint(range(3), rule=lambda m, i: m.p[i] <= caps[i] * m.on[i])
m.dem = pyo.Constraint(expr=sum(m.p[i] for i in range(3)) >= demand)
m.obj = pyo.Objective(expr=sum(fixed[i]*m.on[i] + a[i]*m.p[i]**2 for i in range(3)), sense=pyo.minimize)
print(Client("https://try.quicoptapi.pgi.fz-juelich.de").solve(m).display)
$ python unit_commitment.py
├── status:     optimal
├── feasible:   true
├── objective:  248.0
├── x:          x1=0, x2=1, x3=1, x4=0, x5=60, x6=40  (6 variables)
└── solve_time: 0.0136 s

What you get

The least-cost plan switches on units 2 and 3 (x2=1, x3=1) at outputs 60 and 40 to cover demand 100, for a total cost of 248. Unit 1 stays off — its fixed cost plus fuel would beat neither option. quicopt returns this from binary on/off decisions and a nonlinear cost in one solve.

status: optimal means quicopt proved this is the least-cost commitment — no mix of on/off decisions and outputs does better. The quadratic fuel cost is convex on its own; what makes the problem hard is the binary on/off switching, which is why it needs a mixed-integer solver rather than a plain nonlinear one. The same model extends to more units, multiple time periods, and ramp limits by adding constraints.

Next

Reference: A. J. Wood, B. F. Wollenberg, G. B. Sheblé, Power Generation, Operation, and Control, Wiley (3rd ed., 2013).

A bigger fleet — or a different problem?

Tell us what you're optimizing. We'll help you model it and point you at the right approach.

Talk to us →

Frequently asked questions

Why isn't this just a linear program?

Two things break linearity: the on/off decisions are binary, and the fuel cost rises nonlinearly with output. Together that is a mixed-integer nonlinear program (MINLP) — quicopt handles both in one model.

Can I use integer (not just binary) unit counts?

On the free tier, nonlinear models accept binary integers only; general integers return a 422. Model each unit as its own binary on/off, which is the standard formulation anyway.

Is quicopt free to use?

Yes — pip install quicopt and your first call sets up a free key, no license.