Skip to content

Commit

Permalink
JuMP tests actually runs.
Browse files Browse the repository at this point in the history
Fix serious performance problem in Gurobi binding, we trigger too much updatemodel() calls in the past. The newly added variable and linear constraint can be used without update.
  • Loading branch information
metab0t committed Feb 11, 2024
1 parent c278a74 commit 8057a96
Show file tree
Hide file tree
Showing 22 changed files with 318 additions and 227 deletions.
6 changes: 3 additions & 3 deletions bench/bench_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,15 @@ def bench_msk(M, N):
task.optimize()


M = 100
M = 1000
N = 100
timer = TicTocTimer()

tests = set(
tests = [
"gurobi",
"copt",
#"mosek",
)
]

if "gurobi" in tests:
timer.tic("poi_gurobi starts")
Expand Down
2 changes: 1 addition & 1 deletion bench/jump_bench/facility.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function main(io::IO, Ns = [25, 50, 75, 100])
model = solve_facility(get_model(type), n, n)
run_time = round(Int, time() - start)
num_var = num_variables(model)
println(io, "$type fac-$n $num_var $run_time")
println(io, "jump_$type fac-$n $num_var $run_time")
end
end
end
Expand Down
5 changes: 1 addition & 4 deletions bench/jump_bench/facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,7 @@ def main(Ns=[25, 50, 75, 100]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = solve_facility("gurobi_persistent", n, n)
except:
pass
model = solve_facility("gurobi_persistent", n, n)
run_time = round(time.time() - start)
with open(dir + "/benchmarks.csv", "a") as io:
io.write("pyomo fac-%i -1 %i\n" % (n, run_time))
Expand Down
9 changes: 3 additions & 6 deletions bench/jump_bench/facility_gurobipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,12 @@ def main(Ns=[25, 50, 75, 100]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = solve_facility(n, n)
except:
pass
model = solve_facility(n, n)
run_time = round(time.time() - start)
content = "gurobipy fac-%i -1 %i\n" % (n, run_time)
content = "gurobipy fac-%i -1 %i" % (n, run_time)
print(content)
with open(dir + "/benchmarks.csv", "a") as io:
io.write(content)
io.write(f"{content}\n")
return


Expand Down
119 changes: 62 additions & 57 deletions bench/jump_bench/facility_poi.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,78 +10,83 @@
import time


def solve_facility(model, G, F):
Grid = range(G + 1)
Facs = range(1, F + 1)
Dims = (1, 2)

y = make_nd_variable(model, Facs, Dims, lb=0.0, ub=1.0)
s = make_nd_variable(model, Grid, Grid, Facs, lb=0.0)
z = make_nd_variable(model, Grid, Grid, Facs, domain=poi.VariableDomain.Binary)
r = make_nd_variable(model, Grid, Grid, Facs, Dims)
d = model.add_variable()
def solve_facility(m, G, F):
y = [[m.add_variable(lb=0.0, ub=1.0) for _ in range(2)] for _ in range(F + 1)]
s = [
[[m.add_variable(lb=0.0) for _ in range(F + 1)] for _ in range(G + 1)]
for _ in range(G + 1)
]
z = [
[
[m.add_variable(domain=poi.VariableDomain.Binary) for _ in range(F + 1)]
for _ in range(G + 1)
]
for _ in range(G + 1)
]
r = [
[
[[m.add_variable() for _ in range(2)] for _ in range(F + 1)]
for _ in range(G + 1)
]
for _ in range(G + 1)
]
d = m.add_variable()

obj = poi.ExprBuilder()
obj.add(d)
model.set_objective(obj, sense=poi.ObjectiveSense.Minimize)
m.set_objective(obj, sense=poi.ObjectiveSense.Minimize)

def assmt_rule(i, j):
expr = poi.quicksum(z[i, j, f] for f in Facs)
con = model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 1.0)
return con
for i in range(G + 1):
for j in range(G + 1):
zij = z[i][j]
expr = poi.quicksum(zij[f] for f in range(1, F + 1))
m.add_linear_constraint(expr, poi.ConstraintSense.Equal, 1.0)

assmt = make_tupledict(Grid, Grid, rule=assmt_rule)
M = 2 * 1.414

def quadrhs_rule(i, j, f):
expr = s[i, j, f] - d - M * (1 - z[i, j, f])
con = model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)
return con

quadrhs = make_tupledict(Grid, Grid, Facs, rule=quadrhs_rule)

def quaddistk1_rule(i, j, f):
expr = r[i, j, f, 1] + y[f, 1] - i / G
con = model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)
return con

quaddistk1 = make_tupledict(Grid, Grid, Facs, rule=quaddistk1_rule)

def quaddistk2_rule(i, j, f):
expr = r[i, j, f, 2] + y[f, 2] - j / G
con = model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)
return con

