Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ toolchain go1.23.9

require gonum.org/v1/gonum v0.16.0

require github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1
require github.com/MatProGo-dev/SymbolicMath.go v0.2.5
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1 h1:SIj6oFJgavWtArs8toeHCPfxOefG
github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
github.com/MatProGo-dev/SymbolicMath.go v0.2.4 h1:SxvgOJBpx9H6ZHISyF3A79gOd1pHJd8Nywrqf4sJZTs=
github.com/MatProGo-dev/SymbolicMath.go v0.2.4/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
github.com/MatProGo-dev/SymbolicMath.go v0.2.5 h1:fGpwtywb2hUXvGKk1Te6PQEfHeVar5w05KTbc3wHj6A=
github.com/MatProGo-dev/SymbolicMath.go v0.2.5/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
12 changes: 7 additions & 5 deletions problem/objective_sense.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package problem

import "github.com/MatProGo-dev/MatProInterface.go/optim"
import (
"github.com/MatProGo-dev/MatProInterface.go/optim"
)

// ObjSense represents whether an optimization objective is to be maximized or
// minimized. This implementation conforms to the Gurobi encoding
type ObjSense int
type ObjSense string

// Objective senses (minimize and maximize) encoding using Gurobi's standard
const (
SenseMinimize ObjSense = 1
SenseMaximize = -1
SenseFind ObjSense = 0
SenseMinimize ObjSense = "Minimize"
SenseMaximize = "Maximize"
SenseFind ObjSense = "Find"
)

/*
Expand Down
42 changes: 41 additions & 1 deletion problem/optimization_problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func From(inputModel optim.Model) (*OptimizationProblem, error) {

err = newOptimProblem.SetObjective(
objectiveExpr,
ObjSense(inputModel.Obj.Sense),
ToObjSense(inputModel.Obj.Sense),
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -994,3 +994,43 @@ func (op *OptimizationProblem) MakeNotWellDefinedError() ope.NotWellDefinedError
ErrorSource: op.Check(),
}
}

/*
String
Description:

Creates a string for the problem.
*/
func (op *OptimizationProblem) String() string {
// Create string for the objective
objString := fmt.Sprintf("\n%v\n\t%v\n", op.Objective.Sense, op.Objective.Expression)

// Create the constraints string
constraintsString := "subject to\n"
nVectorConstraints := 0
nMatrixConstraints := 0
for ii, constraint := range op.Constraints {
switch constraint.(type) {
case symbolic.ScalarConstraint:
constraintsString += fmt.Sprintf(
"\tConstraint #%v. %v\n",
ii,
constraint,
)
case symbolic.VectorConstraint:
nVectorConstraints += 1
case symbolic.MatrixConstraint:
nMatrixConstraints += 1
}
}

// Add a text summary of the vector and matrix constraints
// TODO(Kwesi): Create a String() method for vector and matrix constraints.
constraintsString += fmt.Sprintf(
"\t\tin addition to %v vector constraints and %v matrix constraints.",
nVectorConstraints,
nMatrixConstraints,
)

return objString + constraintsString
}
40 changes: 39 additions & 1 deletion testing/problem/objective_sense_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package problem_test

import (
"fmt"
"testing"

"github.com/MatProGo-dev/MatProInterface.go/optim"
"github.com/MatProGo-dev/MatProInterface.go/problem"
"testing"
)

/*
Expand Down Expand Up @@ -52,3 +54,39 @@ func TestObjectiveSense_ToObjSense2(t *testing.T) {
problem.SenseMaximize, objSense)
}
}

/*
TestObjectiveSense_String1
Description:

Tests that we can extract strings from the three normal ObjSense values
(Minimize, Maximize, Find).
*/
func TestObjectiveSense_String1(t *testing.T) {
// Test Minimize
minSense := problem.SenseMinimize
if fmt.Sprintf("%v", minSense) != "Minimize" {
t.Errorf(
"minSense's string is \"%v\"; expected \"Minimize\"",
minSense,
)
}

// Test Maximize
maxSense := problem.SenseMaximize
if fmt.Sprintf("%v", maxSense) != "Maximize" {
t.Errorf(
"maxSense's string is \"%v\"; expected \"Maximize\"",
maxSense,
)
}

// Test Find
findSense := problem.SenseFind
if fmt.Sprintf("%v", findSense) != "Find" {
t.Errorf(
"findSense's string is \"%v\"; expected \"Find\"",
findSense,
)
}
}
100 changes: 100 additions & 0 deletions testing/problem/optimization_problem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3149,3 +3149,103 @@ func TestOptimizationProblem_CopyVariable1(t *testing.T) {
)
}
}

/*
TestOptimizationProblem_String1
Description:

Tests that a small optimization problem with all scalar constraints gets represented
as a string with:
- Minimize sense of objective
- The objective expression is completely contained in the string
- the string describes that there are 0 vector constraints and 0 matrix constraints
*/
func TestOptimizationProblem_String1(t *testing.T) {
// Create Optimization Problem
p := problem.NewProblem("TestOptimizationProblem_String1")

N := 2
x := p.AddVariableVector(N)
c := symbolic.OnesVector(N)
objExpr := x.Transpose().Multiply(c)
p.SetObjective(objExpr, problem.SenseMinimize)

p.Constraints = append(p.Constraints, x.AtVec(0).LessEq(1.2))
p.Constraints = append(p.Constraints, x.AtVec(1).GreaterEq(3.14))

// Create String
pAsString := fmt.Sprintf("%s", p)

// Check that the string has "Minimize" in it
if !strings.Contains(pAsString, "Minimize") {
t.Errorf(
"Problem string does not contain the string \"Minimize\".",
)
}

if !strings.Contains(pAsString, objExpr.String()) {
t.Errorf(
"Problem string does not contain the expression in the objective %s",
objExpr,
)
}

if !strings.Contains(pAsString, "0 vector constraints") {
t.Errorf(
"Problem string does not contain \"0 vector constraints\".",
)
}

if !strings.Contains(pAsString, "0 matrix constraints") {
t.Errorf(
"Problem string does not contain \"0 matrix constraints\".",
)
}
}

/*
TestOptimizationProblem_String2
Description:

Tests that a small optimization problem with all scalar constraints gets represented
as a string with:
- Maximize sense of objective
- the string describes that there are 2 vector constraints and 1 matrix constraints
*/
func TestOptimizationProblem_String2(t *testing.T) {
// Create Optimization Problem
p := problem.NewProblem("TestOptimizationProblem_String1")

N := 2
x := p.AddVariableVector(N)
y := p.AddVariableMatrix(N, N, 0.0, 200.0, symbolic.Continuous)
c := symbolic.OnesVector(N)
objExpr := x.Transpose().Multiply(c)
p.SetObjective(objExpr, problem.SenseMaximize)

p.Constraints = append(p.Constraints, x.LessEq(c))
p.Constraints = append(p.Constraints, x.GreaterEq(symbolic.ZerosVector(N)))
p.Constraints = append(p.Constraints, y.Eq(symbolic.ZerosMatrix(N, N)))

// Create String
pAsString := fmt.Sprintf("%s", p)

// Check that the string has "Maximize" in it
if !strings.Contains(pAsString, "Maximize") {
t.Errorf(
"Problem string does not contain the string \"Maximize\".",
)
}

if !strings.Contains(pAsString, "2 vector constraints") {
t.Errorf(
"Problem string does not contain \"2 vector constraints\".",
)
}

if !strings.Contains(pAsString, "1 matrix constraints") {
t.Errorf(
"Problem string does not contain \"1 matrix constraints\".",
)
}
}