Learning Path

Learn Local-MIP

Start with file-based solving, then move to the C++ or Python APIs, in-memory modeling, shared prepared models, and callback hooks for custom local-search behavior.

Overview

Pick the path that matches your workflow

This page follows the current public README, API headers, parameter template, and the public algorithm description.

Run files

CLI solver

Solve existing .mps or .lp models, use .set files, and script benchmark runs.

Open CLI tutorial
Embed

C++ / Python APIs

Configure Local-MIP from code, run the solver, and query feasibility, objective value, and solution vectors.

Open API tutorial
Build models

Modeling API

Create variables, constraints, objective sense, integrality, and solve a model without reading a file.

Open modeling tutorial
Customize search

Callbacks

Customize starts, restarts, weights, neighbor generation, and feasible or infeasible scoring logic.

Open callback tutorial
Command Line

Solve MPS or LP files directly

Use the CLI when your model already exists as a file. Build from the repository root, then run from build/ so the bundled test-set paths resolve.

Basic Usage

Build and run a 10 second solve

./build.sh release
cd build
./Local-MIP -i ../test-set/2club200v15p5scn.mps -t 10

Short and long flags are both supported. For example, -i and --model_file refer to the same required input model parameter.

Parameter File

Keep solver settings in a .set file

cd build
./Local-MIP --param_set_file ../default.set --model_file ../test-set/2club200v15p5scn.mps

A parameter file uses one parameter_name = value assignment per line. Lines beginning with # or ; are comments. Command-line arguments override values loaded from the file.

Input files.mps and .lp

The current reader handles MPS RANGES sections; SOS data is rejected with an error.

Inspect flags./Local-MIP --help

Use the binary help output as the final source for flag names in the checked-out version.

Templatedefault.set

The repository template lists every parameter with the current default and valid range.

Small configuration example

# General control
time_limit = 10
random_seed = 42
log_obj = 1

# Built-in strategy choices
start = objective
restart = best
weight = monotone
lift_scoring = lift_age
neighbor_scoring = progress_bonus

The built-in start choices are zero, random, objective, and locks. Add start_sol_path = previous.sol to load a validated warm start instead.

Library Use

Embed Local-MIP from C++ or Python

The public APIs expose the same core configuration used in normal runs, plus result queries, parameter-file loading, in-memory modeling, and callback registration.

C++ static library

Minimal file-backed solve

The source build produces build/libLocalMIP.a; headers live under src/. The example projects under example/ show standalone build commands.

#include "local_mip/Local_MIP.h"

int main() {
  Local_MIP solver;
  solver.set_model_file("test-set/2club200v15p5scn.mps");
  solver.set_sol_path("example_simple.sol");
  solver.set_time_limit(10.0);
  solver.set_log_obj(true);

  solver.run();
  if (solver.is_feasible()) {
    printf("Objective value: %.10f\n", solver.get_obj_value());
  }
  return 0;
}
Python bindings

Install in a local venv

For CPython 3.8-3.12 on Linux x86_64, the published 2.0.10 wheels are the shortest path. The venv command avoids system Python package restrictions.

python3 -m venv .venv && .venv/bin/python -m pip install localmip
.venv/bin/python -c "import localmip_py as lm; print(lm.LocalMIP)"
import localmip_py as lm

solver = lm.LocalMIP()
solver.set_model_file("test-set/2club200v15p5scn.mps")
solver.set_time_limit(10.0)
solver.set_log_obj(True)
solver.run()

if solver.is_feasible():
    print("Objective:", solver.get_obj_value())
Modeling API

Build a model in memory

Use the Model API when you want to add variables and constraints from code instead of reading a model file. Build through ModelBuilder, call prepare() to freeze the model, then pass the prepared model to a single-use solver instance.

Python sketch

Variables, bounds, objective, constraints

import math
import localmip_py as lm

builder = lm.ModelBuilder()
builder.set_sense(lm.Sense.minimize)

x1 = builder.add_var("x1", 0.0, 1.0, 1.0, lm.VarType.real)
x2 = builder.add_var("x2", 0.0, 10.0, -0.5, lm.VarType.general_integer)

# x1 + 2*x2 <= 20
builder.add_con(-math.inf, 20.0, [x1, x2], [1.0, 2.0])