quaddistk2 = make_tupledict(Grid, Grid, Facs, rule=quaddistk2_rule)

def quaddist_rule(i, j, f):
expr = (
r[i, j, f, 1] * r[i, j, f, 1]
+ r[i, j, f, 2] * r[i, j, f, 2]
- s[i, j, f] * s[i, j, f]
)
con = model.add_quadratic_constraint(expr, poi.ConstraintSense.LessEqual, 0.0)
return con

quaddist = make_tupledict(Grid, Grid, Facs, rule=quaddist_rule)

model.set_model_attribute(poi.ModelAttribute.TimeLimitSec, 0.0)
model.set_model_raw_parameter("Presolve", 0)
model.optimize()
for i in range(G + 1):
for j in range(G + 1):
for f in range(1, F + 1):
m.add_linear_constraint(
s[i][j][f] - d - M * (1.0 - z[i][j][f]),
poi.ConstraintSense.Equal,
0.0,
)
m.add_linear_constraint(
r[i][j][f][0] + y[f][0] - (1.0 * i) / G,
poi.ConstraintSense.Equal,
0.0,
)
m.add_linear_constraint(
r[i][j][f][1] + y[f][1] - (1.0 * j) / G,
poi.ConstraintSense.Equal,
0.0,
)
m.add_quadratic_constraint(
r[i][j][f][0] * r[i][j][f][0]
+ r[i][j][f][1] * r[i][j][f][1]
- s[i][j][f] * s[i][j][f],
poi.ConstraintSense.LessEqual,
0.0,
)

m.set_model_attribute(poi.ModelAttribute.Silent, True)
m.set_model_attribute(poi.ModelAttribute.TimeLimitSec, 0.0)
m.set_raw_parameter("Presolve", 0)
m.optimize()


