Skip to main content

Universal MIP

umip is both:

  • a MIP modeling package with a unified solver API
  • a framework for structuring optimization systems into explicit, reusable building blocks

The framework side is the core value: it enforces clean boundaries between data prep, variable creation, constraints, objectives, and model assembly. That structure makes large MIP codebases easier to grow, test, reason about, and explain.

Purpose

The aim of this repository is to:

  • Build complex MIP models through explicit, reusable building blocks.
  • Make models modular, highly customizable, and easier to extend over time.
  • Enforce separation of responsibilities by structuring implementations into dedicated builders for variables, constraints, and objective functions.
  • Keep settings and composition logic in model factories, so model classes focus on optimization behavior.
  • Use an object-oriented framework and factory interface to keep model assembly explicit and consistent.
  • Treat objective analytics as a native framework capability, where each objective function builder can expose named analytics and/or granularity analytics.
  • Abstract the solver layer to enable fast switching between solver engines such as OR-Tools, Gurobi, and SCIP.

Installation

This project uses uv for Python version and dependency management.

Prepare environment with default version (always minimum, currently 3.11):

uv sync

For a different Python version, use uv sync --python {version}.

Install optional solver extras as needed:

uv sync --extra ortools
uv sync --extra highs
uv sync --extra gurobi
uv sync --extra docplex
uv sync --extra pyscipopt
uv sync --extra localsolver

or /yolo:

uv sync --all-extras

Solver support

The framework supports multiple backends behind one API.

  • OR-Tools engines (SCIP, CBC, CPLEX, XPRESS, GLPK, Gurobi)
  • Native Gurobi
  • Native CPLEX
  • Native SCIP
  • Native HiGHS

Select a backend via SolverType and create it through SolverFactory.

Minimal usage flow

At a high level, production usage should look like this:

model = MyModelFactory(logger=logger, solver_type=SolverType.ORTOOLS_SCIP).construct(settings=settings)

model.build(input_data=input_data)
model.solve(time_limit=60.0)

output_data = model.get_output_data()
objective_value = model.get_objective_value()
product_analytics = model.get_analytics(granularity="product")

Notes:

  • build(...) expects an AbstractInputData implementation.
  • solve(...) runs the optimization and unpacks variable values through variable builders.
  • get_output_data() delegates conversion via your model's _convert_internal_to_output_data(...).

Modelling variables and constraints in practice

The recommended approach for production models is to back decision variables with DataFrames (pandas or polars), where each row represents one or more decision variable and associated parameters. This keeps variables, their parameters, and their solved values co-located and makes vectorised operations natural.

Creating variables

Use build_column_variables on AbstractDecisionVariableBuilder to add a column of solver variables to a DataFrame in one call. Bounds can be passed as a scalar or as a column name, in which case per-row values are read directly from the DataFrame:

data.items = self.build_column_variables(
    solver=solver,
    data=data.items,
    destination_column=VAR,
    variable_domain=VariableDomain.INTEGER,
    index_name_columns=[ITEM_NAME],
    lower_bound=0.0,
    upper_bound=UPPER_BOUND,  # reads per-row values from the UPPER_BOUND column
)

Unpacking solved values

Use unpack_column_variables after solving to replace the solver variable objects with their solved values in a new column:

data.items = self.unpack_column_variables(
    data=data.items,
    decision_variable_column=VAR,
    decision_variable_value_column=VALUE,
    solver=solver,
    variable_domain=VariableDomain.INTEGER,
)

Building constraints

Pass variable and coefficient columns directly as numpy arrays for vectorised constraint construction — one solver call per constraint regardless of the number of variables involved:

solver.add_constraint(
    coefficients=np.ones(len(data.items)),
    variables=data.items[VAR].to_numpy(),
    upper_bound=100,
    name="flow",
)

See examples/settings_factory_example.py for a complete working example of this pattern.

Multi-granularity analytics and white-boxing