model = builder.prepare()
solver = lm.LocalMIP(model)
solver.set_time_limit(1.0)
solver.run()
if solver.is_feasible():
    sol = solver.get_solution()
    print("Objective:", solver.get_obj_value())
    print("x1:", sol[x1], "x2:", sol[x2])
API surface

Selected methods

ModelBuilder()Create a mutable in-memory model. builder.set_sense(Sense)Choose minimize or maximize. builder.add_var(...)Add a variable and objective coefficient. builder.add_con(...)Add a bounded linear constraint. builder.prepare(options)Normalize and freeze the model. LocalMIP(model)Create an independent solver over the prepared model. get_solution()Read the incumbent vector after a run.

Constraint bounds use lb <= expression <= ub. Preparation settings such as feasibility tolerance, zero tolerance, bound strengthening, and equality splitting belong to ModelPrepareOptions.

Shared Models

Run independent seeds over one prepared model

Local-MIP v2.0.10 can share one immutable PreparedModel across multiple solver instances without copying model data. Each solver keeps independent RNG, callbacks, timers, search state, and incumbents; the application creates the workers and selects the best result.

Python workers

Caller-managed multi-seed run

import threading
import localmip_py as lm

model = lm.PreparedModel.from_file("instance.mps")
solvers = [lm.LocalMIP(model) for _ in range(4)]

for seed, solver in enumerate(solvers, start=1):
    solver.set_random_seed(seed)
    solver.set_time_limit(10.0)

workers = [threading.Thread(target=s.run) for s in solvers]
for worker in workers:
    worker.start()
for worker in workers:
    worker.join()
Execution model

Important boundaries

PreparedModel.from_file(...)Parse, preprocess, and freeze file-backed model data once. LocalMIP(model)Create one single-use, single-trajectory solver. threading.ThreadThe caller owns scheduling and joins workers. run()Releases the Python GIL; Python callbacks reacquire it.

Local-MIP does not synchronize incumbents or create an internal thread pool. Shared callback user data must be synchronized by the application.

Concepts

The search model in one page

Mixed Integer Programming (MIP)

In the canonical minimization form used by the algorithmic description, a MIP is:

$$ \min_x \ c^\top x \quad \text{s.t.} \quad Ax \le b, \quad \ell \le x \le u, \quad x_j \in \mathbb{Z} \ \forall j \in I. $$

A solution assigns values to all variables. It is feasible when it satisfies the linear constraints, variable bounds, and integrality restrictions. Among feasible solutions, the objective value determines solution quality.

Feasible mode

Improve while preserving feasibility

When the current solution is feasible, Local-MIP maintains local feasible domains and uses lift moves to improve the objective without violating constraints.

Infeasible mode

Balance feasibility and objective progress

When constraints are violated, the search uses mixed tight and breakthrough move candidates, weighted progress scoring, and tie-breaking bonuses.

Parameters Reference

CLI flags and .set keys

The table below mirrors the current default.set, src/utils/paras.h, and ./Local-MIP --help output. The input model is required for CLI runs.

General parameters

ParameterDescriptionFlagTypeRangeDefault
model_filePath to input model file (.mps/.lp). Required for CLI runs.-istring-""
sol_pathPath to output solution file (.sol).-sstring-""
start_sol_pathPath to a warm-start solution file (.sol).-kstring-""
param_set_filePath to parameter configuration file (.set).-cstring-""
time_limitPositive time limit in seconds.-tdouble(0, 1e8]10
random_seedRandom seed for local search. 0 uses the default behavior.-Sint[0, 2147483647]0

Numerical and search parameters

ParameterDescriptionFlagTypeRangeDefault
feas_toleranceFeasibility tolerance.-Fdouble[0, 1e-2]1e-6
opt_toleranceOptimality tolerance.-Odouble[0, 1]1e-4
zero_toleranceZero value tolerance.-Zdouble[0, 1e-3]1e-9
bound_strengthenBound strengthening level: 0 off, 1 IP, 2 MIP.-bint[0, 2]1
log_objLog incumbent improvements at their actual timestamps in a bounded trace of at most 3000 points.-lint[0, 1]1
split_eqSplit equality constraints into two inequalities.-jint[0, 1]1
activity_periodFallback constraint activity recompute period. Exactly representable activities skip periodic recomputation.-Hint[1, 100000000]100000
break_eq_feasBreak feasibility on equality constraints in the lift process.-zint[0, 1]0
restart_stepNo-improvement steps before restart. 0 disables restarts.-rint[0, 100000000]1000000
smooth_probWeight smoothing probability in units of 1/10000; 0 never smooths and 10000 always smooths.-0int[0, 10000]1

