Skip to content

Commit 2058881

Browse files
Kr/feature/reveal lp variable maps1 (#21)
* Upgrading SymbolicMath.go * Updated all function signatures to include maps to the new variables that we care about * Fixed all tests * Introducing new test to check the mapping from original variables to positive variables * Added test for purely positive and purely negative variables getting transformed into simple expressions. * Hiding a test for the simplified output of one polynomial
1 parent 6853593 commit 2058881

4 files changed

Lines changed: 185 additions & 44 deletions

File tree

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.5
9+
require github.com/MatProGo-dev/SymbolicMath.go v0.2.6

go.sum

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1 h1:SIj6oFJgavWtArs8toeHCPfxOefGMplWSkNvlR9P2Ac=
2-
github.com/MatProGo-dev/SymbolicMath.go v0.2.4-1/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
3-
github.com/MatProGo-dev/SymbolicMath.go v0.2.4 h1:SxvgOJBpx9H6ZHISyF3A79gOd1pHJd8Nywrqf4sJZTs=
4-
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=
1+
github.com/MatProGo-dev/SymbolicMath.go v0.2.6 h1:0THkOKIjdjadIb9MHIUflk08U7tv17KvtQPOP3eMOfk=
2+
github.com/MatProGo-dev/SymbolicMath.go v0.2.6/go.mod h1:tW8thj4pkaTV9lFNU3OCKmwQ3mZ2Eim6S4JpHRDfRvU=
73
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
84
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=

problem/optimization_problem.go

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ Description:
580580
Then, we replace every instance of the original variable with the difference
581581
of the two new variables (x = x_+ - x_-).
582582
*/
583-
func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*OptimizationProblem, error) {
583+
func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*OptimizationProblem, map[symbolic.Variable]symbolic.Expression, error) {
584584
// Setup
585585
newProblem := NewProblem(op.Name + " (All Positive Variables)")
586586
epsMagic := 1e-8 // TODO(Kwesi): Make this a parameter OR a constant in the package.
@@ -620,7 +620,7 @@ func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*Optimizatio
620620
}
621621

622622
// Set the original variable to be the difference of the two new variables
623-
mapFromOriginalVariablesToNewExpressions[xII] = expressionForReplacement
623+
mapFromOriginalVariablesToNewExpressions[xII] = expressionForReplacement.AsSimplifiedExpression()
624624
}
625625

626626
// Now, let's create the new constraints by replacing the variables in the
@@ -643,7 +643,7 @@ func (op *OptimizationProblem) ToProblemWithAllPositiveVariables() (*Optimizatio
643643
op.Objective.Sense,
644644
)
645645

646-
return newProblem, nil
646+
return newProblem, mapFromOriginalVariablesToNewExpressions, nil
647647
}
648648

649649
/*
@@ -668,22 +668,22 @@ Note:
668668
into a set of scalar constraints. Thus, the number of constraints in your problem may
669669
"seem" to change.
670670
*/
671-
func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem, []symbolic.Variable, error) {
671+
func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem, []symbolic.Variable, map[symbolic.Variable]symbolic.Expression, error) {
672672
// Input Processing
673673
err := problemIn.Check()
674674
if err != nil {
675-
return nil, nil, problemIn.MakeNotWellDefinedError()
675+
return nil, nil, nil, problemIn.MakeNotWellDefinedError()
676676
}
677677

678678
// Check if the problem is linear
679679
if !problemIn.IsLinear() {
680-
return nil, nil, problemIn.CheckIfLinear()
680+
return nil, nil, nil, problemIn.CheckIfLinear()
681681
}
682682

683683
// Change the problem so that it is written in terms of strictly positive variables
684-
problemWithAllPositiveVariables, err := problemIn.ToProblemWithAllPositiveVariables() // Note: This method may change the number of variables and constraints in the problem.
684+
problemWithAllPositiveVariables, originalVariablesToPositiveVariableExpressions, err := problemIn.ToProblemWithAllPositiveVariables() // Note: This method may change the number of variables and constraints in the problem.
685685
if err != nil {
686-
return nil, nil, err
686+
return nil, nil, nil, err
687687
}
688688

689689
// Create a new problem
@@ -692,11 +692,11 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
692692
)
693693

694694
// Add all variables to the new problem
695-
mapFromInToNewVariables := make(map[symbolic.Variable]symbolic.Expression)
695+
mapFromPositiveToNewVariables := make(map[symbolic.Variable]symbolic.Expression)
696696
for _, varII := range problemWithAllPositiveVariables.Variables {
697697
problemInStandardForm.AddVariable()
698698
nVariables := len(problemInStandardForm.Variables)
699-
mapFromInToNewVariables[varII] = problemInStandardForm.Variables[nVariables-1]
699+
mapFromPositiveToNewVariables[varII] = problemInStandardForm.Variables[nVariables-1]
700700
}
701701

