You can use model.write("mymodel.lp")
to generate an LP file (similarly for .mps
and other common formats) that you can pass in open source solvers, provided that they can read that respective format.
Since LP files are also human readable it is not too hard to transform a gurobipy model script into a script using only plain Python file operations that generates your LP file.
In order to make the second part of my answer a bit (in hindsight, it got out of hand) more succinct, I just give an example on how to generate an LP file "by hand" instead of using the gurobipy Model.write()
method. For a minimal working example, consider the binpacking problem (how cliché).
$$
\begin{aligned}
\text{minimize } & \sum_{j=0}^{n-1} y_j\\
\text{subject to } & \sum_{i=0}^{n-1} w_i x_{ij} \leq Cy_j & j \in \{0, \ldots, n-1\}\\
& \sum_{j=0}^{n-1} x_{ij} \geq 1 & i \in \{0, \ldots, n-1\}\\
& x_{ij}, y_j \in \{0, 1\} & i, j \in \{0, \ldots, n-1\}
\end{aligned}
$$
Using gurobipy
, your file looks somewhat similar to this:
from gurobipy import *
# params
w = [5, 4, 1, 2, 3]
C = 6
n = len(w)
model = Model('Binpacking')
x = {}
for i in range(n):
for j in range(n):
x[i,j] = model.addVar(vtype=GRB.BINARY, name="x#{}#{}".format(i, j))
y = {}
for j in range(n):
y[j] = model.addVar(vtype=GRB.BINARY, name="y#{}".format(j))
model.setObjective(quicksum(y[j] for j in range(n)), GRB.MINIMIZE)
for j in range(n):
model.addConstr(quicksum(w[i] * x[i,j] for i in range(n)) <= C * y[j], name="capacity#{}".format(j))
for i in range(n):
model.addConstr(quicksum(x[i,j] for j in range(n)) >= 1, name="assignment#{}#{}".format(i, j))
model.write("binpacking.lp")
Using the same program structure (which is meant to be human readable, not necessarily optimal w.r.t. execution time), we can also create a similar file only using write()
. It is a bit tedious but given the simple structure of LP files straight-forward:
# params
w = [5, 4, 1, 2, 3]
C = 6
n = len(w)
model = open("binpacking.lp", 'w')
model.write("Minimize\n")
model.write("bins: ")
for j in range(n):
model.write("+ y#{} ".format(j))
model.write("\n\nSubject to\n")
for j in range(n):
model.write("capacity#{}:\n".format(j))
for i in range(n):
model.write(" + {} x#{}#{}".format(w[i], i, j))
model.write(" - {} y#{} <= 0\n".format(C, j))
for i in range(n):
model.write("assignment#{}:\n".format(i))
for j in range(n):
model.write(" + x#{}#{}".format(i, j))
model.write(" >= 1\n")
model.write("\n\nBounds\n")
model.write("Binaries\n")
for j in range(n):
for i in range(n):
model.write(" x#{}#{}\n".format(i, j))
model.write(" y#{}\n".format(j))
model.write("End\n")
model.close()