BMS and tabu parameters

ParameterDescriptionFlagTypeRangeDefault
bms_unsat_conBMS unsatisfied constraint sample size.-uint[0, 100000000]10
bms_unsat_opsBMS MTM unsatisfied operations.-pint[0, 100000000]2250
bms_sat_conBMS satisfied constraint sample size.-vint[0, 100000000]1
bms_sat_opsBMS MTM satisfied operations.-oint[0, 100000000]80
bms_flip_opsBMS flip operations.-xint[0, 100000000]0
bms_easy_opsBMS easy operations.-qint[0, 100000000]5
bms_random_opsBMS random operations.-gint[0, 100000000]250
tabu_baseBase tabu tenure.-aint[0, 100000000]4
tabu_varTabu tenure variation.-eint[1, 100000000]7

Strategy selectors

ParameterDescriptionFlagValuesDefault
startBuilt-in start method.-mzero, random, objective, lockszero
restartRestart strategy.-yrandom, best, hybridbest
weightConstraint weight update method.-wsmooth, monotonemonotone
lift_scoringFeasible-phase lift scoring method.-flift_age, lift_randomlift_age
neighbor_scoringInfeasible-phase neighbor scoring method.-nprogress_bonus, progress_ageprogress_bonus

The CLI and API reject unsupported strategy names and out-of-range parameter values instead of silently selecting fallback behavior.

Callback System

Customize search without changing the solver kernel

Callbacks replace selected strategy behavior while the solver owns the main control flow. The C++ API uses typed contexts and optional void* user_data. Python callbacks use structured context objects and can also receive optional user data.

InitializationStart::Start_Ctx

Modify initial variable values and use the solver RNG.

RestartRestart::Restart_Ctx

Perturb the current assignment and adjust weights after restart triggers.

WeightWeight::Weight_Ctx

Update constraint and objective weights.

NeighborNeighbor::Neighbor_Ctx

Generate custom move candidates with helper methods.

Neighbor scoringScoring::Neighbor_Ctx

Rank infeasible-phase candidates using progress and tie-breaking state.

Lift scoringScoring::Lift_Ctx

Rank feasible-phase lift moves.

Common read-only context

Every callback receives access to a shared snapshot through ctx.m_shared in C++ or the corresponding structured object in Python.

Model data

m_model_manager, objective coefficients, variable and constraint metadata.

Current state

Current values, best values, activities, constants, equality flags, and weights.

Constraint sets

Unsatisfied and satisfied constraint index lists used by neighbor and scoring logic.

Search status

Current step, last improvement step, incumbent objective, feasibility status, and breakthrough status.

Neighbor configuration

Neighbor generation can be reset, reordered, mixed with built-in operators, or extended with user-defined generators. Custom generators should emit moves through the context helpers.

Local_MIP solver;
solver.clear_neighbor_list();
solver.add_custom_neighbor("my_random_flip", my_neighbor_cbk);
solver.add_neighbor("unsat_mtm_bm", 12, 8);
solver.add_neighbor("flip", 0, 12);
solver.set_model_file("test-set/2club200v15p5scn.mps");
solver.run();

Registration methods

set_start_cbk(callback, user_data)Custom initialization. set_restart_cbk(callback, user_data)Custom restart action. set_weight_cbk(callback, user_data)Custom weight update. add_custom_neighbor(name, callback, user_data)User-defined neighbor generator. set_neighbor_scoring_cbk(callback, user_data)Infeasible-phase scoring. set_lift_scoring_cbk(callback, user_data)Feasible-phase scoring.

Use repository examples as the runnable source of truth. Values written by start/restart callbacks and custom moves are validated for finiteness, bounds, and integrality before the solver accepts them.

Resources

Where to go next