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.1.tar.gz (37.7 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.1-py3-none-any.whl (75.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: umip-1.0.1.tar.gz
  • Upload date:
  • Size: 37.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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.1.tar.gz
Algorithm Hash digest
SHA256 041e8e39599421cd0b37f83af026b1cd067e7ab7efa5ba298a83b0c511383a50
MD5 9af25fdc3b5ac923aea6aef028217224
BLAKE2b-256 08246a2ad8c83b8ea015e81cbf237253486b92357c01f22c679673efdeb118be

See more details on using hashes here.

Provenance

The following attestation bundles were made for umip-1.0.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: umip-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 75.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4eced9fe4dc634aa6ed4a1b1edf51a74e07a526650cc6c5e1d1e20bd820f6e9a
MD5 4a4e09d067f0cb0266ba1650276e41d0
BLAKE2b-256 cda6af78e59088219d46874e9a0aa42f20c50f5bf2ea0a855e40a5226c28ad06

See more details on using hashes here.

Provenance

The following attestation bundles were made for umip-1.0.1-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

This release

1.0.1 This release

2 files

1.0.0

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