Skip to content

Commit 3a876a7

Browse files
Replace mip package with pulp
Signed-off-by: Keval Morabia <[email protected]>
1 parent a99f503 commit 3a876a7

File tree

3 files changed

+19
-21
lines changed

3 files changed

+19
-21
lines changed

.github/workflows/gpu_tests.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ jobs:
7373
- name: Setup environment variables
7474
run: |
7575
echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/include:/usr/lib/x86_64-linux-gnu" >> $GITHUB_ENV
76-
- name: Install dependencies for mip
77-
run: apt-get update && apt-get install -y libffi-dev
7876
- name: Run gpu tests
7977
run: pip install tox-current-env && tox -e py312-cuda12-gpu --current-env
8078
gpu-tests-non-pr:

modelopt/torch/_compress/mip/mip_with_multi_layer_replacements.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from random import random
2424
from typing import Any, Hashable, Iterable, Optional, TypeAlias
2525

26-
from mip import BINARY, Model, maximize, minimize, xsum
26+
import pulp
2727

2828
from modelopt.torch._compress.mip.utils import (
2929
InfeasibleError,
@@ -57,13 +57,15 @@ def run_mip(
5757
)
5858
print("\n\n\n")
5959

60-
mip_model = Model()
60+
# Create pulp problem with appropriate sense (minimize or maximize)
61+
sense = pulp.LpMaximize if bigger_is_better else pulp.LpMinimize
62+
problem = pulp.LpProblem(name="multi_layer_replacement", sense=sense)
6163

6264
objective_vars = []
6365
constraint_vars = {constraint_key: [] for constraint_key in constraints.keys()}
6466
choice_indicators_by_layer = defaultdict(list)
65-
for replacement_id, replacement in replacements.items():
66-
is_chosen = mip_model.add_var(var_type=BINARY)
67+
for i, (replacement_id, replacement) in enumerate(replacements.items()):
68+
is_chosen = pulp.LpVariable(f"choice_{i}", cat=pulp.LpBinary)
6769
replacement["is_chosen"] = is_chosen
6870

6971
for parent_layer_idx in replacement["parent_layer_indices"]:
@@ -78,30 +80,29 @@ def run_mip(
7880

7981
# MIP constraints: each parent layer must come from exactly one chosen replacement
8082
for parent_layer_idx, curr_choice_indicators in choice_indicators_by_layer.items():
81-
mip_model += xsum(curr_choice_indicators) == 1
83+
problem += pulp.lpSum(curr_choice_indicators) == 1
8284

8385
# MIP constraints: the sum of chosen replacement costs must be lower than the max cost
8486
for constraint_key, max_cost in constraints.items():
8587
min_cost = None
8688
if isinstance(max_cost, Iterable):
8789
min_cost, max_cost = max_cost
8890

89-
if max_cost is not None:
90-
mip_model += xsum(constraint_vars[constraint_key]) <= max_cost
91-
if min_cost is not None:
92-
mip_model += xsum(constraint_vars[constraint_key]) >= min_cost
91+
# PuLP is stricter than mip - it doesn't allow NaN/inf in constraints
92+
if max_cost is not None and math.isfinite(max_cost):
93+
problem += pulp.lpSum(constraint_vars[constraint_key]) <= max_cost
94+
if min_cost is not None and math.isfinite(min_cost):
95+
problem += pulp.lpSum(constraint_vars[constraint_key]) >= min_cost
9396

9497
# MIP objective
95-
mip_model.objective = (
96-
maximize(xsum(objective_vars)) if bigger_is_better else minimize(xsum(objective_vars))
97-
)
98-
99-
if max_seconds_per_solution is not None:
100-
mip_model.max_seconds = max_seconds_per_solution
98+
problem += (pulp.lpSum(objective_vars), "objective")
10199

102-
mip_model.optimize()
100+
# Configure and run solver
101+
solver = pulp.PULP_CBC_CMD(msg=True, timeLimit=max_seconds_per_solution)
102+
problem.solve(solver)
103103

104-
if is_chosen.x is None:
104+
# Check if solution is feasible
105+
if problem.status != pulp.LpStatusOptimal:
105106
return []
106107
# raise InfeasibleError()
107108

@@ -111,7 +112,7 @@ def run_mip(
111112
chosen_replacements: ChosenReplacements = []
112113
chosen_layers = []
113114
for replacement_id, replacement in replacements.items():
114-
is_chosen = replacement["is_chosen"].x >= 0.99
115+
is_chosen = replacement["is_chosen"].varValue >= 0.99
115116
if is_chosen:
116117
assert replacement not in chosen_replacements
117118
chosen_replacements.append(replacement)

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@
107107
"hydra-core==1.3.2",
108108
"immutabledict",
109109
"lru-dict",
110-
"mip",
111110
"omegaconf==2.3.0",
112111
"pandas",
113112
"typeguard",

0 commit comments

Comments
 (0)