One of the most useful framework features is native support for analytics at different granularities.

Typical pattern:

  • implement objective analytics on highest granularity (for example, product_store)
  • add a higher level (store)
  • add an aggregate level (total)
  • and optionally make these calculations nested/reused across levels with native caching at each level to avoid recalculation

This gives you a practical path to white-boxing complex models, as you can solve an optimization problem, while automatically get individual objective contributions on different granularities. This makes the model traceable and explainable at multiple business levels directly.

Relevant model APIs:

  • model.get_objective_analytics_granularities()
  • model.get_analytics(granularity=...)
  • model.get_named_objectives()

Framework-first project structure

When implementing a model package on top of umip, a common structure is:

  • data_prep/: input normalization and derivations.
  • variables/: one builder per set of variables.
  • constraints/: one builder per set of constraints.
  • objectives/: one builder per objective function + analytics definitions.
  • factories/: factories that build the model based on the input settings enabled for the run.
  • model.py: concrete AbstractMipModel implementation.

This style keeps optimization systems modular and easier to evolve as requirements change.

Suggested implementation path

For a new project (ground up)

  1. Start with a minimal base model made of the set of variables, set of constraints, and set of objective functions that are always present.
  2. Make sure this base model solves the minimum problem you care about. The base can be feasible and useful even without optional objective functions.
  3. Test the base model thoroughly.
  4. Define a settings object early, but leave it intentionally empty to make it explicit that no settings are implemented yet.
  5. Keep the factory settings-aware from day one, even if the first version only builds the base model.

For an existing project (incremental extension)

  1. Add or extend a settings object and wire it in the model factory so composition is decided from input settings.
from dataclasses import dataclass


@dataclass
class FlowProblemMip:
    edge_cost: bool = False
  1. Map each setting to the collection of constraint builders, variable builders, and objective function builders associated with that setting.
  2. Implement only the collection of constraint builders, variable builders, and objective function builders needed to implement the new setting / feature.
  3. Test each new setting / feature in isolation.

Examples

You can inspect the repository examples in examples/, but treat them primarily as development references.

If you specifically want a minimal settings-driven factory composition example, see examples/settings_factory_example.py

Class overview

The UMIP framework is a collection of classes that can be used to construct a MIP model. The classes are:

Abstract data classes:

Enums:

Above classes is visualised ín the below UML class diagram. For an explanation of UML diagrams, please go to https://www.uml-diagrams.org.

UML diagram

Download files

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

Source Distribution

umip-1.0.0.tar.gz (32.3 kB view details)

Uploaded Source

Built Distribution

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

umip-1.0.0-py3-none-any.whl (52.8 kB view details)

Uploaded Python 3

File details

Details for the file umip-1.0.0.tar.gz.

File metadata

  • Download URL: umip-1.0.0.tar.gz
  • Upload date:
  • Size: 32.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for umip-1.0.0.tar.gz
Algorithm Hash digest
SHA256 946a4ea1e58ff624f42901531b7236e7ad9ebd9737419389f8a92f544a9d9dc9
MD5 e8e978b694b8b9b418924900176ebe26
BLAKE2b-256 8f4a1965fd6399dec88595a3d19de647ac2b22b4ab5a3b1fab0968ef5411d03a

See more details on using hashes here.

Provenance

The following attestation bundles were made for umip-1.0.0.tar.gz:

Publisher: publish-pypi.yaml on SneaksAndData/umip

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file umip-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: umip-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 52.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for umip-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3736f082a19b548b7548bf94fb1df3370a8469f3e4e008ee3cf5cfe0d725ef4d
MD5 3c95d093072ab688f162af157573a83a
BLAKE2b-256 7762cb4960f52a5a27e9681f6b2866ec2d524a21e32e2fc172d16b18d83051b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for umip-1.0.0-py3-none-any.whl:

Publisher: publish-pypi.yaml on SneaksAndData/umip

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.0.1

2 files

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page