Changeset 5643 for coopr.plugins


Ignore:
Timestamp:
04/05/12 16:43:35 (2 years ago)
Author:
jwatson
Message:

More improvements to the Xpress plugin - mainly, proper processing of the solver options.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • coopr.plugins/trunk/coopr/plugins/solvers/XPRESS.py

    r5642 r5643  
    8989 
    9090    # 
    91     # XPRESS has a simple, easy-to-use warm-start capability. 
     91    # we haven't reached this point quite yet. 
    9292    # 
    9393    def warm_start_capable(self): 
    94         return True 
    95  
    96     # 
    97     # write a warm-start file in the XPRESS MST format. 
    98     # 
    99     def warm_start(self, instance): 
    100  
    101         def _error_labeler(obj): 
    102             raise KeyError( 
    103                 "XPRESS Warm Start Error: instance contains an object, %s, " 
    104                 "that is not found in the symbol map.  Does the instance " 
    105                 "match the provided symbol map?" % ( obj.name, )) 
    106  
    107         from coopr.pyomo.base import Var, VarStatus 
    108  
    109         doc = xml.dom.minidom.Document() 
    110         root_element = doc.createElement("XPRESSSolution") 
    111         root_element.setAttribute("version","1.0") 
    112         doc.appendChild(root_element) 
    113  
    114         # currently not populated. 
    115         header_element = doc.createElement("header") 
    116         # currently not populated. 
    117         quality_element = doc.createElement("quality") 
    118         # definitely populated! 
    119         variables_element = doc.createElement("variables") 
    120  
    121         root_element.appendChild(header_element) 
    122         root_element.appendChild(quality_element) 
    123         root_element.appendChild(variables_element) 
    124  
    125         # for each variable in the symbol_map, add a child to the 
    126         # variables element.  Both continuous and discrete are accepted 
    127         # (and required, depending on other options), according to the 
    128         # XPRESS manual.  Note, this assumes that the symbol_map matches 
    129         # the instance... 
    130         output_index = 0 
    131         for block in instance.all_blocks(): 
    132             for variable in block.active_components(Var).itervalues(): 
    133                 for index in variable: 
    134                     var = variable[index] 
    135                     if var.status == VarStatus.unused or var.value is None \ 
    136                             or var.fixed: 
    137                         continue 
    138                     name = self._symbol_map.getSymbol(var, _error_labeler) 
    139  
    140                     variable_element = doc.createElement("variable") 
    141                     variable_element.setAttribute("name", name) 
    142                     variable_element.setAttribute("index", str(output_index)) 
    143                     variable_element.setAttribute("value", str(var.value)) 
    144                     variables_element.appendChild(variable_element) 
    145                     output_index = output_index + 1 
    146  
    147         mst_file = open(self.warm_start_file_name,'w') 
    148         doc.writexml(mst_file, indent="    ", newl="\n") 
    149         mst_file.close() 
    150  
    151     # over-ride presolve to extract the warm-start keyword, if specified. 
    152     def _presolve(self, *args, **kwds): 
    153  
    154         # if the first argument is a string (representing a filename), 
    155         # then we don't have an instance => the solver is being applied 
    156         # to a file. 
    157         self.warm_start_solve = kwds.pop( 'warmstart', False ) 
    158  
    159         # the input argument can currently be one of two things: an instance or a filename. 
    160         # if a filename is provided and a warm-start is indicated, we go ahead and 
    161         # create the temporary file - assuming that the user has already, via some external 
    162         # mechanism, invoked warm_start() with a instance to create the warm start file. 
    163         if (self.warm_start_solve is True) and (isinstance(args[0],basestring) is True): 
    164             pass # we assume the user knows what they are doing... 
    165         elif (self.warm_start_solve is True) and (isinstance(args[0],basestring) is False) and (args[0].has_discrete_variables() is True): 
    166            # assign the name of the warm start file *before* calling the base class 
    167            # presolve - the base class method ends up creating the command line, 
    168            # and the warm start file-name is (obviously) needed there. 
    169            self.warm_start_file_name = pyutilib.services.TempfileManager.create_tempfile(suffix = '.xpress.mst') 
    170         else: 
    171            self.warm_start_file_name = None 
    172  
    173         # let the base class handle any remaining keywords/actions. 
    174         ILMLicensedSystemCallSolver._presolve(self, *args, **kwds) 
    175  
    176         # NB: we must let the base class presolve run first so that the 
    177         # symbol_map is actually constructed! 
    178  
    179         if (len(args) > 0) and (isinstance(args[0],basestring) is False): 
    180  
    181             # write the warm-start file - currently only supports MIPs. 
    182             # we only know how to deal with a single problem instance. 
    183             if self.warm_start_solve is True: 
    184  
    185                 if len(args) != 1: 
    186                     raise ValueError( 
    187                         "XPRESS _presolve method can only handle a single " 
    188                         "problem instance - %s were supplied" % (len(args),)) 
    189  
    190                 if args[0].has_discrete_variables() is True: 
    191                     start_time = time.time() 
    192                     self.warm_start(args[0]) 
    193                     end_time = time.time() 
    194                     if self._report_timing is True: 
    195                         print "Warm start write time= %.2f seconds" % (end_time-start_time) 
     94         
     95        return False 
    19696 
    19797    def executable(self): 
     
    230130        # 
    231131        script = "" 
     132         
    232133        script = "setlogfile %s\n" % ( self.log_file, ) 
     134         
    233135        if self._timelimit is not None and self._timelimit > 0.0: 
    234             script += "set timelimit %s\n" % ( self._timelimit, ) 
     136            script += "maxtime=%s\n" % ( self._timelimit, ) 
     137             
    235138        if (self.options.mipgap is not None) and (self.options.mipgap > 0.0): 
    236             script += "set mip tolerances mipgap %s\n" % ( self.options.mipgap, ) 
    237         for key in self.options: 
    238             if key == 'relax_integrality' or key == 'mipgap': 
    239                 continue 
    240             elif isinstance(self.options[key],basestring) and ' ' in self.options[key]: 
    241                 opt = " ".join(key.split('_'))+" "+str(self.options[key]) 
    242             else: 
    243                 opt = " ".join(key.split('_'))+" "+str(self.options[key]) 
    244             script += "set %s\n" % ( opt, ) 
     139            script += "miprelstop=%s\n" % ( self.options.mipgap, ) 
     140             
     141        for option_name in self.options: 
     142            script += "%s=%s" % ( option_name, self.options[option_name] )                 
     143 
    245144        script += "readprob %s\n" % ( problem_files[0], ) 
    246145 
     
    249148        if (self.warm_start_solve is True) and (self.warm_start_file_name is not None): 
    250149            script += "read %s\n" % ( self.warm_start_file_name, ) 
    251  
    252         # TBD - need to deal with mipgap 
    253  
    254         # TBD - haven't dealt with the following yet... 
    255         if 'relax_integrality' in self.options: 
    256             script += "change problem lp\n" 
    257150 
    258151        script += "lpoptimize\n" # doesn't seem to be a global solve command for mip versus lp solves 
     
    265158        # c: outputs the costs for variables, slacks for constraints. 
    266159        # d: outputs the reduced costs for columns, duals for constraints 
    267         # TBD: We'll have to modify the flags based on mip/lp 
    268160        script += "writesol %s -pnatcd\n" % ( self.soln_file, ) 
    269161 
     
    297189 
    298190    def process_logfile(self): 
    299         """ 
    300         Process logfile 
    301         """ 
    302191 
    303192        results = SolverResults() 
    304193        results.problem.number_of_variables = None 
    305194        results.problem.number_of_nonzeros = None 
    306         # 
    307         # Process logfile 
    308         # 
    309         OUTPUT = open(self.log_file) 
    310         output = "".join(OUTPUT.readlines()) 
    311         OUTPUT.close() 
    312         # 
    313         # It is generally useful to know the XPRESS version number for logfile parsing. 
    314         # 
    315         xpress_version = None 
    316  
    317         # 
    318         # Parse logfile lines 
    319         # 
    320         for line in output.split("\n"): 
     195 
     196        log_file = open(self.log_file) 
     197        log_file_contents = "".join(log_file.readlines()) 
     198        log_file.close() 
     199 
     200        return 
     201         
     202        for line in log_file_contents.split("\n"): 
    321203            tokens = re.split('[ \t]+',line.strip()) 
     204 
    322205            if len(tokens) > 3 and tokens[0] == "XPRESS" and tokens[1] == "Error": 
    323206            # IMPT: See below - cplex can generate an error line and then terminate fine, e.g., in XPRESS 12.1. 
Note: See TracChangeset for help on using the changeset viewer.