Changeset 3082


Ignore:
Timestamp:
Oct 11, 2010 11:24:45 PM (11 years ago)
Author:
jwatson
Message:

Restructured LP writer to print a single term per line, for two reasons. First, Gurobi does not like LP files that are broken based on an arbitrary column width (e.g., which might yield lines ending in a "+"). Second, the performance of the textwrap to enforce a particular column width was terrible; that performance bottleneck is now eliminated.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • coopr.pyomo/trunk/coopr/pyomo/io/cpxlp.py

    r3013 r3082  
    1414
    1515import math
    16 import textwrap
    1716
    1817from coopr.opt import ProblemFormat
     
    2928
    3029def convert_name(namestr):
     30   
    3131    return namestr.replace('[','(').replace(']',')')
    3232
     
    3838
    3939    def __init__(self):
     40       
    4041        AbstractProblemWriter.__init__(self,ProblemFormat.cpxlp)
    41 
    42         tw_options = {
    43           'subsequent_indent' : '  ',  # default: empty string
    44           'break_long_words'  : False, # default: True
    45           'width'             : 80,    # 80 wide: more readable on screen
    46         }
    47         self.wrapper = textwrap.TextWrapper( **tw_options )
    48           # used to enforce CPlex's arbitrary 510 line limit
    4942
    5043        # temporarily placing attributes used in extensive-form writing
     
    7669
    7770    def __call__(self, model, filename):
     71       
    7872        if filename is None:
    7973           filename = model.name + ".lp"
     
    8478
    8579    def _get_bound(self, exp):
     80       
    8681        if isinstance(exp,expr._IdentityExpression):
    8782           return self._get_bound(exp._args[0])
     
    9590    @staticmethod
    9691    def _collect_key ( a ):
     92       
    9793        return a[0]
    9894
     
    10096    @staticmethod
    10197    def _no_label_error ( var ):
     98       
    10299        msg  = "Unable to find label for variable '%s'.\n"                    \
    103100        'Possibly uninstantiated model.  Do any constraint or objective  '     \
     
    109106
    110107
    111     def _print_expr ( self, x, **kwargs ):
     108    def _print_expr ( self, x, OUTPUT, **kwargs ):
     109       
    112110        """
    113111        Return a expression as a string in LP format.
     
    130128        is_objective = kwargs.pop('is_objective', False)
    131129        print_offset = kwargs.pop('print_offset', False)
    132 
    133         output = list()
    134130
    135131        #
     
    154150                sign = '+'
    155151                if coef < 0: sign = '-'
    156                 output.append('%s%f' % (sign, math.fabs(coef)) )
    157                 output.append( name )
     152                print >>OUTPUT, '%s%f %s' % (sign, math.fabs(coef), name)
    158153
    159154        #
     
    200195            output.append( quad_output )
    201196
    202         #raise Exception
    203197        #
    204198        # Constant offset
     
    210204            sign = '+'
    211205            if offset < 0: sign = '-'
    212             output.append('%s%f' % (sign, math.fabs(offset)) )
    213             output.append('ONE_VAR_CONSTANT')
    214 
    215         expr = ' '.join( output ) # convert expression parts to a single str
    216 
    217         # finally, actually write expression, taking care to not break the
    218         # arbitrary 510 character line length limit of CPlex.
    219         #print >>OUTPUT, self.wrapper.fill( expr )
     206            print >>OUTPUT, '%s%f %s' % (sign, math.fabs(offset), 'ONE_VAR_CONSTANT')
     207
    220208        #
    221209        # Return constant offset
    222210        #
    223         return expr, offset
     211        return offset
    224212
    225213
    226214#    @deprecated
    227215    def _print_quadterm(self, x, is_minimizing, OUTPUT):
     216       
    228217        # The LP format doesn't allow for expression of constant terms in the
    229218        # objective.  A work-around involves tracking the sum of constant terms
     
    269258                        str(rho),
    270259                        convert_name(variable.label)
    271                       ),
     260                      )
    272261
    273262                      sign = ' -'
     
    298287
    299288    @staticmethod
    300     def printSOS(con, name, index=None):
     289    def printSOS(con, name, OUTPUT, index=None):
     290       
    301291        """
    302292        Returns the SOS constraint (as a string) associated with con.
     
    306296        con    The SOS constraint object
    307297        name   The name of the variable
     298        OUTPUT The output stream
    308299        index  [Optional] the index to pass to the sets indexing the variables.
    309300        """
     
    329320                varNames.append(varName + "(" + strX + ")")
    330321
    331         # We need to 'weight' each variable
    332         # For now we just increment a counter
    333         resultStr = ""
    334         for i in range(0, len(varNames)):
    335             resultStr += varNames[i] + ":" + str(i+1) + " "
    336 
    337322        conNameIndex = ""
    338323        if index is not None:
    339324            conNameIndex = str(index)
    340325
    341         # Print to CPLEX file
    342         line = str(name) + conNameIndex + ": S" + str(con.sos_level()) +      \
    343                ":: " + resultStr
    344         return line
    345 
     326        print >>OUTPUT, '%s%s: S%s::' % (name, conNameIndex, con.sos_level())
     327
     328        # We need to 'weight' each variable
     329        # For now we just increment a counter
     330        for i in range(0, len(varNames)):
     331            print >>OUTPUT, '%s:%f' % (varNames[i], i+1)
    346332
    347333    def _print_model_LP(self, model, OUTPUT):
     334
    348335        _obj = model.active_components(Objective)
    349336
     
    354341        #
    355342        if self._output_objectives is True:
     343           
    356344           printed_quadterm = False
    357345           if len(_obj) == 0:
     
    376364
    377365           for key in obj_keys:
     366
    378367                if is_constant(obj[key].repn):
    379368
     
    381370                           "with a placeholder to prevent solver failure.")
    382371                   
    383                     line = "obj: +0.0 ONE_VAR_CONSTANT\n"
    384                     print >>OUTPUT, self.wrapper.fill(line)
     372                    print >>OUTPUT, "obj: +0.0 ONE_VAR_CONSTANT"
    385373
    386374                    # Skip the remaining logic of the section
     
    403391                    raise ValueError, msg
    404392
    405                 expr, offset = self._print_expr( obj[key].repn,
    406                   print_offset=True, is_objective=True
    407                 )
    408 
    409                 line = 'obj: ' + expr + '\n'
    410                 print >>OUTPUT, self.wrapper.fill( line )
     393                print >>OUTPUT, "obj: "
     394
     395                offset = self._print_expr(obj[key].repn,
     396                                          OUTPUT,
     397                                          print_offset=True,
     398                                          is_objective=True)
    411399
    412400           if obj._quad_subexpr is not None:
    413401               self._print_quadterm(obj._quad_subexpr, (_obj[ _obj.keys()[0] ].sense == minimize), OUTPUT)
    414402               printed_quadterm = True
     403               
    415404           print >>OUTPUT, ""
    416405
     
    429418           # elements - these should probably be done in the form of
    430419           # "end_objective()" and "end_constraint()" helper methods.
    431            if True == self._output_objectives == self._output_variables:
     420           if self._output_objectives == self._output_variables == True:
    432421               print >>OUTPUT, "s.t."
     422               print >>OUTPUT, ""
    433423
    434424           CON = model.active_components(Constraint)
     
    485475                   prefix = C.model.name+"_"
    486476
    487                expr, offset = self._print_expr(C[cndx].repn)
    488477               con_name = convert_name(C._data[cndx].label)
    489                fmt = '%s%%s%s_: %s %%s %%s' % ( prefix, con_name, expr )
    490                con = list()
    491 
    492478               if C._data[cndx]._equality:
    493                    bound = C._data[cndx].lower
    494                    bound = str(self._get_bound(bound) - offset)
    495                    cfmt = fmt % ( 'c_e_', '=', bound )
    496                    con.append( cfmt )
     479                  print >>OUTPUT, '%sc_e_%s_:' % (prefix, con_name)
     480                  offset = self._print_expr(C[cndx].repn, OUTPUT)               
     481                  bound = C._data[cndx].lower
     482                  bound = str(self._get_bound(bound) - offset)
     483                  print >>OUTPUT, "=", bound
     484                  print >>OUTPUT, ""
    497485               else:
    498                     if C._data[cndx].lower is not None:
    499                         bound = C._data[cndx].lower
    500                         bound = str(self._get_bound(bound) - offset)
    501                         cfmt = fmt % ( 'c_l_', '>=', bound )
    502                         con.append( cfmt )
    503 
    504                     if C._data[cndx].upper is not None:
    505                         bound = C._data[cndx].upper
    506                         bound = str(self._get_bound(bound) - offset)
    507                         cfmt = fmt % ( 'c_u_', '<=', bound )
    508                         con.append( cfmt )
    509 
    510                for line in con:
    511                    print >>OUTPUT, self.wrapper.fill( line ) + '\n'
     486                  if C._data[cndx].lower is not None:
     487                     print >>OUTPUT, '%sc_l_%s_:' % (prefix, con_name)
     488                     offset = self._print_expr(C[cndx].repn, OUTPUT)                                   
     489                     bound = C._data[cndx].lower
     490                     bound = str(self._get_bound(bound) - offset)
     491                     print >>OUTPUT, ">=", bound
     492                     print >>OUTPUT, ""                     
     493                  if C._data[cndx].upper is not None:
     494                     print >>OUTPUT, '%sc_u_%s_:' % (prefix, con_name)
     495                     offset = self._print_expr(C[cndx].repn, OUTPUT)                                                         
     496                     bound = C._data[cndx].upper
     497                     bound = str(self._get_bound(bound) - offset)
     498                     print >>OUTPUT, "<=", bound
     499                     print >>OUTPUT, ""                                         
    512500
    513501           if not have_nontrivial:
     
    523511           if self._output_prefixes is True:
    524512              prefix = model.name + "_"
    525            print >>OUTPUT, '%sc_e_ONE_VAR_CONSTANT: %sONE_VAR_CONSTANT = '    \
    526                            '1.0\n' % (prefix, prefix)
     513           print >>OUTPUT, '%sc_e_ONE_VAR_ONSTANT: ' % prefix
     514           print >>OUTPUT, '%sONE_VAR_CONSTANT = 1.0' % prefix
     515           print >>OUTPUT, ""
    527516
    528517        #
     
    660649                    if None in masterIndex:
    661650                        # A single constraint
    662                         line = self.printSOS(con, name)
    663                         print >>OUTPUT, self.wrapper.fill( line )
     651                        self.printSOS(con, name, OUTPUT)
    664652                    else:
    665653                        # A series of indexed constraints
    666654                        for index in masterIndex:
    667                             line = self.printSOS(con, name, index)
    668                             print >>OUTPUT, self.wrapper.fill( line )
     655                            self.printSOS(con, name, OUTPUT, index)
    669656
    670657        #
    671658        # wrap-up
    672659        #
    673         if True == self._output_objectives == self._output_constraints:
     660        if self._output_objectives == self._output_constraints == True:
    674661           #
    675662           # End
Note: See TracChangeset for help on using the changeset viewer.