Skip to content

Commit 7aaf198

Browse files
committed
Added New Method for Simplifying ScalarConstraints (This needs to be more thoroughly thought out and documented)
1 parent 37b97f4 commit 7aaf198

File tree

3 files changed

+110
-22
lines changed

3 files changed

+110
-22
lines changed

README.md

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,33 +133,15 @@ code. Hopefully, this is avoided using this format.
133133
* [X] Create New AddConstr methods which work for vector constraints
134134
* [ ] Mult
135135
* [ ] General Function (in operators.go)
136-
* [ ] Methods for
137-
* [X] Scalars
138-
* [X] Constant
139-
* [X] Var
140-
* [X] ScalarLinearExpression
141-
* [X] QuadraticExpression
142-
* [ ] Vectors
143-
* [ ] Vector Constant
144-
* [ ] VarVector
145-
* [ ] VectorLinearExpression
146136
* [ ] Plus
147137
* [ ] General Function (in operators.go)
148138
* [ ] Introducing Optional Input for Variable Name to Var/VarVector
149139
* [ ] Consider renaming VarVector to VectorVar
150140
* [ ] Decide whether or not we really need the Coeffs() method (What is it doing?)
151-
* [ ] Create function for easily creating MatDense:
152-
* [ ] ones matrices
153-
* [ ] Create function for:
154-
* [ ] IsScalar()
155-
* [ ] IsVector()
156-
* [X] VectorConstraint
157-
* [X] AtVec()
158141
* [ ] Write changes to all AtVec() methods to output both elements AND errors (so we can detect out of length calls)
159142
* [ ] Determine whether or not to keep the Solution and Solver() interfaces in this module. It seems like they can be solver-specific.
160143
* [ ] Introduce MatrixVar object
161-
* [ ] Add The Following to the Expression Interface
162-
* [ ] Comparison
163-
* [ ] LessEq
164-
* [ ] GreaterEq
165-
* [ ] Eq
144+
* [ ] Add Check() to:
145+
* [ ] Expression
146+
* [ ] ScalarExpression
147+
* [ ] VectorExpression interfaces

optim/scalar_constraint.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package optim
22

3+
import "fmt"
4+
35
// ScalarConstraint represnts a linear constraint of the form x <= y, x >= y, or
46
// x == y. ScalarConstraint uses a left and right hand side expressions along with a
57
// constraint sense (<=, >=, ==) to represent a generalized linear constraint
@@ -40,6 +42,70 @@ func (sc ScalarConstraint) IsLinear() (bool, error) {
4042
return true, nil
4143
}
4244

45+
/*
46+
Simplify
47+
Description:
48+
49+
Moves all of the variables of the ScalarConstraint to its
50+
left hand side.
51+
*/
52+
func (sc ScalarConstraint) Simplify() (ScalarConstraint, error) {
53+
// Create LHS
54+
newLHS := sc.LeftHandSide
55+
56+
// Algorithm
57+
switch right := sc.RightHandSide.(type) {
58+
case K:
59+
return sc, nil
60+
case Variable:
61+
newLHS, err := newLHS.Plus(right.Multiply(-1.0))
62+
if err != nil {
63+
return sc, err
64+
}
65+
newLHSAsSE, _ := ToScalarExpression(newLHS)
66+
67+
return ScalarConstraint{
68+
LeftHandSide: newLHSAsSE,
69+
RightHandSide: K(0),
70+
Sense: sc.Sense,
71+
}, nil
72+
case ScalarLinearExpr:
73+
rightWithoutConstant := right
74+
rightWithoutConstant.C = 0.0
75+
76+
newLHS, err := newLHS.Plus(rightWithoutConstant.Multiply(-1.0))
77+
if err != nil {
78+
return sc, err
79+
}
80+
newLHSAsSE, _ := ToScalarExpression(newLHS)
81+
82+
return ScalarConstraint{
83+
LeftHandSide: newLHSAsSE,
84+
RightHandSide: K(right.C),
85+
Sense: sc.Sense,
86+
}, nil
87+
case ScalarQuadraticExpression:
88+
rightWithoutConstant := right
89+
rightWithoutConstant.C = 0.0
90+
91+
newLHS, err := newLHS.Plus(rightWithoutConstant.Multiply(-1.0))
92+
if err != nil {
93+
return sc, err
94+
}
95+
newLHSAsSE, _ := ToScalarExpression(newLHS)
96+
97+
return ScalarConstraint{
98+
LeftHandSide: newLHSAsSE,
99+
RightHandSide: K(right.C),
100+
Sense: sc.Sense,
101+
}, nil
102+
103+
default:
104+
return sc, fmt.Errorf("unexpected type of right hand side: %T", right)
105+
}
106+
107+
}
108+
43109
// ConstrSense represents if the constraint x <= y, x >= y, or x == y. For easy
44110
// integration with Gurobi, the senses have been encoding using a byte in
45111
// the same way Gurobi encodes the constraint senses.

testing/optim/scalar_constraint_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,43 @@ func TestScalarConstraint_IsLinear2(t *testing.T) {
9898
}
9999

100100
}
101+
102+
/*
103+
TestScalarConstraint_Simplify1
104+
Description:
105+
106+
Attempts to simplify the constraint between
107+
a scalar linear epression and a scalar linear expression.
108+
*/
109+
func TestScalarConstraint_Simplify1(t *testing.T) {
110+
// Constants
111+
m := optim.NewModel("scalar-constraint-test1")
112+
vv1 := m.AddVariableVector(3)
113+
sle2 := optim.ScalarLinearExpr{
114+
L: optim.OnesVector(vv1.Len()),
115+
X: vv1,
116+
C: 2.0,
117+
}
118+
sle3 := optim.ScalarLinearExpr{
119+
L: *mat.NewVecDense(vv1.Len(), []float64{1.0, 2.0, 3.0}),
120+
X: vv1,
121+
C: 1.0,
122+
}
123+
124+
// Create sles
125+
sc1 := optim.ScalarConstraint{
126+
LeftHandSide: sle2,
127+
RightHandSide: sle3,
128+
Sense: optim.SenseEqual,
129+
}
130+
131+
// Attempt to simplify
132+
sc2, err := sc1.Simplify()
133+
if err != nil {
134+
t.Errorf("unexpected error during simplify(): %v", err)
135+
}
136+
137+
if float64(sc2.RightHandSide.(optim.K)) != 1.0 {
138+
t.Errorf("Remainder on LHS was not contained properly")
139+
}
140+
}

0 commit comments

Comments
 (0)