@@ -750,47 +750,59 @@ def copy_cone(cone, cone_size: int = None):
750750
751751
752752def _reduce_convex_constraints (A , b , cones , cone_sizes ):
753- # condense the problem
754- # identify variables that are zero
755- zero_constraints = []
756753 zero_is = []
757754 rows_seen = 0
758-
759- for i , cone in enumerate (cones ):
755+ for i , cone in enumerate (cones ): # identify variables that are zero
760756 if isinstance (cone , cb .ZeroConeT ):
761757 for j in range (cone_sizes [i ]):
762758 if np .count_nonzero (A [rows_seen + j , :]) == 1 and b [rows_seen + j ] == 0 :
763- zero_constraints .append (rows_seen + j )
764759 zero_is .append (np .nonzero (A [rows_seen + j , :])[0 ][0 ])
765760 rows_seen += cone_sizes [i ]
761+ A_reduced = np .delete (A , zero_is , axis = 1 ) # delete columns that are zero
766762
767- # remove variables that are zero
768- A_reduced = np .delete (A , zero_constraints , axis = 0 )
769- A_reduced = np .delete (A_reduced , zero_is , axis = 1 )
770- b_reduced = np .delete (b , zero_constraints )
771- rows_seen = 0
772- zero_rows = []
763+ constraints_to_delete = []
773764 new_cones = []
774765 new_cone_sizes = []
775- for i in range (len (cones )):
776- cone_size = cone_sizes [i ]
777- new_cones .append (copy_cone (cones [i ], cone_sizes [i ]))
778- if isinstance (cones [i ], cb .ZeroConeT ):
766+ rows_seen = 0
767+ for i , cone in enumerate (cones ): # identify rows that are zero in linear cones
768+ new_cone_size = cone_sizes [i ]
769+ new_cone = copy_cone (cone , cone_sizes [i ])
770+ if isinstance (cone , cb .ZeroConeT ):
779771 for j in range (cone_sizes [i ]):
780- if rows_seen + j in zero_constraints :
781- cone_size -= 1
782- new_cones [i ] = cb .ZeroConeT (cone_size )
772+ if np .count_nonzero (A_reduced [rows_seen + j , :]) == 0 and b [rows_seen + j ] == 0 :
773+ constraints_to_delete .append (rows_seen + j )
774+ new_cone_size -= 1
775+ new_cone = cb .ZeroConeT (new_cone_size )
776+ elif isinstance (cone , cb .NonnegativeConeT ):
777+ for j in range (cone_sizes [i ]):
778+ if np .count_nonzero (A_reduced [rows_seen + j , :]) == 0 and b [rows_seen + j ] == 0 :
779+ constraints_to_delete .append (rows_seen + j )
780+ new_cone_size -= 1
781+ new_cone = cb .NonnegativeConeT (new_cone_size )
782+ new_cones .append (new_cone )
783+ new_cone_sizes .append (new_cone_size )
783784 rows_seen += cone_sizes [i ]
784- new_cone_sizes .append (cone_size )
785+ A_reduced = np .delete (A_reduced , constraints_to_delete , axis = 0 ) # delete rows that are zero
786+ b_reduced = np .delete (b , constraints_to_delete )
787+
788+ assert A .shape [0 ] >= A_reduced .shape [0 ], "Reduced A has more rows than original A"
785789
786790 return A_reduced , b_reduced , new_cones , new_cone_sizes , zero_is
787791
788792
789793def _reduce_convex_problem (A , b , cones , cone_sizes , q ):
794+ orig_var_ct = A .shape [1 ]
790795 A_reduced , b_reduced , new_cones , new_cone_sizes , zero_is = _reduce_convex_constraints (A , b , cones , cone_sizes )
796+ vars_kept = [i for i in range (orig_var_ct ) if i not in zero_is ]
797+ while A_reduced .shape [0 ] < A .shape [0 ]: # keep reducing until no more constraints can be removed
798+ A , b , cones , cone_sizes = A_reduced , b_reduced , new_cones , new_cone_sizes
799+ A_reduced , b_reduced , new_cones , new_cone_sizes , zero_is = _reduce_convex_constraints (A , b , cones , cone_sizes )
800+ vars_kept = [x for i , x in enumerate (vars_kept ) if i not in zero_is ]
801+
802+ vars_removed = [i for i in range (orig_var_ct ) if i not in vars_kept ]
791803 # remove variables that are zero from q
792- q_reduced = np .delete (q , zero_is )
793- return A_reduced , b_reduced , new_cones , new_cone_sizes , q_reduced , zero_is
804+ q_reduced = np .delete (q , vars_removed )
805+ return A_reduced , b_reduced , new_cones , new_cone_sizes , q_reduced , vars_removed
794806
795807
796808def _find_solution_unrounded (
0 commit comments