702702
// Add all constraints to the new problem
@@ -706,10 +706,10 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
706706
// Create a new expression by substituting the variables according
707707
// to the map we created above
708708
oldLHS := constraint.Left()
709-
newLHS := oldLHS.SubstituteAccordingTo(mapFromInToNewVariables)
709+
newLHS := oldLHS.SubstituteAccordingTo(mapFromPositiveToNewVariables)
710710

711711
oldRHS := constraint.Right()
712-
newRHS := oldRHS.SubstituteAccordingTo(mapFromInToNewVariables)
712+
newRHS := oldRHS.SubstituteAccordingTo(mapFromPositiveToNewVariables)
713713

714714
switch constraint.ConstrSense() {
715715
case symbolic.SenseEqual:
@@ -742,7 +742,7 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
742742
newLHS = newLHS.Plus(problemInStandardForm.Variables[nVariables-1])
743743

744744
default:
745-
return nil, nil, fmt.Errorf(
745+
return nil, nil, nil, fmt.Errorf(
746746
"Unknown constraint sense: " + constraint.ConstrSense().String(),
747747
)
748748
}
@@ -762,7 +762,7 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
762762
// Now, let's create the new objective function by substituting the variables
763763
// according to the map we created above
764764
newObjectiveExpression := problemWithAllPositiveVariables.Objective.Expression.SubstituteAccordingTo(
765-
mapFromInToNewVariables,
765+
mapFromPositiveToNewVariables,
766766
)
767767
problemInStandardForm.SetObjective(
768768
newObjectiveExpression,
@@ -772,8 +772,16 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
772772
// Simplify The Constraints If Possible
773773
problemInStandardForm.SimplifyConstraints()
774774

775+
// Create the map from the original variables to the new variables
776+
// by composing the two maps we created above
777+
originalVariablesToNewVariables := make(map[symbolic.Variable]symbolic.Expression)
778+
for originalVar, positiveVarExpr := range originalVariablesToPositiveVariableExpressions {
779+
newVarExpr := positiveVarExpr.SubstituteAccordingTo(mapFromPositiveToNewVariables)
780+
originalVariablesToNewVariables[originalVar] = newVarExpr
781+
}
782+
775783
// Return the new problem and the slack variables
776-
return problemInStandardForm, slackVariables, nil
784+
return problemInStandardForm, slackVariables, originalVariablesToNewVariables, nil
777785
}
778786

779787
/*
@@ -795,17 +803,17 @@ Description:
795803
This method also returns the slack variables (i.e., the variables that
796804
are added to the problem to convert the inequalities into equalities).
797805
*/
798-
func (problemIn *OptimizationProblem) ToLPStandardForm2() (*OptimizationProblem, []symbolic.Variable, error) {
806+
func (problemIn *OptimizationProblem) ToLPStandardForm2() (*OptimizationProblem, []symbolic.Variable, map[symbolic.Variable]symbolic.Expression, error) {
799807
// Input Processing
800808
err := problemIn.Check()
801809
if err != nil {
802-
return nil, nil, problemIn.MakeNotWellDefinedError()
810+
return nil, nil, nil, problemIn.MakeNotWellDefinedError()
803811
}
804812

805813
// Use the existing method to convert to standard form 1
806-
problemInStandardForm, slackVariables, err := problemIn.ToLPStandardForm1()
814+
problemInStandardForm, slackVariables, originalVariablesToNewVariables, err := problemIn.ToLPStandardForm1()
807815
if err != nil {
808-
return nil, nil, err
816+
return nil, nil, nil, err
809817
}
810818

811819
// Modify the objective function to be a maximization problem,
@@ -816,12 +824,12 @@ func (problemIn *OptimizationProblem) ToLPStandardForm2() (*OptimizationProblem,
816824
newObjectiveExpression := problemInStandardForm.Objective.Expression.Multiply(-1.0)
817825
err = problemInStandardForm.SetObjective(newObjectiveExpression, SenseMaximize)
818826
if err != nil {
819-
return nil, nil, fmt.Errorf("there was a problem setting the new objective function: %v", err)
827+
return nil, nil, originalVariablesToNewVariables, fmt.Errorf("there was a problem setting the new objective function: %v", err)
820828
}
821829
}
822830

823831
// Return the new problem and the slack variables
824-
return problemInStandardForm, slackVariables, nil
832+
return problemInStandardForm, slackVariables, originalVariablesToNewVariables, nil
825833
}
826834

827835
/*

0 commit comments

Comments
 (0)