Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding go.mod files as well as support for linear objectives and a setup script #1

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e751698
Introduced the setup.go function which should setup gurobi.go for a M…
kwesiRutledge Dec 18, 2021
e95c404
Added support for linear objectives by adding the SetLinearObjective(…
kwesiRutledge Dec 18, 2021
01c3896
Updated README.md with install instructions and a reference to the ne…
kwesiRutledge Dec 18, 2021
1aec038
Including examples and new module info in go.mod.
kwesiRutledge Dec 21, 2021
f484273
Defined gen.go which allows for setup to occur using the 'go generate…
kwesiRutledge Jan 3, 2022
ca815db
Fixed comment formatting in gen.go.
kwesiRutledge Jan 3, 2022
e6367b1
Trying something to see if this will help with install (having gen.go…
kwesiRutledge Jan 3, 2022
e3826c6
Moving again to test installation process.
kwesiRutledge Jan 3, 2022
b6a5866
Added a new SetTimeLimit() functionality and tested it.
kwesiRutledge Jan 10, 2022
8158b1d
Added instructions for using the -d version of go get for proper inst…
kwesiRutledge Jan 10, 2022
f7b0cfe
Added a more general function. SetDBLParam() can be used to set the T…
kwesiRutledge Jan 10, 2022
2556814
Completed test and added a few more objects to the allowed param values.
kwesiRutledge Jan 10, 2022
c1e9ea2
Exporting the fields of a gurobi model. Also added some changes for env.
kwesiRutledge Jan 20, 2022
107e74a
Updated the members of the Model struct so that they are all exported.
kwesiRutledge Jan 23, 2022
b3561a1
Added some comments to AddConstr(), but haven't finished it. Updated …
kwesiRutledge Feb 4, 2022
e629c3f
Added support for Apple Silicon to the setup. (Apple silicon might be…
kwesiRutledge Nov 11, 2022
7494a94
Update README.md to reference MatProGo
kwesiRutledge Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
*.log
*.lp
.vscode/

# Ignore the cgo helper files and gurobi passthrough files
***cgoHelper.go
*gurobi_passthrough.h
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
# NOTE: This repository has now been replaced by the organization [MatProGo](https://github.com/MatProGo-dev)'s project: [Gurobi.go](https://github.com/MatProGo-dev/Gurobi.go/tree/main)

# Gurobi Interfaces for Golang

Unofficial Gurobi Interfaces for Golang.

(inspired from https://github.com/JuliaOpt/Gurobi.jl)
(inspired by https://github.com/JuliaOpt/Gurobi.jl)

## Installation

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.

### Installation in Module

1. Use a "-d" `go get -d github.com/kwesiRutledge/gurobi.go/gurobi`. Pay attention to which version appears in your terminal output.
2. Enter Go's internal installation of gurobi.go. For example, run `cd ~/go/pkg/mod/github.com/kwesi\!rutledge/[email protected]` where the suffix is the version number from the previous output.
3. Run go generate with sudo privileges from this installation. `sudo go generate`.

### Development Installation

1. Clone the library using `git clone github.com/kwesiRutledge/gurobi.go `
2. Run the setup script from inside the cloned repository: `go generate`.



## Usage

See the `testing` directory for some examples of how to use this.

Works in progress...



## LICENSE
See [LICENSE](LICENSE).
7 changes: 5 additions & 2 deletions examples/qp.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package main

import "../gurobi"
import "fmt"
import (
"fmt"

gurobi "../gurobi"
)

func main() {
// Create environment.
Expand Down
9 changes: 9 additions & 0 deletions gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gurobi

/*
gen.go
Description:
Includes a go:generate statement. This will be called when the user runs go generate.
*/

//go:generate go run utils/setup.go
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/kwesiRutledge/gurobi.go

go 1.16
133 changes: 131 additions & 2 deletions gurobi/env.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package gurobi

// #include <gurobi_c.h>
// #include <gurobi_passthrough.h>
import "C"
import "errors"
import (
"errors"
"fmt"
)

type Env struct {
env *C.GRBenv
Expand All @@ -25,3 +28,129 @@ func (env *Env) Free() {
C.GRBfreeenv(env.env)
}
}

/*
SetTimeLimit
Description:
This member function is meant to set the time limit of the environment that has
been created in Gurobi.
*/
func (env *Env) SetTimeLimit(limitIn float64) error {
// Constants
paramName := "TimeLimit"

// Algorithm

if env == nil {
return fmt.Errorf("The input env variable to SetTimeLimit() was nil!")
}

errcode := int(C.GRBsetdblparam(env.env, C.CString(paramName), C.double(limitIn)))
if errcode != 0 {
return fmt.Errorf("There was an error running GRBsetdblparam(): Error code %v", errcode)
}

// If everything was successful, then return nil.
return nil

}

/*
GetTimeLimit
Description:
This member function is meant to set the time limit of the environment that has
been created in Gurobi.
*/
func (env *Env) GetTimeLimit() (float64, error) {
// Constants
paramName := "TimeLimit"

// Algorithm

if env == nil {
return -1, fmt.Errorf("The input env variable to SetTimeLimit() was nil!")
}

var limitOut C.double
errcode := int(C.GRBgetdblparam(env.env, C.CString(paramName), &limitOut))
if errcode != 0 {
return -1, fmt.Errorf("There was an error running GRBsetdblparam(): Error code %v", errcode)
}

// If everything was successful, then return nil.
return float64(limitOut), nil

}

/*
SetDBLParam()
Description:
Mirrors the functionality of the GRBsetdblattr() function from the C api.
Sets the parameter of the solver that has name paramName with value val.
*/
func (env *Env) SetDBLParam(paramName string, val float64) error {
// Check that attribute is actually a scalar double attribute.
if !IsValidDBLParam(paramName) {
return fmt.Errorf("The input attribute name (%v) is not considered a valid attribute.", paramName)
}

// Check that the env object is not nil.
if env == nil {
return fmt.Errorf("The input env variable to SetTimeLimit() was nil!")
}

// Set Attribute
errcode := int(C.GRBsetdblparam(env.env, C.CString(paramName), C.double(val)))
if errcode != 0 {
return fmt.Errorf("There was an error running GRBsetdblparam(), errcode %v", errcode)
}

// If everything was successful, then return nil.
return nil

}

/*
GetDBLParam()
Description:
Mirrors the functionality of the GRBgetdblattr() function from the C api.
Gets the parameter of the model with the name paramName if it exists.
*/
func (env *Env) GetDBLParam(paramName string) (float64, error) {
// Check the paramName to make sure it is valid
if !IsValidDBLParam(paramName) {
return -1, fmt.Errorf("The input attribute name (%v) is not considered a valid attribute.", paramName)
}

// Check environment input
if env == nil {
return -1, fmt.Errorf("The input env variable to SetTimeLimit() was nil!")
}

// Use GRBgetdblparam
var valOut C.double
errcode := int(C.GRBgetdblparam(env.env, C.CString(paramName), &valOut))
if errcode != 0 {
return -1, fmt.Errorf("There was an error running GRBgetdblparam(). Errorcode %v", errcode)
}

// If everything was successful, then return nil.
return float64(valOut), nil
}

func IsValidDBLParam(paramName string) bool {
// All param names
var scalarDoubleAttributes []string = []string{"TimeLimit", "Cutoff", "BestObjStop"}

// Check that attribute is actually a scalar double attribute.
paramNameIsValid := false

for _, validName := range scalarDoubleAttributes {
if validName == paramName {
paramNameIsValid = true
break
}
}

return paramNameIsValid
}
121 changes: 121 additions & 0 deletions gurobi/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package gurobi

import "testing"

/*
TestEnv_NewEnv1
Description:
Verifies that NewEnv() correctly creates a new environment with log file given.
*/
func TestEnv_NewEnv1(t *testing.T) {
// Constants
logfilename1 := "thomTide.log"

// Algorithm
env, err := NewEnv(logfilename1)
if err != nil {
t.Errorf("There was an issue creating the new Env variable: %v", err)
}
defer env.Free()

}

/*
TestEnv_SetTimeLimit1
Description:
Verifies that NewEnv() correctly creates a new environment with log file given.
*/
func TestEnv_SetTimeLimit1(t *testing.T) {
// Constants
logfilename1 := "thomTide.log"
var newTimeLimit float64 = 132

// Algorithm
env, err := NewEnv(logfilename1)
if err != nil {
t.Errorf("There was an issue creating the new Env variable: %v", err)
}
defer env.Free()

err = env.SetTimeLimit(newTimeLimit)
if err != nil {
t.Errorf("There was an error setting the time limit of the environment! %v", err)
}

detectedTimeLimit, err := env.GetTimeLimit()
if err != nil {
t.Errorf("There was an error getting the time limit of the environment! %v", err)
}

if detectedTimeLimit != newTimeLimit {
t.Errorf("The detected time limit (%v) was not equal to the expected time limit (%v s).", detectedTimeLimit, newTimeLimit)
}

}

/*
TestEnv_SetDBLParam1
Description:
Verifies that we can set the value of 'TimeLimit' in current model.
*/
func TestEnv_SetDBLParam1(t *testing.T) {
// Constants
logfilename1 := "thomTide.log"
var newTimeLimit float64 = 132

// Algorithm
env, err := NewEnv(logfilename1)
if err != nil {
t.Errorf("There was an issue creating the new Env variable: %v", err)
}
defer env.Free()

err = env.SetDBLParam("TimeLimit", newTimeLimit)
if err != nil {
t.Errorf("There was an error setting the time limit of the environment! %v", err)
}

detectedTimeLimit, err := env.GetDBLParam("TimeLimit")
if err != nil {
t.Errorf("There was an error getting the time limit of the environment! %v", err)
}

if detectedTimeLimit != newTimeLimit {
t.Errorf("The detected time limit (%v) was not equal to the expected time limit (%v s).", detectedTimeLimit, newTimeLimit)
}

}

/*
TestEnv_SetDBLParam2
Description:
Verifies that we can set the value of 'BestObjStop' in current model.
*/
func TestEnv_SetDBLParam2(t *testing.T) {
// Constants
logfilename1 := "thomTide.log"
var newVal float64 = 132
var paramToModify string = "BestObjStop"

// Algorithm
env, err := NewEnv(logfilename1)
if err != nil {
t.Errorf("There was an issue creating the new Env variable: %v", err)
}
defer env.Free()

err = env.SetDBLParam(paramToModify, newVal)
if err != nil {
t.Errorf("There was an error setting the time limit of the environment! %v", err)
}

detectedVal, err := env.GetDBLParam(paramToModify)
if err != nil {
t.Errorf("There was an error getting the time limit of the environment! %v", err)
}

if detectedVal != newVal {
t.Errorf("The detected %v (%v) was not equal to the expected %v (%v).", paramToModify, detectedVal, paramToModify, newVal)
}

}
4 changes: 2 additions & 2 deletions gurobi/error.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gurobi

// #include <gurobi_c.h>
// #include <gurobi_passthrough.h>
import "C"
import "errors"

Expand All @@ -27,5 +27,5 @@ func (env *Env) makeError(errcode C.int) error {
}

func (model *Model) makeError(errcode C.int) error {
return model.env.makeError(errcode)
return model.Env.makeError(errcode)
}
3 changes: 1 addition & 2 deletions gurobi/gurobi.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gurobi

// #include <gurobi_c.h>
// #cgo LDFLAGS: -lgurobi65
// #include <gurobi_passthrough.h>
import "C"

const DBL_ATTR_OBJ = C.GRB_DBL_ATTR_OBJ
Expand Down
Loading