def main(Ns=[25, 50, 75, 100]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = gurobi.Model()
solve_facility(model, n, n)
except:
pass
model = gurobi.Model()
solve_facility(model, n, n)
run_time = round(time.time() - start)
content = "poi fac-%i -1 %i" % (n, run_time)
print(content)
with open(dir + "/benchmarks.csv", "a") as io:
io.write("poi fac-%i -1 %i\n" % (n, run_time))
io.write(f"{content}\n")
return


Expand Down
2 changes: 1 addition & 1 deletion bench/jump_bench/lqcp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function main(io::IO, Ns = [500, 1000, 1500, 2000])
model = solve_lqcp(get_model(type), n)
run_time = round(Int, time() - start)
num_var = num_variables(model)
println(io, "$type lqcp-$n $num_var $run_time")
println(io, "jump_$type lqcp-$n $num_var $run_time")
end
end
end
Expand Down
5 changes: 1 addition & 4 deletions bench/jump_bench/lqcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ def main(Ns=[500, 1000, 1500, 2000]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = solve_lqcp("gurobi_persistent", n)
except:
pass
model = solve_lqcp("gurobi_persistent", n)
run_time = round(time.time() - start)
with open(dir + "/benchmarks.csv", "a") as io:
io.write("pyomo lqcp-%i -1 %i\n" % (n, run_time))
Expand Down
9 changes: 3 additions & 6 deletions bench/jump_bench/lqcp_gurobipy.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,12 @@ def main(Ns=[500, 1000, 1500, 2000]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = solve_lqcp(n)
except:
pass
model = solve_lqcp(n)
run_time = round(time.time() - start)
content = "gurobipy lqcp-%i -1 %i\n" % (n, run_time)
content = "gurobipy lqcp-%i -1 %i" % (n, run_time)
print(content)
with open(dir + "/benchmarks.csv", "a") as io:
io.write(content)
io.write(f"{content}\n")
return


Expand Down
112 changes: 48 additions & 64 deletions bench/jump_bench/lqcp_poi.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,90 +5,74 @@

import pyoptinterface as poi
from pyoptinterface import gurobi
from pyoptinterface import make_tupledict, make_nd_variable
import os
import time


def solve_lqcp(model, N):
n = N
m = N
dx = 1.0 / n
def solve_lqcp(m, N):
dx = 1.0 / N
T = 1.58
dt = T / n
dt = T / N
h2 = dx**2
a = 0.001
ns = range(n)
ms = range(n)

y = make_nd_variable(model, ms, ns, lb=0.0, ub=1.0)
y = [[m.add_variable(lb=0.0, ub=1.0) for _ in range(N + 1)] for _ in range(N + 1)]
u = [m.add_variable(lb=-1.0, ub=1.0) for _ in range(N + 1)]

yt = {j: 0.5 * (1 - (j * dx) ** 2) for j in range(N + 1)}

u = make_nd_variable(ms, lb=-1.0, ub=1.0)
yt = [0.5 * (1 - (j * dx) ** 2) for j in range(n + 1)]
obj = poi.ExprBuilder()
obj.add((y[m, 0] - yt[0]) * (y[m, 0] - yt[0]))
for j in range(1, n):
obj.add(2 * (y[m, j] - yt[j]) * (y[m, j] - yt[j]))
obj.add((y[m, n] - yt[n]) * (y[m, n] - yt[n]))
for i in range(1, m):
obj.add((y[N][0] - yt[0]) * (y[N][0] - yt[0]))
for j in range(1, N):
obj.add(2.0 * (y[N][j] - yt[j]) * (y[N][j] - yt[j]))
obj.add((y[N][N] - yt[N]) * (y[N][N] - yt[N]))
for i in range(1, N):
obj.add(0.25 * a * dt * 2 * (u[i] * u[i]))
obj.add(0.25 * a * dt * (u[m] * u[m]))
obj.add(0.25 * a * dt * (u[N] * u[N]))
obj.mul(1 / 4 * dx)
model.set_objective(obj, sense=poi.ObjectiveSense.Minimize)

def pde_rule(i, j):
expr = (y[i + 1, j] - y[i, j]) / dt - 0.5 * (
y[i, j - 1]
- 2 * y[i, j]
+ y[i, j + 1]
+ y[i + 1, j - 1]
- 2 * y[i + 1, j]
+ y[i + 1, j + 1]
) / h2
return model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

pde = make_tupledict(range(n - 1), range(1, n - 1), rule=pde_rule)

def ic_rule(j):
return model.add_linear_constraint(y[0, j], poi.ConstraintSense.Equal, 0.0)

ic = make_tupledict(ns, rule=ic_rule)

def bc1_rule(i):
expr = y[i, 2] - 4 * y[i, 1] + 3 * y[i, 0]
return model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

bc1 = make_tupledict(range(1, n), rule=bc1_rule)

def bc2_rule(i):
expr = (
y[i, n - 2]
- 4 * y[i, n - 1]
+ 3 * y[i, n - 0]
- (2 * dx) * (u[i] - y[i, n - 0])
)
return model.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

bc2 = make_tupledict(range(1, n), rule=bc2_rule)

model.set_model_attribute(poi.ModelAttribute.TimeLimitSec, 0.0)
model.set_model_raw_parameter("Presolve", 0)
model.optimize()
m.set_objective(obj, sense=poi.ObjectiveSense.Minimize)

for i in range(N):
for j in range(1, N):
expr = (y[i + 1][j] - y[i][j]) / dt - 0.5 * (
y[i][j - 1]
- 2 * y[i][j]
+ y[i][j + 1]
+ y[i + 1][j - 1]
- 2 * y[i + 1][j]
+ y[i + 1][j + 1]
) / h2
m.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

for j in range(N + 1):
expr = y[0][j]
m.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

for i in range(1, N):
expr = y[i][2] - 4 * y[i][1] + 3 * y[i][0]
m.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

for i in range(1, N):
expr = y[i][N - 2] - 4 * y[i][N - 1] + 3 * y[i][N] - 2 * dx * (u[i] - y[i][N])
m.add_linear_constraint(expr, poi.ConstraintSense.Equal, 0.0)

m.set_model_attribute(poi.ModelAttribute.Silent, True)
m.set_model_attribute(poi.ModelAttribute.TimeLimitSec, 0.0)
m.set_raw_parameter("Presolve", 0)
m.optimize()


def main(Ns=[500, 1000, 1500, 2000]):
dir = os.path.realpath(os.path.dirname(__file__))
for n in Ns:
start = time.time()
try:
model = gurobi.Model()
solve_lqcp(model, n)
except:
pass
model = gurobi.Model()
solve_lqcp(model, n)
run_time = round(time.time() - start)
print(f"poi lqcp-{n} -1 {run_time}")
content = "poi lqcp-%i -1 %i" % (n, run_time)
print(content)
with open(dir + "/benchmarks.csv", "a") as io:
io.write("poi lqcp-%i -1 %i\n" % (n, run_time))
io.write(f"{content}\n")
return


Expand Down
4 changes: 2 additions & 2 deletions bench/jump_bench/produce_table.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ for i in 1:size(df, 1)
type, model, variables, time = df[i, :]
inner = get!(models, model, Dict{String,Int}())
inner[type] = time
if type == "direct"
if type == "jump_direct"
inner["variables"] = variables
end
end

columns = ["model", "variables", "gurobi", "gurobipy", "poi", "direct", "default", "pyomo"]
columns = ["model", "variables", "gurobi", "gurobipy", "poi", "jump_direct", "jump_default", "pyomo"]
keys = [
"fac-25",
"fac-50",
Expand Down
Loading

0 comments on commit 8057a96

Please sign in to comment.