@@ -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/*
592572ToProblemWithAllPositiveVariables
593573Description:
@@ -602,6 +582,7 @@ Description:
602582func (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
@@ -697,8 +693,9 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
697693 }
698694
699695 // Add all constraints to the new problem
696+ problemWithPositivesAndCleanedConstraints := problemWithAllPositiveVariables .WithAllPositiveVariableConstraintsRemoved ()
700697 slackVariables := []symbolic.Variable {}
701- for _ , constraint := range problemWithAllPositiveVariables .Constraints {
698+ for _ , constraint := range problemWithPositivesAndCleanedConstraints .Constraints {
702699 // Create a new expression by substituting the variables according
703700 // to the map we created above
704701 oldLHS := constraint .Left ()
@@ -827,12 +824,70 @@ func (problemIn *OptimizationProblem) ToLPStandardForm1() (*OptimizationProblem,
827824 problemWithAllPositiveVariables .Objective .Sense ,
828825 )
829826
830- // fmt.Printf("The slack variables are: %v\n", slackVariables)
827+ // Simplify The Constraints If Possible
828+ problemInStandardForm .SimplifyConstraints ()
831829
832830 // Return the new problem and the slack variables
833831 return problemInStandardForm , slackVariables , nil
834832}
835833
834+ /*
835+ WithAllPositiveVariableConstraintsRemoved
836+ Description:
837+
838+ Returns a new optimization problem that is the same as the original problem
839+ but with all constraints of the following form removed:
840+ x >= 0
841+ 0 <= x
842+ Where x is a variable in the problem.
843+ This is useful for removing redundant constraints that are already implied by the variable bounds.
844+ */
845+ func (op * OptimizationProblem ) WithAllPositiveVariableConstraintsRemoved () * OptimizationProblem {
846+ // Setup
847+ newProblem := NewProblem (op .Name )
848+
849+ // Copy the variables
850+ for _ , variable := range op .Variables {
851+ newProblem .Variables = append (newProblem .Variables , variable )
852+ }
853+
854+ // Copy the constraints
855+ for _ , constraintII := range op .Constraints {
856+ // Check if the constraint is a x >= 0 constraint
857+ if symbolic .SenseGreaterThanEqual == constraintII .ConstrSense () {
858+ lhsContains1Variable := len (constraintII .Left ().Variables ()) == 1
859+ rhs , rhsIsConstant := constraintII .Right ().(symbolic.K )
860+ if lhsContains1Variable && rhsIsConstant {
861+ if float64 (rhs ) == 0.0 {
862+ // If the constraint is of the form x >= 0, we can remove it
863+ continue
864+ }
865+ }
866+ }
867+
868+ // Check if the constraint is a 0 <= x constraint
869+ if symbolic .SenseLessThanEqual == constraintII .ConstrSense () {
870+ rhsContains1Variable := len (constraintII .Left ().Variables ()) == 1
871+ lhs , lhsIsConstant := constraintII .Right ().(symbolic.K )
872+ if rhsContains1Variable && lhsIsConstant {
873+ if float64 (lhs ) == 0.0 {
874+ // If the constraint is of the form 0 <= x, we can remove it
875+ continue
876+ }
877+ }
878+ }
879+
880+ // Otherwise, we can keep the constraint
881+ newProblem .Constraints = append (newProblem .Constraints , constraintII )
882+ }
883+
884+ // Copy the objective
885+ newProblem .Objective = op .Objective
886+
887+ // Return the new problem
888+ return newProblem
889+ }
890+
836891/*
837892CheckIfLinear
838893Description:
0 commit comments