This is a simple wrapper that goes around the C API for Gurobi.
When this module is installed properly (with go generate
),
you can use it to set up Mathematical Programs with or
without using the MatProInterface.
Effectively Solve Mathematical Programs | Using the Tools of Mathematical Programming |
The above example will be discussed in more detail in a Wiki or example for this library.
To get a sense of how to use Gurobi.go, feel free to use the examples in the examples
directory as a guide. You can solve
optimization problems using the gurobi
package in this library or using MatProInterface.go
, a modelling library developed
by the MatProGo-dev team.
To illustrate how to use each, we solve the QP above using each option.
gurobi
package main
import (
"fmt"
gurobi "github.com/MatProGo-dev/Gurobi.go/gurobi"
)
func main() {
// Constants
exampleName := "gurobi_go-qp1"
// Create environment.
env, err := gurobi.NewEnv(exampleName + ".log")
if err != nil {
panic(err.Error())
}
defer env.Free()
// Create an empty model.
model, err := gurobi.NewModel(exampleName+".model", env)
if err != nil {
panic(err.Error())
}
defer model.Free()
// Add varibles
x1, err := model.AddVar(gurobi.CONTINUOUS, 0.0, -gurobi.INFINITY, gurobi.INFINITY, "x", []*gurobi.Constr{}, []float64{})
if err != nil {
panic(err.Error())
}
x2, err := model.AddVar(gurobi.CONTINUOUS, 0.0, -gurobi.INFINITY, gurobi.INFINITY, "y", []*gurobi.Constr{}, []float64{})
if err != nil {
panic(err.Error())
}
// Integrate new variables.
if err := model.Update(); err != nil {
panic(err.Error())
}
// Set Objective function
expr := gurobi.QuadExpr{}
expr.AddTerm(x2, -0.97).AddQTerm(x1, x1, 1).AddQTerm(x1, x2, 0.5).AddQTerm(x2, x2, 0.25)
if err := model.SetObjective(&expr, gurobi.MINIMIZE); err != nil {
panic(err.Error())
}
// First constraint
if _, err = model.AddConstr([]*gurobi.Var{x1, x2}, []float64{1.0, 0.0}, '>', 0.0, "c0"); err != nil {
panic(err.Error())
}
// Second constraint
if _, err = model.AddConstr([]*gurobi.Var{x1, x2}, []float64{0.0, 1}, '>', 1.0, "c1"); err != nil {
panic(err.Error())
}
// Third constraint
if _, err = model.AddConstr([]*gurobi.Var{x1, x2}, []float64{1.0, 0.0}, '<', 2.0, "c2"); err != nil {
panic(err.Error())
}
// Fourth constraint
if _, err = model.AddConstr([]*gurobi.Var{x1, x2}, []float64{0.0, 1}, '<', 3.0, "c3"); err != nil {
panic(err.Error())
}
// Optimize model
if err := model.Optimize(); err != nil {
panic(err.Error())
}
// Write model to 'qp1.lp'.
if err := model.Write(exampleName + ".lp"); err != nil {
panic(err.Error())
}
// Capture solution information
optimstatus, err := model.GetIntAttr(gurobi.INT_ATTR_STATUS)
if err != nil {
panic(err.Error())
}
objval, err := model.GetDoubleAttr(gurobi.DBL_ATTR_OBJVAL)
if err != nil {
panic(err.Error())
}
sol, err := model.GetDoubleAttrVars(gurobi.DBL_ATTR_X, []*gurobi.Var{x1, x2})
if err != nil {
panic(err.Error())
}
fmt.Printf("\nOptimization complete\n")
if optimstatus == gurobi.OPTIMAL {
fmt.Printf("Optimal objective: %.4e\n", objval)
fmt.Printf(" x=%.4f, y=%.4f\n", sol[0], sol[1])
} else if optimstatus == gurobi.INF_OR_UNBD {
fmt.Printf("Model is infeasible or unbounded\n")
} else {
fmt.Printf("Optimization was stopped early\n")
}
}
MatProInterface.go
package main
import (
"fmt"
"github.com/MatProGo-dev/Gurobi.go/mpgSolver"
"gonum.org/v1/gonum/mat"
gurobi "github.com/MatProGo-dev/Gurobi.go/gurobi"
"github.com/MatProGo-dev/MatProInterface.go/optim"
)
func main() {
// Constants
exampleName := "matprointerface-qp1"
// Create environment.
env, err := gurobi.NewEnv(exampleName + ".log")
if err != nil {
panic(err.Error())
}
defer env.Free()
// Create an empty model.
model := optim.NewModel(exampleName + ".model")
// Add varibles
x := model.AddVariableVector(2)
vd1 := mat.NewVecDense(2, []float64{0.0, 1.0})
vd2 := mat.NewVecDense(2, []float64{2.0, 3.0})
// Create constraints
err = model.AddConstraint(x.GreaterEq(*vd1))
if err != nil {
panic(fmt.Sprintf("there was an issue creating the proper vector constraint: %v", err))
}
err = model.AddConstraint(x.LessEq(*vd2))
if err != nil {
panic(fmt.Sprintf("there was an issue creating the proper vector constraint: %v", err))
}
// Set Objective function
Q1 := *mat.NewDense(2, 2, []float64{1.0, 0.25, 0.25, 0.25})
prod1, _ := x.Transpose().Multiply(Q1)
prod2, err := prod1.Multiply(x)
if err != nil {
panic(fmt.Sprintf("there was an issue creating product 2: %v", err))
}
sum, err := prod2.Plus(
x.Transpose().Multiply(*mat.NewVecDense(2, []float64{0, -0.97})),
)
if err != nil {
panic(fmt.Sprintf("There was an issue computing the final sum: %v", err))
}
err = model.SetObjective(sum, optim.SenseMinimize)
if err != nil {
panic(fmt.Sprintf("There was an issue setting the objective for the model: %v", err))
}
// Solve the above model with GurobiSolver
sol, gs, err := mpgSolver.Solve(*model)
if err != nil {
panic(
fmt.Errorf("error in solving model: %v", err),
)
}
//// Write model to 'qp.lp'.
fmt.Printf("%v\n%v\n%v\n", gs.GoopIDToGurobiIndexMap, x.Elements[0].ID, x.Elements[1].ID)
if err := gs.CurrentModel.Write(exampleName + ".lp"); err != nil {
panic(err.Error())
}
// Capture solution information
optimstatus := sol.Status
objval := sol.Objective
fmt.Printf("\nOptimization complete\n")
if optimstatus == gurobi.OPTIMAL {
fmt.Printf("Optimal objective: %.4e\n", objval)
fmt.Printf(" x_1=%.4f, x_2=%.4f\n", sol.Values[0], sol.Values[1])
} else if optimstatus == gurobi.INF_OR_UNBD {
fmt.Printf("Model is infeasible or unbounded\n")
} else {
fmt.Printf("Optimization was stopped early\n")
}
}
Note: As of November 2023, only QP1 has been tested.
Warning: The setup script is designed to only work on Mac OS X. If you are interested in using this on a Windows machine, then there are no guarantees that it will work.
If you are using this as part of another Go project, then you will need to install this as a module ready for import. To do this, follow the instructions below:
- Get this module using the "-d" option.
go get -d github.com/MatProGo-dev/Gurobi.go/gurobi
. Pay attention to which version appears in your terminal output. - Enter Go's internal installation of gurobi.go. For example, run
cd ~/go/pkg/mod/github.com/MatProGo-dev/[email protected]
where the suffix is the version number from the previous output. - Run go generate with sudo privileges from this installation.
sudo go generate
.
If you wish to improve upon Gurobi.go, then you can simply clone the repository into your local file system and then run go generate
.
- Clone the library using
git clone github.com/MatProGo-dev/Gurobi.go
- Enter the repository:
cd Gurobi.go
. - Run the setup script from inside the cloned repository:
go generate
.
See LICENSE.
- Figure Out What Needs to Change in
setup
package to work on:- Windows Computers
- Linux Computers
- Invite Others to Participate