Skip to content

Commit bbbe4d9

Browse files
committed
Creating a bit of logic to avoid creating extra variables if possible
1 parent 250db11 commit bbbe4d9

2 files changed

Lines changed: 84 additions & 30 deletions

File tree

problem/optimization_problem.go

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -568,26 +568,6 @@ func (op *OptimizationProblem) LinearEqualityConstraintMatrices() (symbolic.KMat
568568
return COut2, dOut2, nil
569569
}
570570

571-
// func (op *OptimizationProblem) Simplify() OptimizationProblem {
572-
// // Create a new optimization problem
573-
// newProblem := NewProblem(op.Name + " (Simplified)")
574-
575-
// // Add all variables to the new problem
576-
// for _, variable := range op.Variables {
577-
// newProblem.Variables = append(newProblem.Variables, variable)
578-
// }
579-
580-
// // Add all constraints to the new problem
581-
// for _, constraint := range op.Constraints {
582-
// newProblem.Constraints = append(newProblem.Constraints, constraint)
583-
// }
584-
585-
// // Set the objective of the new problem
586-
// newProblem.Objective = op.Objective
587-
588-
// return newProblem
589-
// }
590-
591571
/*
592572
ToProblemWithAllPositiveVariables
593573
Description:
@@ -602,6 +582,7 @@ Description:
602582
func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*OptimizationProblem, error) {
603583
// Setup
604584
newProblem := NewProblem(op.Name + " (All Positive Variables)")
585+
epsMagic := 1e-8 // TODO(Kwesi): Make this a parameter OR a constant in the package.
605586

606587
// For each variable, let's create two new variables
607588
// and set the original variable to be the difference of the two
@@ -610,20 +591,35 @@ func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*Optimizatio
610591
// Setup
611592
xII := op.Variables[ii]
612593

594+
// Expression for the positive and negative parts
595+
var expressionForReplacement symbolic.Expression = symbolic.K(0.0)
596+
613597
// Create the two new variables
614-
newProblem.AddVariableClassic(0.0, symbolic.Infinity.Constant(), symbolic.Continuous)
615-
nVariables := len(newProblem.Variables)
616-
newProblem.Variables[nVariables-1].Name = xII.Name + " (+)"
617-
variablePositivePart := newProblem.Variables[nVariables-1]
598+
// - Positive Part
599+
positivePartExists := xII.Upper >= 0
600+
positivePartExists = positivePartExists && !ConstraintIsRedundantGivenOthers(xII.LessEq(0.0-epsMagic), op.Constraints)
601+
if positivePartExists {
602+
newProblem.AddVariableClassic(0.0, symbolic.Infinity.Constant(), symbolic.Continuous)
603+
nVariables := len(newProblem.Variables)
604+
newProblem.Variables[nVariables-1].Name = xII.Name + " (+)"
605+
variablePositivePart := newProblem.Variables[nVariables-1]
606+
expressionForReplacement = expressionForReplacement.Plus(variablePositivePart)
607+
}
618608

619-
newProblem.AddVariableClassic(0.0, symbolic.Infinity.Constant(), symbolic.Continuous)
620-
nVariables = len(newProblem.Variables)
621-
newProblem.Variables[nVariables-1].Name = xII.Name + " (-)"
622-
variableNegativePart := newProblem.Variables[nVariables-1]
609+
// - Negative Part
610+
negativePartExists := xII.Lower < 0
611+
negativePartExists = negativePartExists && !ConstraintIsRedundantGivenOthers(xII.GreaterEq(0.0), op.Constraints)
612+
if negativePartExists {
613+
newProblem.AddVariableClassic(0.0, symbolic.Infinity.Constant(), symbolic.Continuous)
614+
nVariables := len(newProblem.Variables)
615+
newProblem.Variables[nVariables-1].Name = xII.Name + " (-)"
616+
variableNegativePart := newProblem.Variables[nVariables-1]
617+
618+
expressionForReplacement = expressionForReplacement.Minus(variableNegativePart)
619+
}
623620

624621
// Set the original variable to be the difference of the two new variables
625-
mapFromOriginalVariablesToNewExpressions[xII] =
626-
variablePositivePart.Minus(variableNegativePart)
622+
mapFromOriginalVariablesToNewExpressions[xII] = expressionForReplacement
627623
}
628624

629625
// Now, let's create the new constraints by replacing the variables in the
@@ -688,6 +684,8 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
688684
problemIn.Name + " (In Standard Form)",
689685
)
690686

687+
// Copy over each of the
688+
691689
// Add all variables to the new problem
692690
mapFromInToNewVariables := make(map[symbolic.Variable]symbolic.Expression)
693691
for _, varII := range problemWithAllPositiveVariables.Variables {

testing/problem/optimization_problem_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,62 @@ func TestOptimizationProblem_ToProblemWithAllPositiveVariables1(t *testing.T) {
20172017
}
20182018
}
20192019

2020+
/*
2021+
TestOptimizationProblem_ToProblemWithAllPositiveVariables2
2022+
Description:
2023+
2024+
Tests the ToProblemWithAllPositiveVariables function with a simple problem
2025+
that has:
2026+
- a constant objective
2027+
- 2 variables,
2028+
- and two scalar linear inequality constraints.
2029+
One of the variables is purely positive, while the other is purely negative.
2030+
The result should be a problem with 2 variables and 2 constraints.
2031+
*/
2032+
func TestOptimizationProblem_ToProblemWithAllPositiveVariables2(t *testing.T) {
2033+
// Constants
2034+
p1 := problem.NewProblem("TestOptimizationProblem_ToProblemWithAllPositiveVariables2")
2035+
vv1 := p1.AddVariableVector(2)
2036+
// Add constraints
2037+
c1 := vv1.AtVec(0).GreaterEq(1.0)
2038+
c2 := vv1.AtVec(1).LessEq(-2.0)
2039+
2040+
p1.Constraints = append(p1.Constraints, c1)
2041+
p1.Constraints = append(p1.Constraints, c2)
2042+
2043+
// Create good objective
2044+
p1.Objective = *problem.NewObjective(
2045+
symbolic.K(3.14),
2046+
problem.SenseMaximize,
2047+
)
2048+
2049+
// Algorithm
2050+
p2, err := p1.ToProblemWithAllPositiveVariables()
2051+
if err != nil {
2052+
t.Errorf("unexpected error: %v", err)
2053+
}
2054+
2055+
// Check that the number of variables is as expected.
2056+
if len(p2.Variables) != 2 {
2057+
t.Errorf("expected the number of variables to be %v; received %v",
2058+
2, len(p2.Variables))
2059+
}
2060+
2061+
// Check that the number of constraints is as expected.
2062+
if len(p2.Constraints) != 2 {
2063+
t.Errorf("expected the number of constraints to be %v; received %v",
2064+
2, len(p2.Constraints))
2065+
}
2066+
2067+
// Verify that the new constraints contain two variables in the left hand side
2068+
for _, c := range p2.Constraints {
2069+
if len(c.Left().Variables()) != 1 {
2070+
t.Errorf("expected the number of variables in the left hand side to be %v; received %v",
2071+
1, len(c.Left().Variables()))
2072+
}
2073+
}
2074+
}
2075+
20202076
/*
20212077
TestOptimizationProblem_ToLPStandardForm1_1
20222078
Description:

0 commit comments

Comments
 (0)