Skip to content

Commit efd3e27

Browse files
Adding some String()-like methods for problem.ObjSense and problem.OptimizationProblem (#15)
* Update SymbolicMath.go version * Changed how ObjSense is represented to make it easier to print * Created a simple String method for the problem and test it * Fixing bug in one conversion method from optim.Problem to problem.OptimizationProblem * Added more coverage for the problem.OptimizationProblem.String method
1 parent 4c1b027 commit efd3e27

File tree

6 files changed

+190
-8
lines changed

6 files changed

+190
-8
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ toolchain go1.23.9
66

77
require gonum.org/v1/gonum v0.16.0
88

9-
require github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1
9+
require github.com/MatProGo-dev/SymbolicMath.go v0.2.5

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1 h1:SIj6oFJgavWtArs8toeHCPfxOefG
22
github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
33
github.com/MatProGo-dev/SymbolicMath.go v0.2.4 h1:SxvgOJBpx9H6ZHISyF3A79gOd1pHJd8Nywrqf4sJZTs=
44
github.com/MatProGo-dev/SymbolicMath.go v0.2.4/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
5+
github.com/MatProGo-dev/SymbolicMath.go v0.2.5 h1:fGpwtywb2hUXvGKk1Te6PQEfHeVar5w05KTbc3wHj6A=
6+
github.com/MatProGo-dev/SymbolicMath.go v0.2.5/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
57
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
68
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=

problem/objective_sense.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package problem
22

3-
import "github.com/MatProGo-dev/MatProInterface.go/optim"
3+
import (
4+
"github.com/MatProGo-dev/MatProInterface.go/optim"
5+
)
46

57
// ObjSense represents whether an optimization objective is to be maximized or
68
// minimized. This implementation conforms to the Gurobi encoding
7-
type ObjSense int
9+
type ObjSense string
810

911
// Objective senses (minimize and maximize) encoding using Gurobi's standard
1012
const (
11-
SenseMinimize ObjSense = 1
12-
SenseMaximize = -1
13-
SenseFind ObjSense = 0
13+
SenseMinimize ObjSense = "Minimize"
14+
SenseMaximize = "Maximize"
15+
SenseFind ObjSense = "Find"
1416
)
1517

1618
/*

problem/optimization_problem.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ func From(inputModel optim.Model) (*OptimizationProblem, error) {
264264

265265
err = newOptimProblem.SetObjective(
266266
objectiveExpr,
267-
ObjSense(inputModel.Obj.Sense),
267+
ToObjSense(inputModel.Obj.Sense),
268268
)
269269
if err != nil {
270270
return nil, err
@@ -994,3 +994,43 @@ func (op *OptimizationProblem) MakeNotWellDefinedError() ope.NotWellDefinedError
994994
ErrorSource: op.Check(),
995995
}
996996
}
997+
998+
/*
999+
String
1000+
Description:
1001+
1002+
Creates a string for the problem.
1003+
*/
1004+
func (op *OptimizationProblem) String() string {
1005+
// Create string for the objective
1006+
objString := fmt.Sprintf("\n%v\n\t%v\n", op.Objective.Sense, op.Objective.Expression)
1007+
1008+
// Create the constraints string
1009+
constraintsString := "subject to\n"
1010+
nVectorConstraints := 0
1011+
nMatrixConstraints := 0
1012+
for ii, constraint := range op.Constraints {
1013+
switch constraint.(type) {
1014+
case symbolic.ScalarConstraint:
1015+
constraintsString += fmt.Sprintf(
1016+
"\tConstraint #%v. %v\n",
1017+
ii,
1018+
constraint,
1019+
)
1020+
case symbolic.VectorConstraint:
1021+
nVectorConstraints += 1
1022+
case symbolic.MatrixConstraint:
1023+
nMatrixConstraints += 1
1024+
}
1025+
}
1026+
1027+
// Add a text summary of the vector and matrix constraints
1028+
// TODO(Kwesi): Create a String() method for vector and matrix constraints.
1029+
constraintsString += fmt.Sprintf(
1030+
"\t\tin addition to %v vector constraints and %v matrix constraints.",
1031+
nVectorConstraints,
1032+
nMatrixConstraints,
1033+
)
1034+
1035+
return objString + constraintsString
1036+
}

testing/problem/objective_sense_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package problem_test
22

33
import (
4+
"fmt"
5+
"testing"
6+
47
"github.com/MatProGo-dev/MatProInterface.go/optim"
58
"github.com/MatProGo-dev/MatProInterface.go/problem"
6-
"testing"
79
)
810

911
/*
@@ -52,3 +54,39 @@ func TestObjectiveSense_ToObjSense2(t *testing.T) {
5254
problem.SenseMaximize, objSense)
5355
}
5456
}
57+
58+
/*
59+
TestObjectiveSense_String1
60+
Description:
61+
62+
Tests that we can extract strings from the three normal ObjSense values
63+
(Minimize, Maximize, Find).
64+
*/
65+
func TestObjectiveSense_String1(t *testing.T) {
66+
// Test Minimize
67+
minSense := problem.SenseMinimize
68+
if fmt.Sprintf("%v", minSense) != "Minimize" {
69+
t.Errorf(
70+
"minSense's string is \"%v\"; expected \"Minimize\"",
71+
minSense,
72+
)
73+
}
74+
75+
// Test Maximize
76+
maxSense := problem.SenseMaximize
77+
if fmt.Sprintf("%v", maxSense) != "Maximize" {
78+
t.Errorf(
79+
"maxSense's string is \"%v\"; expected \"Maximize\"",
80+
maxSense,
81+
)
82+
}
83+
84+
// Test Find
85+
findSense := problem.SenseFind
86+
if fmt.Sprintf("%v", findSense) != "Find" {
87+
t.Errorf(
88+
"findSense's string is \"%v\"; expected \"Find\"",
89+
findSense,
90+
)
91+
}
92+
}

testing/problem/optimization_problem_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,3 +3149,103 @@ func TestOptimizationProblem_CopyVariable1(t *testing.T) {
31493149
)
31503150
}
31513151
}
3152+
3153+
/*
3154+
TestOptimizationProblem_String1
3155+
Description:
3156+
3157+
Tests that a small optimization problem with all scalar constraints gets represented
3158+
as a string with:
3159+
- Minimize sense of objective
3160+
- The objective expression is completely contained in the string
3161+
- the string describes that there are 0 vector constraints and 0 matrix constraints
3162+
*/
3163+
func TestOptimizationProblem_String1(t *testing.T) {
3164+
// Create Optimization Problem
3165+
p := problem.NewProblem("TestOptimizationProblem_String1")
3166+
3167+
N := 2
3168+
x := p.AddVariableVector(N)
3169+
c := symbolic.OnesVector(N)
3170+
objExpr := x.Transpose().Multiply(c)
3171+
p.SetObjective(objExpr, problem.SenseMinimize)
3172+
3173+
p.Constraints = append(p.Constraints, x.AtVec(0).LessEq(1.2))
3174+
p.Constraints = append(p.Constraints, x.AtVec(1).GreaterEq(3.14))
3175+
3176+
// Create String
3177+
pAsString := fmt.Sprintf("%s", p)
3178+
3179+
// Check that the string has "Minimize" in it
3180+
if !strings.Contains(pAsString, "Minimize") {
3181+
t.Errorf(
3182+
"Problem string does not contain the string \"Minimize\".",
3183+
)
3184+
}
3185+
3186+
if !strings.Contains(pAsString, objExpr.String()) {
3187+
t.Errorf(
3188+
"Problem string does not contain the expression in the objective %s",
3189+
objExpr,
3190+
)
3191+
}
3192+
3193+
if !strings.Contains(pAsString, "0 vector constraints") {
3194+
t.Errorf(
3195+
"Problem string does not contain \"0 vector constraints\".",
3196+
)
3197+
}
3198+
3199+
if !strings.Contains(pAsString, "0 matrix constraints") {
3200+
t.Errorf(
3201+
"Problem string does not contain \"0 matrix constraints\".",
3202+
)
3203+
}
3204+
}
3205+
3206+
/*
3207+
TestOptimizationProblem_String2
3208+
Description:
3209+
3210+
Tests that a small optimization problem with all scalar constraints gets represented
3211+
as a string with:
3212+
- Maximize sense of objective
3213+
- the string describes that there are 2 vector constraints and 1 matrix constraints
3214+
*/
3215+
func TestOptimizationProblem_String2(t *testing.T) {
3216+
// Create Optimization Problem
3217+
p := problem.NewProblem("TestOptimizationProblem_String1")
3218+
3219+
N := 2
3220+
x := p.AddVariableVector(N)
3221+
y := p.AddVariableMatrix(N, N, 0.0, 200.0, symbolic.Continuous)
3222+
c := symbolic.OnesVector(N)
3223+
objExpr := x.Transpose().Multiply(c)
3224+
p.SetObjective(objExpr, problem.SenseMaximize)
3225+
3226+
p.Constraints = append(p.Constraints, x.LessEq(c))
3227+
p.Constraints = append(p.Constraints, x.GreaterEq(symbolic.ZerosVector(N)))
3228+
p.Constraints = append(p.Constraints, y.Eq(symbolic.ZerosMatrix(N, N)))
3229+
3230+
// Create String
3231+
pAsString := fmt.Sprintf("%s", p)
3232+
3233+
// Check that the string has "Maximize" in it
3234+
if !strings.Contains(pAsString, "Maximize") {
3235+
t.Errorf(
3236+
"Problem string does not contain the string \"Maximize\".",
3237+
)
3238+
}
3239+
3240+
if !strings.Contains(pAsString, "2 vector constraints") {
3241+
t.Errorf(
3242+
"Problem string does not contain \"2 vector constraints\".",
3243+
)
3244+
}
3245+
3246+
if !strings.Contains(pAsString, "1 matrix constraints") {
3247+
t.Errorf(
3248+
"Problem string does not contain \"1 matrix constraints\".",
3249+
)
3250+
}
3251+
}

0 commit comments

Comments
 (0)