@@ -139,6 +139,15 @@ class LinearStandardFormCompiler(object):
139139 description = 'Add slack variables and return `min cTx s.t. Ax == b`' ,
140140 ),
141141 )
142+ CONFIG .declare (
143+ 'mixed_form' ,
144+ ConfigValue (
145+ default = False ,
146+ domain = bool ,
147+ description = 'Return A in mixed form (the comparison operator is a '
148+ 'mix of <=, ==, and >=)' ,
149+ ),
150+ )
142151 CONFIG .declare (
143152 'show_section_timing' ,
144153 ConfigValue (
@@ -332,6 +341,9 @@ def write(self, model):
332341 # Tabulate constraints
333342 #
334343 slack_form = self .config .slack_form
344+ mixed_form = self .config .mixed_form
345+ if slack_form and mixed_form :
346+ raise ValueError ("cannot specify both slack_form and mixed_form" )
335347 rows = []
336348 rhs = []
337349 con_data = []
@@ -372,7 +384,30 @@ def write(self, model):
372384 f"model contains a trivially infeasible constraint, '{ con .name } '"
373385 )
374386
375- if slack_form :
387+ if mixed_form :
388+ N = len (repn .linear )
389+ _data = np .fromiter (repn .linear .values (), float , N )
390+ _index = np .fromiter (map (var_order .__getitem__ , repn .linear ), float , N )
391+ if ub == lb :
392+ rows .append (RowEntry (con , 0 ))
393+ rhs .append (ub - offset )
394+ con_data .append (_data )
395+ con_index .append (_index )
396+ con_index_ptr .append (con_index_ptr [- 1 ] + N )
397+ else :
398+ if ub is not None :
399+ rows .append (RowEntry (con , 1 ))
400+ rhs .append (ub - offset )
401+ con_data .append (_data )
402+ con_index .append (_index )
403+ con_index_ptr .append (con_index_ptr [- 1 ] + N )
404+ if lb is not None :
405+ rows .append (RowEntry (con , - 1 ))
406+ rhs .append (lb - offset )
407+ con_data .append (_data )
408+ con_index .append (_index )
409+ con_index_ptr .append (con_index_ptr [- 1 ] + N )
410+ elif slack_form :
376411 _data = list (repn .linear .values ())
377412 _index = list (map (var_order .__getitem__ , repn .linear ))
378413 if lb == ub : # TODO: add tolerance?
0 commit comments