# Standard Form for LP and MPS

Is there any way I could have Gurobi/CPLEX or any other package write/export MPS and LP files in the standard LP construct loaded with slack variables and transformations required for unsigned vars?

Here, by 'standard LP construct', I am referring to the LP formation ie. $$\{ \min ~ c^\top x : Ax = b, x \geq 0 \}$$.

EDIT: I'd also appreciate if you could share knowledge about some utility/function from Coin-OR or AMPL that can do this.

• Do i understand it correctly that you are looking for a modeling software that automtically creates slack variables for linear problems when variables require them and prduces a MPS or LP file? Sep 27 at 16:35
• yes, that is correct Sep 28 at 18:21

I am not aware of anything in the Coin-OR or AMPL ecosystem that does that as i am not familiar with those ecosystems. However one can convince the open source modeling language JuMP to do what you want with a few lines of Julia.

I assume you have a Julia installed and JuMP installed into your working (or global) environment.

Let's first create a model:

using JuMP #assumes you did ]add JuMP [enter] [waiting] [backspace] once

m = Model()

@variable(m, x[1:2])

@constraint(m, x[1] + x[2] <= 1)
@constraint(m, x[1] - x[2] <= 1)
@constraint(m, -x[1] + x[2] <= 1)
@constraint(m, -x[1] - x[2] <= 1)

@objective(m, Max, pi*x[1] -x[2])


If we know wanted to write that into an MPS or LP file it would be as easy as write_to_file(m, "test.lp") write_to_file(m, "test.mps") however that would not be in form you want. So let's define that form by defining a new model type:

MOI.Utilities.@model(
MyStandardForm,
(),
(MOI.EqualTo,),
(MOI.Nonnegatives,),
(),
(),
(MOI.ScalarAffineFunction,),
(MOI.VectorOfVariables,),
(),
false,
)

::MyStandardForm,
::Type{MOI.Reals},
)
return false
end

::MyStandardForm,
::Type{S},
) where {S<:MOI.AbstractScalarSet}
return false
end

::MyStandardForm,
::Type{MOI.Nonnegatives},
)
return true
end

function bridged_copy_to(dest, src)
MOI.copy_to(MOI.Bridges.full_bridge_optimizer(dest, Float64), src)
return dest
end


This model type uses the backend MathOptInterface to do all the transformations by only accepting a "standard LP construct". Now we got to copy our model $$m$$ into a model build from our newly defined type.

std_form = MyStandardForm{Float64}()
bridged_copy_to(std_form, backend(model))


However due to it being a user defined model the exporting is a bit more incovinient as we got to convert it first into a model type MathOptInterface defined.

MOI.write_to_file(bridged_copy_to(MOI.FileFormats.LP.Model(), std_form_m), "std_form.lp")


or for mps:

 MOI.write_to_file(bridged_copy_to(MOI.FileFormats.MPS.Model(), std_form_m), "std_form.mps")


which gives puts these files into your pwd():

maximize
obj: 3.141592653589793 x1 - 3.141592653589793 x3 - 1 x2 + 1 x4
subject to
c1: -1 x1 - 1 x2 + 1 x3 + 1 x4 - 1 x5 = -1
c2: -1 x1 + 1 x2 + 1 x3 - 1 x4 - 1 x6 = -1
c3: 1 x1 + 1 x2 - 1 x3 - 1 x4 - 1 x7 = -1
c4: 1 x1 - 1 x2 - 1 x3 + 1 x4 - 1 x8 = -1
Bounds
x1 >= 0
x2 >= 0
x3 >= 0
x4 >= 0
x5 >= 0
x6 >= 0
x7 >= 0
x8 >= 0
End


or in "std_form.mps":

NAME
ROWS
N  OBJ
E  c1
E  c2
E  c3
E  c4
COLUMNS
x1        c1        -1
x1        c2        -1
x1        c3        1
x1        c4        1
x1        OBJ       -3.141592653589793
x2        c1        -1
x2        c2        1
x2        c3        1
x2        c4        -1
x2        OBJ       1
x3        c1        1
x3        c2        1
x3        c3        -1
x3        c4        -1
x3        OBJ       3.141592653589793
x4        c1        1
x4        c2        -1
x4        c3        -1
x4        c4        1
x4        OBJ       -1
x5        c1        -1
x6        c2        -1
x7        c3        -1
x8        c4        -1
RHS
rhs       c1        -1
rhs       c2        -1
rhs       c3        -1
rhs       c4        -1
RANGES
BOUNDS
LO bounds    x1        0
PL bounds    x1
LO bounds    x2        0
PL bounds    x2
LO bounds    x3        0
PL bounds    x3
LO bounds    x4        0
PL bounds    x4
LO bounds    x5        0
PL bounds    x5
LO bounds    x6        0
PL bounds    x6
LO bounds    x7        0
PL bounds    x7
LO bounds    x8        0
PL bounds    x8
ENDATA


You can also read in existing files you then can copy to into a model instance of MyStandardFormFunctionConstraints and then copy that one in a new MOI.FileFormats.LP.Model()and write that to disk. If you wanted to do batch processing i would recommend looping over the files in Julia so you only have to pay the compilation overhead once and not per file.

If you want to use that Mixed-Integer problems MyStandardFormFunctionConstraints would need to be declared to also support those and an appropiate output format that also supports would need to be chosen.

• Awesome! Thanks for the great solution. It's good to know that JuMP has a way to do this. I might utilize this as a sub-routine for transformation, however, I do not prefer to add dependencies in my repo so, until I find a better solution I can live with this. Thanks again for your help Sep 29 at 15:24
• @mohit-mhjn I understand and know that Julia is a big dependency. (For that reason i only use Julia and it'S ecosystem ;-) ) In this case i would recommend you to create a Julia project in which stores the fact you use JuMP as in a toml file, you can also pin versions etc ... by default it will be pinned to the version you installed when creating the project. Julia actually has a language provided decent package manager. pkgdocs.julialang.org/v1.2/environments should cover what you need to know. You should also be aware that calling CPLEX/Gurobi/GLPK/CBC from JuMP is quiet easy. Sep 29 at 15:44