Changeset 2903
 Timestamp:
 Aug 3, 2010 12:58:43 PM (9 years ago)
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

coopr.plugins/trunk/coopr/plugins/mip/GLPK.py
r2902 r2903 39 39 # 40 40 self._valid_problem_formats = [ 41 ProblemFormat.mod, ProblemFormat.cpxlp, ProblemFormat.mps ]41 ProblemFormat.mod, ProblemFormat.cpxlp, ProblemFormat.mps ] 42 42 self._valid_result_formats = { 43 ProblemFormat.mod : ResultsFormat.soln,44 ProblemFormat.cpxlp : ResultsFormat.soln,45 ProblemFormat.mps : ResultsFormat.soln,43 ProblemFormat.mod : ResultsFormat.soln, 44 ProblemFormat.cpxlp : ResultsFormat.soln, 45 ProblemFormat.mps : ResultsFormat.soln, 46 46 } 47 47 … … 51 51 self._capabilities.integer = True 52 52 53 53 54 def executable(self): 54 55 executable = registered_executable('glpsol') 55 56 if executable is None: 56 msg = "Could not locate the 'glpsol' executable, which is " \57 msg = "Could not locate the 'glpsol' executable, which is " \ 57 58 "required for solver '%s'" 58 PluginGlobals.env().log.error( msg % self.name)59 PluginGlobals.env().log.error( msg % self.name ) 59 60 self.enable = False 60 61 return None … … 62 63 return executable.get_path() 63 64 64 def create_command_line(self, executable, problem_files): 65 66 def create_command_line(self,executable,problem_files): 65 67 # 66 68 # Define log file 67 69 # 68 70 if self.log_file is None: 69 self.log_file = TempfileManager.create_tempfile(suffix='.glpk.log')71 self.log_file = TempfileManager.create_tempfile( suffix='.glpk.log') 70 72 71 73 # … … 74 76 if self.soln_file is None: 75 77 self.soln_file = \ 76 78 TempfileManager.create_tempfile(suffix='.glpk.soln') 77 79 78 80 # 79 81 # Define results file 80 82 # 81 if self._results_format is None \83 if self._results_format is None \ 82 84 or self._results_format == ResultsFormat.soln: 83 85 self.results_file = self.soln_file … … 88 90 cmd = [self._timer, '"%s"' % executable] 89 91 for key in self.options: 90 if isinstance(self.options[key], basestring)\91 92 cmd.append('%s "%s"' % (key, str(self.options[key])) )92 if isinstance(self.options[key],basestring) \ 93 and ' ' in self.options[key]: 94 cmd.append('%s "%s"' % (key, str(self.options[key])) ) 93 95 else: 94 cmd.append('%s %s' % (key, str(self.options[key])) )96 cmd.append('%s %s' % (key, str(self.options[key])) ) 95 97 96 98 if self._timelimit is not None and self._timelimit > 0.0: 97 cmd.append('tmlim ' + str(self._timelimit) )99 cmd.append('tmlim ' + str(self._timelimit) ) 98 100 99 101 if (self.mipgap is not None) and (self.mipgap > 0.0): 100 cmd.append('mipgap ' + str(self.mipgap) )101 cmd.append('output ' + self.soln_file )102 cmd.append('mipgap ' + str(self.mipgap) ) 103 cmd.append('output ' + self.soln_file ) 102 104 103 105 if self._problem_format == ProblemFormat.cpxlp: 104 cmd.append('cpxlp ' + problem_files[0] )106 cmd.append('cpxlp ' + problem_files[0] ) 105 107 elif self._problem_format == ProblemFormat.mps: 106 cmd.append('freemps ' + problem_files[0] )108 cmd.append('freemps ' + problem_files[0] ) 107 109 elif self._problem_format == ProblemFormat.mod: 108 cmd.append('math ' + problem_files[0] )109 cmd.append('data "%s"' % fname for fname in problem_files[1:] )110 111 cmd = ' '.join( cmd)112 113 return Bunch( cmd=cmd, log_file=self.log_file, env=None)110 cmd.append('math ' + problem_files[0] ) 111 cmd.append('data "%s"' % fname for fname in problem_files[1:] ) 112 113 cmd = ' '.join( cmd ) 114 115 return Bunch( cmd=cmd, log_file=self.log_file, env=None ) 114 116 115 117 def process_logfile(self): … … 121 123 # Initial values 122 124 # 123 # results.solver.statistics.branch_and_bound. 124 # number_of_created_subproblems=0 125 # results.solver.statistics.branch_and_bound. 126 # number_of_bounded_subproblems=0 125 #results.solver.statistics.branch_and_bound.number_of_created_subproblems=0 126 #results.solver.statistics.branch_and_bound.number_of_bounded_subproblems=0 127 127 soln = results.solution.add() 128 soln.objective['f'] =float('inf')128 soln.objective['f']=float('inf') 129 129 # 130 130 # Process logfile … … 136 136 # Parse logfile lines 137 137 # 138 139 # Handle long variable names140 stats = results.solver.statistics141 142 138 for line in output.split("\n"): 143 tokens = re.split('[ \t]+', line.strip()) 144 if len(tokens) > 4 and tokens[1] == "objval": 145 soln.objective['f'] = tokens[3] 146 elif len(tokens) > 3 and tokens[0] == "Objective" and \ 147 tokens[1] == "value": 148 soln.objective['f'] = tokens[3] 149 elif len(tokens) > 4 and tokens[0] == "!" and \ 150 tokens[2] == "objval": 151 soln.objective['f'] = tokens[4] 152 elif len(tokens) > 4 and tokens[0] == "+" and \ 153 tokens[2] == "objval": 154 soln.objective['f'] = tokens[4] 155 elif len(tokens) > 4 and tokens[0] == "*" and \ 156 tokens[2] == "objval": 157 soln.objective['f'] = tokens[4] 158 elif len(tokens) > 4 and tokens[0] == "+" and \ 159 tokens[2] == "mip" and tokens[4] == "not": 160 soln.objective['f'] = "unknown" 161 results.problem.lower_bound = tokens[8] 162 elif len(tokens) > 4 and tokens[0] == "+" and \ 163 tokens[1] == "mip" and tokens[4] == "not": 164 soln.objective['f'] = "unknown" 165 results.problem.lower_bound = tokens[7] 166 elif len(tokens) > 4 and tokens[0] == "+" and \ 167 tokens[2] == "mip" and tokens[4] != "not": 168 soln.objective['f'] = tokens[4] 169 if tokens[6] != "tree": 170 results.problem.lower_bound = tokens[6] 171 elif len(tokens) > 4 and tokens[0] == "+" and \ 172 tokens[1] == "mip" and tokens[4] != "not": 173 soln.objective['f'] = tokens[3] 174 results.problem.lower_bound = tokens[5] 175 elif len(tokens) == 6 and tokens[0] == "OPTIMAL" and \ 176 tokens[1] == "SOLUTION" and tokens[5] == "PRESOLVER": 177 stats.branch_and_bound.number_of_created_subproblems = 0 178 stats.branch_and_bound.number_of_bounded_subproblems = 0 179 soln.status = SolutionStatus.optimal 180 elif len(tokens) == 7 and tokens[1] == "OPTIMAL" and \ 181 tokens[2] == "SOLUTION" and tokens[6] == "PRESOLVER": 182 stats.branch_and_bound.number_of_created_subproblems = 0 183 stats.branch_and_bound.number_of_bounded_subproblems = 0 184 soln.status = SolutionStatus.optimal 185 elif len(tokens) > 10 and tokens[0] == "+" and \ 186 tokens[8] == "empty": 187 stats.branch_and_bound.number_of_created_subproblems = tokens[11][:1] 188 stats.branch_and_bound.number_of_bounded_subproblems = tokens[11][:1] 189 elif len(tokens) > 9 and tokens[0] == "+" and \ 190 tokens[7] == "empty": 191 stats.branch_and_bound.number_of_created_subproblems = tokens[10][:1] 192 stats.branch_and_bound.number_of_bounded_subproblems = tokens[10][:1] 193 elif len(tokens) == 2 and tokens[0] == "sys": 194 results.solver.system_time = tokens[1] 195 elif len(tokens) == 2 and tokens[0] == "user": 196 results.solver.user_time = tokens[1] 197 elif len(tokens) > 2 and tokens[0] == "OPTIMAL" and \ 198 tokens[1] == "SOLUTION": 199 soln.status = SolutionStatus.optimal 200 elif len(tokens) > 2 and tokens[0] == "INTEGER" and \ 201 tokens[1] == "OPTIMAL": 202 soln.status = SolutionStatus.optimal 203 stats.branch_and_bound.number_of_created_subproblems = 0 204 stats.branch_and_bound.number_of_bounded_subproblems = 0 205 elif len(tokens) > 2 and tokens[0] == "TIME" and \ 206 tokens[2] == "EXCEEDED;": 207 soln.status = SolutionStatus.stoppedByLimit 139 tokens = re.split('[ \t]+',line.strip()) 140 if len(tokens) > 4 and tokens[1] == "objval": 141 soln.objective['f'] = tokens[3] 142 elif len(tokens) > 3 and tokens[0] == "Objective" and tokens[1] == "value": 143 soln.objective['f'] = tokens[3] 144 elif len(tokens) > 4 and tokens[0] == "!" and tokens[2] == "objval": 145 soln.objective['f'] = tokens[4] 146 elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "objval": 147 soln.objective['f'] = tokens[4] 148 elif len(tokens) > 4 and tokens[0] == "*" and tokens[2] == "objval": 149 soln.objective['f'] = tokens[4] 150 elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "mip" and tokens[4] == "not": 151 soln.objective['f'] = "unknown" 152 results.problem.lower_bound = tokens[8] 153 elif len(tokens) > 4 and tokens[0] == "+" and tokens[1] == "mip" and tokens[4] == "not": 154 soln.objective['f'] = "unknown" 155 results.problem.lower_bound = tokens[7] 156 elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "mip" and tokens[4] != "not": 157 soln.objective['f'] = tokens[4] 158 if tokens[6] != "tree": 159 results.problem.lower_bound = tokens[6] 160 elif len(tokens) > 4 and tokens[0] == "+" and tokens[1] == "mip" and tokens[4] != "not": 161 soln.objective['f'] = tokens[3] 162 results.problem.lower_bound = tokens[5] 163 elif len(tokens) == 6 and tokens[0] == "OPTIMAL" and tokens[1] == "SOLUTION" and tokens[5] == "PRESOLVER": 164 results.solver.statistics.branch_and_bound.number_of_created_subproblems = 0 165 results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = 0 166 soln.status = SolutionStatus.optimal 167 elif len(tokens) == 7 and tokens[1] == "OPTIMAL" and tokens[2] == "SOLUTION" and tokens[6] == "PRESOLVER": 168 results.solver.statistics.branch_and_bound.number_of_created_subproblems = 0 169 results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = 0 170 soln.status = SolutionStatus.optimal 171 elif len(tokens) > 10 and tokens[0] == "+" and tokens[8] == "empty": 172 results.solver.statistics.branch_and_bound.number_of_created_subproblems = tokens[11][:1] 173 results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = tokens[11][:1] 174 elif len(tokens) > 9 and tokens[0] == "+" and tokens[7] == "empty": 175 results.solver.statistics.branch_and_bound.number_of_created_subproblems = tokens[10][:1] 176 results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = tokens[10][:1] 177 elif len(tokens) == 2 and tokens[0] == "sys": 178 results.solver.system_time=tokens[1] 179 elif len(tokens) == 2 and tokens[0] == "user": 180 results.solver.user_time=tokens[1] 181 elif len(tokens) > 2 and tokens[0] == "OPTIMAL" and tokens[1] == "SOLUTION": 182 soln.status = SolutionStatus.optimal 183 elif len(tokens) > 2 and tokens[0] == "INTEGER" and tokens[1] == "OPTIMAL": 184 soln.status = SolutionStatus.optimal 185 results.solver.statistics.branch_and_bound.number_of_created_subproblems = 0 186 results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = 0 187 elif len(tokens) > 2 and tokens[0] == "TIME" and tokens[2] == "EXCEEDED;": 188 soln.status = SolutionStatus.stoppedByLimit 208 189 if results.problem.upper_bound == "inf": 209 190 results.problem.upper_bound = 'Infinity' 210 191 if results.problem.lower_bound == "inf": 211 192 results.problem.lower_bound = "Infinity" 212 193 try: 213 194 val = results.problem.upper_bound … … 229 210 pass 230 211 if soln.status is SolutionStatus.optimal: 231 soln.gap =0.0212 soln.gap=0.0 232 213 elif soln.status is SolutionStatus.stoppedByLimit: 233 soln.gap = "Infinity" # until proven otherwise 234 if "lower_bound" in dir(results.problem): 235 if results.problem.lower_bound is "Infinity": 236 soln.gap = "Infinity" 237 elif not results.problem.lower_bound is None: 238 if "upper_bound" not in dir(results.problem): 239 gap = "Infinity" 240 elif results.problem.upper_bound is None: 241 gap = "Infinity" 242 else: 243 soln.gap = eval(soln.objective['f'])  \ 244 eval(results.problem.lower_bound) 245 elif "upper_bound" in dir(results.problem): 246 if results.problem.upper_bound is "Infinity": 247 soln.gap = "Infinity" 248 elif not results.problem.upper_bound is None: 249 soln.gap = eval(results.problem.upper_bound)  \ 250 eval(soln.objective['f']) 214 soln.gap = "Infinity" # until proven otherwise 215 if "lower_bound" in dir(results.problem): 216 if results.problem.lower_bound is "Infinity": 217 soln.gap="Infinity" 218 elif not results.problem.lower_bound is None: 219 if "upper_bound" not in dir(results.problem): 220 gap="Infinity" 221 elif results.problem.upper_bound is None: 222 gap="Infinity" 223 else: 224 soln.gap=eval(soln.objective['f'])  eval(results.problem.lower_bound) 225 elif "upper_bound" in dir(results.problem): 226 if results.problem.upper_bound is "Infinity": 227 soln.gap="Infinity" 228 elif not results.problem.upper_bound is None: 229 soln.gap=eval(results.problem.upper_bound)  eval(soln.objective['f']) 251 230 if results.solver.status is SolverStatus.error: 252 231 results.solution.delete(0) 253 232 return results 254 233 255 def process_soln_file(self, 234 def process_soln_file(self,results): 256 235 257 236 # the only suffixes that we extract from GLPK are … … 261 240 extract_duals = False 262 241 for suffix in self.suffixes: 263 flag =False264 if re.match(suffix, 242 flag=False 243 if re.match(suffix,"dual"): 265 244 extract_duals = True 266 flag =True245 flag=True 267 246 if not flag: 268 raise RuntimeError, \ 269 ("***GLPK solver plugin cannot extract solution " + \ 270 "suffix='%s'") % (suffix) 271 272 lp_solution = True # if false, we're dealing with a MIP! 247 raise RuntimeError,"***GLPK solver plugin cannot extract solution suffix="+suffix 248 249 lp_solution = True # if false, we're dealing with a MIP! 273 250 if not os.path.exists(self.soln_file): 274 251 return 275 252 soln = results.solution(0) 276 INPUT = open(self.soln_file, 253 INPUT = open(self.soln_file,"r") 277 254 278 255 try: 279 256 280 state = 0 # 0=initial header, 1=constraints, 2=variables, 1=done 281 282 results.problem.number_of_objectives = 1 283 284 # for validation of the total count read and the order 285 number_of_constraints_read = 0 286 number_of_variables_read = 0 287 288 # constraint names and their value/bounds can be split 289 # across multiple lines 290 active_constraint_name = "" 291 292 # variable names and their value/bounds can be split across 293 # multiple lines 294 active_variable_name = "" 295 296 for line in INPUT: 297 tokens = re.split('[ \t]+', line.strip()) 298 299 if (len(tokens) == 1) and (len(tokens[0]) == 0): 300 pass 301 elif state == 0: 302 # 303 # Processing initial header 304 # 305 if len(tokens) == 2 and tokens[0] == "Problem:": 306 # the problem name may be absent, in which case 307 # the "Problem:" line will be skipped. 308 results.problem.name = tokens[1] 309 elif len(tokens) == 2 and tokens[0] == "Rows:": 310 results.problem.number_of_constraints = eval(tokens[1]) 311 elif len(tokens) == 2 and tokens[0] == "Columns:": 312 lp_solution = True 313 results.problem.number_of_variables = eval(tokens[1]) 314 elif len(tokens) > 2 and tokens[0] == "Columns:": 315 lp_solution = False 316 results.problem.number_of_variables = eval(tokens[1]) 317 elif len(tokens) == 2 and tokens[0] == "Nonzeros:": 318 results.problem.number_of_nonzeros = eval(tokens[1]) 319 elif len(tokens) >= 2 and tokens[0] == "Status:": 320 if tokens[1] == "OPTIMAL": 321 soln.status = SolutionStatus.optimal 322 elif len(tokens) == 3 and tokens[1] == "INTEGER" and \ 323 tokens[2] == "NONOPTIMAL": 324 soln.status = SolutionStatus.bestSoFar 325 elif len(tokens) == 3 and tokens[1] == "INTEGER" and \ 326 tokens[2] == "OPTIMAL": 327 soln.status = SolutionStatus.optimal 328 elif len(tokens) == 3 and tokens[1] == "INTEGER" and \ 329 tokens[2] == "UNDEFINED": 330 soln.status = SolutionStatus.stoppedByLimit 331 elif (len(tokens) == 2) and (tokens[1] == "UNDEFINED"): 332 soln.status = SolutionStatus.infeasible 333 else: 334 print ("WARNING: Read unknown status while " + \ 335 "parsing GLPK solution file  " + \ 336 "status='%s'") % (" ".join(tokens[1:])) 337 elif len(tokens) >= 2 and tokens[0] == "Objective:": 338 if tokens[4] == "(MINimum)": 339 results.problem.sense = ProblemSense.minimize 340 else: 341 results.problem.sense = ProblemSense.maximize 342 soln.objective['f'] = tokens[3] 343 if soln.status is SolutionStatus.optimal: 344 if tokens[4] == "(MINimum)": 345 results.problem.lower_bound = soln.objective['f'].value 346 if "upper_bound" in dir(results.problem): 347 del results.problem.upper_bound 348 else: 349 results.problem.upper_bound = soln.objective['f'].value 350 if "lower_bound" in dir(results.problem): 351 del results.problem.lower_bound 352 # the objective is the last entry in the problem section  move on to constraints. 353 state = 1 354 355 elif state == 1: 356 # 357 # Process Constraint Info 358 # 359 360 if (len(tokens) == 2) and (len(active_constraint_name) == 0): 361 number_of_constraints_read = number_of_constraints_read + 1 362 active_constraint_name = tokens[1].strip() 363 index = eval(tokens[0].strip()) 364 365 # sanity check  the indices should be in sequence. 366 if index != number_of_constraints_read: 367 raise ValueError, \ 368 ("***ERROR: Unexpected constraint index " + \ 369 "encountered on line=%s; expected " + \ 370 "value=%s; actual value=%s") % \ 371 (line, str(number_of_consrtaints_read), 372 str(index)) 373 else: 374 index = None 375 activity = None 376 lower_bound = None 377 upper_bound = None 378 marginal = None 379 380 # extract the field names and process accordingly. there 381 # is some wasted processing w.r.t. single versus doubleline 382 # entries, but it's not significant enough to worry about. 383 384 index_string = line[0:6].strip() 385 name_string = line[7:19].strip() 386 activity_string = line[23:36].strip() 387 lower_bound_string = line[37:50].strip() 388 upper_bound_string = line[51:64].strip() 389 390 state_string = None 391 marginal_string = None 392 393 # skip any headers 394 if (index_string == "") or (index_string == "No."): 395 continue 396 397 if len(index_string) > 0: 398 index = eval(index_string) 399 400 if lp_solution is True: 401 state_string = line[20:22].strip() 402 marginal_string = line[65:78].strip() 403 if (activity_string != "< eps") and (len(activity_string) > 0): 404 activity = eval(activity_string) 405 else: 406 activity = 0.0 407 if (lower_bound_string != "< eps") and (len(lower_bound_string) > 0): 408 lower_bound = eval(lower_bound_string) 409 else: 410 lower_bound = 0.0 411 if state_string != "NS": 412 if (upper_bound_string != "< eps") and (len(upper_bound_string) > 0): 413 upper_bound = eval(upper_bound_string) 414 else: 415 upper_bound = 0.0 416 if (marginal_string != "< eps") and (len(marginal_string) > 0): 417 marginal = eval(marginal_string) 418 else: 419 marginal = 0.0 420 421 else: 422 # no constraintrelated attributes/values are extracted currently for MIPs. 423 pass 424 425 constraint_name = None 426 if len(active_constraint_name) > 0: 427 # if there is an active constraint name, the identifier was 428 # too long for everything to be on a single line; the second 429 # line contains all of the value information. 430 constraint_name = active_constraint_name 431 active_constraint_name = "" 432 else: 433 # everything is on a single line. 434 constraint_name = name_string 435 number_of_constraints_read = number_of_constraints_read + 1 436 # sanity check  the indices should be in sequence. 437 if index != number_of_constraints_read: 438 raise ValueError,"***ERROR: Unexpected constraint index encountered on line="+line+"; expected value="+str(number_of_constraints_read)+"; actual value="+str(index) 439 440 if lp_solution is True: 441 # GLPK doesn't report slacks directly. 442 constraint_dual = activity 443 if state_string == "B": 444 constraint_dual = 0.0 445 elif (state_string == "NS") or (state_string == "NL") or (state_string == "NU"): 446 constraint_dual = marginal 447 else: 448 raise ValueError, "Unknown status="+tokens[0]+" encountered for constraint="+active_constraint_name+" in line="+line+" of solution file="+self.soln_file 449 450 if extract_duals is True: 451 soln.constraint[constraint_name].dual = constraint_dual 452 453 else: 454 # there isn't anything interesting to do with constraints in the MIP case. 455 pass 456 457 # if all of the constraints have been read, exit. 458 if number_of_constraints_read == results.problem.number_of_constraints: 459 state = 2 460 461 elif state == 2: 462 # 463 # Process Variable Info 464 # 465 466 if (len(tokens) == 2) and (len(active_variable_name) == 0): 467 468 # in the case of name overflow, there are only two tokens 469 # on the first of two lines for the variable entry. 470 number_of_variables_read = number_of_variables_read + 1 471 active_variable_name = tokens[1].strip() 472 index = eval(tokens[0].strip()) 473 474 # sanity check  the indices should be in sequence. 475 if index != number_of_variables_read: 476 raise ValueError,"***ERROR: Unexpected variable index encountered on line="+line+"; expected value="+str(number_of_variables_read)+"; actual value="+str(index) 477 478 else: 479 480 index = None 481 activity = None 482 lower_bound = None 483 upper_bound = None 484 marginal = None 485 486 # extract the field names and process accordingly. there 487 # is some wasted processing w.r.t. single versus doubleline 488 # entries, but it's not significant enough to worry about. 489 490 index_string = line[0:6].strip() 491 name_string = line[7:19].strip() 492 activity_string = line[23:36].strip() 493 lower_bound_string = line[37:50].strip() 494 upper_bound_string = line[51:64].strip() 495 496 state_string = None 497 marginal_string = None 498 499 # skip any headers 500 if (index_string == "") or (index_string == "No."): 501 continue 502 503 if len(index_string) > 0: 504 index = eval(index_string) 505 506 if lp_solution is True: 507 508 state_string = line[20:22].strip() 509 marginal_string = line[65:78].strip() 510 511 if (activity_string != "< eps") and (len(activity_string) > 0): 512 activity = eval(activity_string) 513 else: 514 activity = 0.0 515 if (lower_bound_string != "< eps") and (len(lower_bound_string) > 0): 516 lower_bound = eval(lower_bound_string) 517 else: 518 lower_bound = 0.0 519 if state_string != "NS": 520 if (upper_bound_string != "< eps") and (len(upper_bound_string) > 0): 521 upper_bound = eval(upper_bound_string) 522 else: 523 upper_bound = 0.0 524 if (marginal_string != "< eps") and (len(marginal_string) > 0): 525 marginal = eval(marginal_string) 526 else: 527 marginal = 0.0 528 else: 529 if (activity_string != "< eps") and (len(activity_string) > 0): 530 activity = eval(activity_string) 531 else: 532 activity = 0.0 533 534 variable_name = None 535 if len(active_variable_name) > 0: 536 # if there is an active variable name, the identifier was 537 # too long for everything to be on a single line; the second 538 # line contains all of the value information. 539 variable_name = active_variable_name 540 active_variable_name = "" 541 else: 542 # everything is on a single line. 543 variable_name = name_string 544 number_of_variables_read = number_of_variables_read + 1 545 # sanity check  the indices should be in sequence. 546 if index != number_of_variables_read: 547 raise ValueError,"***ERROR: Unexpected variable index encountered on line="+line+"; expected value="+str(number_of_variables_read)+"; actual value="+str(index) 548 549 if lp_solution is True: 550 # the "activity" column always specifies the variable value. 551 # embedding the ifthenelse to validate the basis status. 552 # we are currently ignoring all boundrelated information. 553 variable_value = None 554 if state_string in ('B', 'NL', 'NS', 'NU', 'NF'): 555 # NF = nonbasic free (unbounded) variable 556 # NL = nonbasic variable at its lower bound 557 # NU = nonbasic variable at its upper bound 558 # NS = nonbasic fixed variable 559 variable_value = activity 560 else: 561 raise ValueError, "Unknown status="+state_string+" encountered for variable="+variable_name+" in the following line of the GLPK solution file="+self.soln_file+":\n"+line 562 563 soln.variable[variable_name].value = variable_value 564 else: 565 soln.variable[variable_name].value = activity 566 567 # if all of the variables have been read, exit. 568 if number_of_variables_read == results.problem.number_of_variables: 569 state = 1 570 571 if state==1: 572 break 573 574 INPUT.close() 257 state = 0 # 0=initial header, 1=constraints, 2=variables, 1=done 258 259 results.problem.number_of_objectives = 1 260 261 number_of_constraints_read = 0 # for validation of the total count read and the order 262 number_of_variables_read = 0 263 active_constraint_name = "" # constraint names and their value/bounds can be split across multiple lines 264 active_variable_name = "" # variable names and their value/bounds can be split across multiple lines 265 266 for line in INPUT: 267 tokens = re.split('[ \t]+',line.strip()) 268 269 if (len(tokens) == 1) and (len(tokens[0]) == 0): 270 pass 271 elif state == 0: 272 # 273 # Processing initial header 274 # 275 if len(tokens) == 2 and tokens[0] == "Problem:": 276 # the problem name may be absent, in which case the "Problem:" line will be skipped. 277 results.problem.name = tokens[1] 278 elif len(tokens) == 2 and tokens[0] == "Rows:": 279 results.problem.number_of_constraints = eval(tokens[1]) 280 elif len(tokens) == 2 and tokens[0] == "Columns:": 281 lp_solution = True 282 results.problem.number_of_variables = eval(tokens[1]) 283 elif len(tokens) > 2 and tokens[0] == "Columns:": 284 lp_solution = False 285 results.problem.number_of_variables = eval(tokens[1]) 286 elif len(tokens) == 2 and tokens[0] == "Nonzeros:": 287 results.problem.number_of_nonzeros = eval(tokens[1]) 288 elif len(tokens) >= 2 and tokens[0] == "Status:": 289 if tokens[1] == "OPTIMAL": 290 soln.status = SolutionStatus.optimal 291 elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "NONOPTIMAL": 292 soln.status = SolutionStatus.bestSoFar 293 elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "OPTIMAL": 294 soln.status = SolutionStatus.optimal 295 elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "UNDEFINED": 296 soln.status = SolutionStatus.stoppedByLimit 297 elif (len(tokens) == 2) and (tokens[1] == "UNDEFINED"): 298 soln.status = SolutionStatus.infeasible 299 else: 300 print "WARNING: Read unknown status while parsing GLPK solution file  status="+" ".join(tokens[1:]) 301 elif len(tokens) >= 2 and tokens[0] == "Objective:": 302 if tokens[4] == "(MINimum)": 303 results.problem.sense = ProblemSense.minimize 304 else: 305 results.problem.sense = ProblemSense.maximize 306 soln.objective['f']=tokens[3] 307 if soln.status is SolutionStatus.optimal: 308 if tokens[4] == "(MINimum)": 309 results.problem.lower_bound = soln.objective['f'].value 310 if "upper_bound" in dir(results.problem): 311 del results.problem.upper_bound 312 else: 313 results.problem.upper_bound = soln.objective['f'].value 314 if "lower_bound" in dir(results.problem): 315 del results.problem.lower_bound 316 # the objective is the last entry in the problem section  move on to constraints. 317 state = 1 318 319 elif state == 1: 320 # 321 # Process Constraint Info 322 # 323 324 if (len(tokens) == 2) and (len(active_constraint_name) == 0): 325 326 number_of_constraints_read = number_of_constraints_read + 1 327 active_constraint_name = tokens[1].strip() 328 index = eval(tokens[0].strip()) 329 330 # sanity check  the indices should be in sequence. 331 if index != number_of_constraints_read: 332 raise ValueError,"***ERROR: Unexpected constraint index encountered on line="+line+"; expected value="+str(number_of_constraints_read)+"; actual value="+str(index) 333 334 else: 335 336 index = None 337 activity = None 338 lower_bound = None 339 upper_bound = None 340 marginal = None 341 342 # extract the field names and process accordingly. there 343 # is some wasted processing w.r.t. single versus doubleline 344 # entries, but it's not significant enough to worry about. 345 346 index_string = line[0:6].strip() 347 name_string = line[7:19].strip() 348 activity_string = line[23:36].strip() 349 lower_bound_string = line[37:50].strip() 350 upper_bound_string = line[51:64].strip() 351 352 state_string = None 353 marginal_string = None 354 355 # skip any headers 356 if (index_string == "") or (index_string == "No."): 357 continue 358 359 if len(index_string) > 0: 360 index = eval(index_string) 361 362 if lp_solution is True: 363 state_string = line[20:22].strip() 364 marginal_string = line[65:78].strip() 365 if (activity_string != "< eps") and (len(activity_string) > 0): 366 activity = eval(activity_string) 367 else: 368 activity = 0.0 369 if (lower_bound_string != "< eps") and (len(lower_bound_string) > 0): 370 lower_bound = eval(lower_bound_string) 371 else: 372 lower_bound = 0.0 373 if state_string != "NS": 374 if (upper_bound_string != "< eps") and (len(upper_bound_string) > 0): 375 upper_bound = eval(upper_bound_string) 376 else: 377 upper_bound = 0.0 378 if (marginal_string != "< eps") and (len(marginal_string) > 0): 379 marginal = eval(marginal_string) 380 else: 381 marginal = 0.0 382 383 else: 384 # no constraintrelated attributes/values are extracted currently for MIPs. 385 pass 386 387 constraint_name = None 388 if len(active_constraint_name) > 0: 389 # if there is an active constraint name, the identifier was 390 # too long for everything to be on a single line; the second 391 # line contains all of the value information. 392 constraint_name = active_constraint_name 393 active_constraint_name = "" 394 else: 395 # everything is on a single line. 396 constraint_name = name_string 397 number_of_constraints_read = number_of_constraints_read + 1 398 # sanity check  the indices should be in sequence. 399 if index != number_of_constraints_read: 400 raise ValueError,"***ERROR: Unexpected constraint index encountered on line="+line+"; expected value="+str(number_of_constraints_read)+"; actual value="+str(index) 401 402 if lp_solution is True: 403 # GLPK doesn't report slacks directly. 404 constraint_dual = activity 405 if state_string == "B": 406 constraint_dual = 0.0 407 elif (state_string == "NS") or (state_string == "NL") or (state_string == "NU"): 408 constraint_dual = marginal 409 else: 410 raise ValueError, "Unknown status="+tokens[0]+" encountered for constraint="+active_constraint_name+" in line="+line+" of solution file="+self.soln_file 411 412 if extract_duals is True: 413 soln.constraint[constraint_name].dual = constraint_dual 414 415 else: 416 # there isn't anything interesting to do with constraints in the MIP case. 417 pass 418 419 # if all of the constraints have been read, exit. 420 if number_of_constraints_read == results.problem.number_of_constraints: 421 state = 2 422 423 elif state == 2: 424 # 425 # Process Variable Info 426 # 427 428 if (len(tokens) == 2) and (len(active_variable_name) == 0): 429 430 # in the case of name overflow, there are only two tokens 431 # on the first of two lines for the variable entry. 432 number_of_variables_read = number_of_variables_read + 1 433 active_variable_name = tokens[1].strip() 434 index = eval(tokens[0].strip()) 435 436 # sanity check  the indices should be in sequence. 437 if index != number_of_variables_read: 438 raise ValueError,"***ERROR: Unexpected variable index encountered on line="+line+"; expected value="+str(number_of_variables_read)+"; actual value="+str(index) 439 440 else: 441 442 index = None 443 activity = None 444 lower_bound = None 445 upper_bound = None 446 marginal = None 447 448 # extract the field names and process accordingly. there 449 # is some wasted processing w.r.t. single versus doubleline 450 # entries, but it's not significant enough to worry about. 451 452 index_string = line[0:6].strip() 453 name_string = line[7:19].strip() 454 activity_string = line[23:36].strip() 455 lower_bound_string = line[37:50].strip() 456 upper_bound_string = line[51:64].strip() 457 458 state_string = None 459 marginal_string = None 460 461 # skip any headers 462 if (index_string == "") or (index_string == "No."): 463 continue 464 465 if len(index_string) > 0: 466 index = eval(index_string) 467 468 if lp_solution is True: 469 470 state_string = line[20:22].strip() 471 marginal_string = line[65:78].strip() 472 473 if (activity_string != "< eps") and (len(activity_string) > 0): 474 activity = eval(activity_string) 475 else: 476 activity = 0.0 477 if (lower_bound_string != "< eps") and (len(lower_bound_string) > 0): 478 lower_bound = eval(lower_bound_string) 479 else: 480 lower_bound = 0.0 481 if state_string != "NS": 482 if (upper_bound_string != "< eps") and (len(upper_bound_string) > 0): 483 upper_bound = eval(upper_bound_string) 484 else: 485 upper_bound = 0.0 486 if (marginal_string != "< eps") and (len(marginal_string) > 0): 487 marginal = eval(marginal_string) 488 else: 489 marginal = 0.0 490 491 else: 492 493 if (activity_string != "< eps") and (len(activity_string) > 0): 494 activity = eval(activity_string) 495 else: 496 activity = 0.0 497 498 variable_name = None 499 if len(active_variable_name) > 0: 500 # if there is an active variable name, the identifier was 501 # too long for everything to be on a single line; the second 502 # line contains all of the value information. 503 variable_name = active_variable_name 504 active_variable_name = "" 505 else: 506 # everything is on a single line. 507 variable_name = name_string 508 number_of_variables_read = number_of_variables_read + 1 509 # sanity check  the indices should be in sequence. 510 if index != number_of_variables_read: 511 raise ValueError,"***ERROR: Unexpected variable index encountered on line="+line+"; expected value="+str(number_of_variables_read)+"; actual value="+str(index) 512 513 if lp_solution is True: 514 # the "activity" column always specifies the variable value. 515 # embedding the ifthenelse to validate the basis status. 516 # we are currently ignoring all boundrelated information. 517 variable_value = None 518 if state_string in ('B', 'NL', 'NS', 'NU', 'NF'): 519 # NF = nonbasic free (unbounded) variable 520 # NL = nonbasic variable at its lower bound 521 # NU = nonbasic variable at its upper bound 522 # NS = nonbasic fixed variable 523 variable_value = activity 524 else: 525 raise ValueError, "Unknown status="+state_string+" encountered for variable="+variable_name+" in the following line of the GLPK solution file="+self.soln_file+":\n"+line 526 527 soln.variable[variable_name].value = variable_value 528 else: 529 soln.variable[variable_name].value = activity 530 531 # if all of the variables have been read, exit. 532 if number_of_variables_read == results.problem.number_of_variables: 533 state = 1 534 535 if state==1: 536 break 537 538 INPUT.close() 575 539 576 540 except ValueError, msg: 577 578 541 INPUT.close() 542 raise RuntimeError, msg 579 543 except Exception: 580 581 544 INPUT.close() 545 raise RuntimeError, "Unexpected input encountered in GLPK solution file, yielding parse failure; line="+str(line) 582 546 583 547 class MockGLPK(GLPK,mockmip.MockMIP):
Note: See TracChangeset
for help on using the changeset viewer.