source: trunk/coopr/plugins/mip/GLPK.py @ 1657

Last change on this file since 1657 was 1657, checked in by wehart, 11 years ago

Removing coopr.opt-depricated, and
renaming coopr.core to coopr.opt.

Unfortunately, plugins are still not being properly loaded, so
some of the tests are failing.

File size: 13.9 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11
12import os
13import re
14from coopr.opt.base import *
15from coopr.opt.solver import *
16import mockmip
17import pyutilib
18
19
20class GLPK(SystemCallSolver):
21    """The GLPK LP/MIP solver
22    """
23
24    def __init__(self, **kwds):
25        #
26        # Call base constructor
27        #
28        kwds['type'] = 'glpk'
29        SystemCallSolver.__init__(self, **kwds)
30        #
31        # Valid problem formats, and valid results for each format
32        #
33        self._valid_problem_formats=[ProblemFormat.mod, ProblemFormat.cpxlp, ProblemFormat.mps]
34        self._valid_result_formats={}
35        self._valid_result_formats[ProblemFormat.mod] = [ResultsFormat.log]
36        self._valid_result_formats[ProblemFormat.cpxlp] = [ResultsFormat.log]
37        self._valid_result_formats[ProblemFormat.mps] = [ResultsFormat.log]
38
39    def executable(self):
40        executable = pyutilib.registered_executable("glpsol")
41        if executable is None:
42            pyutilib.plugin.PluginGlobals.env().log.error("Could not locate the 'glpsol' executable, which is required for solver %s" % self.name)
43            self.enable = False
44            return None
45        return executable.get_path()
46
47    def create_command_line(self,executable,problem_files):
48        #
49        # Define log file
50        #
51        if self.log_file is None:
52           self.log_file = pyutilib.TempfileManager.create_tempfile(suffix = '.glpk.log')
53
54        #
55        # Define solution file
56        #
57        if self.soln_file is None:
58            self.soln_file = pyutilib.TempfileManager.create_tempfile(suffix = '.glpk.soln')
59
60        #
61        # Define results file
62        #
63        if self._results_format is None or self._results_format == ResultsFormat.log:
64           self.results_file = self.log_file
65           
66        #
67        # Define command line
68        #
69        if self._timelimit is not None and self._timelimit > 0.0:
70           timing = " --tmlim "+str(self._timelimit)+" "
71        else:
72           timing = ""
73        if self._problem_format == ProblemFormat.cpxlp:
74            problem=" --cpxlp " + problem_files[0]
75        elif self._problem_format == ProblemFormat.mps:
76            problem=" --freemps " + problem_files[0]
77        elif self._problem_format == ProblemFormat.mod:
78            problem=" --math " + problem_files[0]
79            for filename in problem_files[1:]:
80                problem += " --data " + filename
81        opt = ""
82        for key in self.options:
83            if isinstance(self.options[key],basestring) and ' ' in self.options[key]:
84                opt += " --"+key+" \""+str(self.options[key])+"\""
85            else:
86                opt += " --"+key+" "+str(self.options[key])
87        proc = self._timer + " " + executable + opt + " " + timing + " --output " + self.soln_file + problem
88        return pyutilib.Bunch(cmd=proc, log_file=self.log_file, env=None)
89
90    def process_logfile(self):
91        """
92        Process logfile
93        """
94        results = SolverResults()
95        #
96        # Initial values
97        #
98        results.solver.ncreated=0
99        results.solver.nbounded=0
100        soln = results.solution.create()
101        #
102        # Process logfile
103        #
104        OUTPUT = open(self.log_file)
105        output = "".join(OUTPUT.readlines())
106        OUTPUT.close()
107        #
108        # Parse logfile lines
109        #
110        for line in output.split("\n"):
111          tokens = re.split('[ \t]+',line.strip())
112          #print "LINE:", tokens
113          if len(tokens) > 4 and tokens[1] == "objval":
114             soln.value = tokens[3]
115          elif len(tokens) > 3 and tokens[0] == "Objective" and tokens[1] == "value":
116             soln.value = tokens[3]
117          elif len(tokens) > 4 and tokens[0] == "!" and tokens[2] == "objval":
118             soln.value = tokens[4]
119          elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "objval":
120             soln.value = tokens[4]
121          elif len(tokens) > 4 and tokens[0] == "*" and tokens[2] == "objval":
122             soln.value = tokens[4]
123          elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "mip" and tokens[4] == "not":
124             soln.value = "unknown"
125             results.problem.lower_bound = tokens[8]
126          elif len(tokens) > 4 and tokens[0] == "+" and tokens[1] == "mip" and tokens[4] == "not":
127             soln.value = "unknown"
128             results.problem.lower_bound = tokens[7]
129          elif len(tokens) > 4 and tokens[0] == "+" and tokens[2] == "mip" and tokens[4] != "not":
130             soln.value = tokens[4]
131             if tokens[6] != "tree":
132                results.problem.lower_bound = tokens[6]
133          elif len(tokens) > 4 and tokens[0] == "+" and tokens[1] == "mip" and tokens[4] != "not":
134             soln.value = tokens[3]
135             results.problem.lower_bound = tokens[5]
136          elif len(tokens) == 6 and tokens[0] == "OPTIMAL" and tokens[1] == "SOLUTION" and tokens[5] == "PRESOLVER":
137             results.solver.ncreated = 0
138             results.solver.nbounded = 0
139             soln.status = SolutionStatus.optimal
140          elif len(tokens) == 7 and tokens[1] == "OPTIMAL" and tokens[2] == "SOLUTION" and tokens[6] == "PRESOLVER":
141             results.solver.ncreated = 0
142             results.solver.nbounded = 0
143             soln.status = SolutionStatus.optimal
144          elif len(tokens) > 10 and tokens[0] == "+" and tokens[8] == "empty":
145             results.solver.ncreated = tokens[11][:-1]
146             results.solver.nbounded = tokens[11][:-1]
147          elif len(tokens) > 9 and tokens[0] == "+" and tokens[7] == "empty":
148             results.solver.ncreated = tokens[10][:-1]
149             results.solver.nbounded = tokens[10][:-1]
150          elif len(tokens) == 2 and tokens[0] == "sys":
151             results.solver.systime=tokens[1]
152          elif len(tokens) == 2 and tokens[0] == "user":
153             results.solver.usrtime=tokens[1]
154          elif len(tokens) > 2 and tokens[0] == "OPTIMAL" and tokens[1] == "SOLUTION":
155             soln.status = SolutionStatus.optimal
156          elif len(tokens) > 2 and tokens[0] == "INTEGER" and tokens[1] == "OPTIMAL":
157             soln.status = SolutionStatus.optimal
158          elif len(tokens) > 2 and tokens[0] == "TIME" and tokens[2] == "EXCEEDED;":
159             soln.status = SolutionStatus.stoppedByLimit
160        if results.problem.upper_bound == "inf":
161           results.problem.upper_bound = "Infinity"
162        if results.problem.lower_bound == "-inf":
163           results.problem.lower_bound = "-Infinity"
164        try:
165            tmp = eval(results.problem.upper_bound.strip())
166            results.problem.upper_bound = str(tmp)
167        except:
168            pass
169        try:
170            tmp = eval(results.problem.lower_bound.strip())
171            results.problem.lower_bound = str(tmp)
172        except:
173            pass
174        try:
175            tmp = eval(soln.value.strip())
176            soln.value = str(tmp)
177        except:
178            pass
179        if soln.status is SolutionStatus.optimal:
180           soln.gap=0.0
181        elif soln.status is SolutionStatus.stoppedByLimit:
182           soln.gap = "Infinity" # until proven otherwise
183           if "lower_bound" in dir(results.problem):
184              if results.problem.lower_bound is "-Infinity":
185                 soln.gap="Infinity"
186              elif not results.problem.lower_bound is None:
187                 if "upper_bound" not in dir(results.problem):
188                    gap="Infinity"
189                 elif results.problem.upper_bound is None:
190                    gap="Infinity"
191                 else:
192                    soln.gap=eval(soln.value) - eval(results.problem.lower_bound)
193           elif "upper_bound" in dir(results.problem):
194              if results.problem.upper_bound is "Infinity":
195                 soln.gap="Infinity"
196              elif not results.problem.upper_bound is None:
197                 soln.gap=eval(results.problem.upper_bound) - eval(soln.value)
198        if results.solver.status is SolverStatus.error:
199           results.solution.delete(0)
200        return results
201
202    def process_other_data(self,results):
203        lp_solution=False
204        if not os.path.exists(self.soln_file):
205           return
206        soln = results.solution(0)
207        INPUT = open(self.soln_file,"r")
208        state=0
209        results.problem.num_objectives=1
210        for line in INPUT:
211          tokens = re.split('[ \t]+',line.strip())
212          ##print "LINE",line,len(tokens)
213          ##print "TOKENS",tokens
214          if state==0:
215             #
216             # Processing initial header
217             #
218             if len(tokens) == 2 and tokens[0] == "Problem:":
219                results.problem.name = tokens[1]
220             elif len(tokens) == 2 and tokens[0] == "Rows:":
221                results.problem.num_constraints = tokens[1]
222             elif len(tokens) >= 2 and tokens[0] == "Columns:":
223                results.problem.num_variables = tokens[1]
224             elif len(tokens) == 2 and tokens[0] == "Non-zeros:":
225                results.problem.num_nonzeros = tokens[1]
226             elif len(tokens) >= 2 and tokens[0] == "Status:":
227                if tokens[1] == "OPTIMAL":
228                   soln.status = SolutionStatus.optimal
229                elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "NON-OPTIMAL":
230                   soln.status = SolutionStatus.bestSoFar
231                elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "OPTIMAL":
232                   soln.status = SolutionStatus.optimal
233                elif len(tokens) == 3 and tokens[1] == "INTEGER" and tokens[2] == "UNDEFINED":
234                   soln.status = SolutionStatus.unbounded                   
235                else:
236                   print "GLPK WARNING: unknown status: "+" ".join(tokens[1:])
237             elif len(tokens) >= 2 and tokens[0] == "Objective:":
238                if tokens[4] == "(MINimum)":
239                   results.problem.sense = ProblemSense.minimize
240                else:
241                   results.problem.sense = ProblemSense.maximize
242                soln.value=tokens[3]
243                if soln.status is SolutionStatus.optimal:
244                   if tokens[4] == "(MINimum)":
245                        results.problem.lower_bound = soln.value
246                        if "upper_bound" in dir(results.problem):
247                            del results.problem.upper_bound
248                   else:
249                        results.problem.upper_bound = soln.value
250                        if "lower_bound" in dir(results.problem):
251                            del results.problem.lower_bound
252             elif len(tokens) > 1 and tokens[0] == "No.":
253                if tokens[1] == "Row":
254                   state=1
255                else:
256                   state=2
257          elif state==1:
258             #
259             # Process Constraint Info
260             #
261             if len(tokens) == 0:
262                continue
263             if len(tokens) > 1 and tokens[0] == "No.":
264                state=2
265                if line[65:78].strip() == "Marginal":
266                   lp_solution=True
267             else:
268                tmp=line[0:6]
269                tmp = tmp.strip()
270                if tmp == "------":
271                   continue
272                if tmp != "":
273                   tmpname = tokens[1]
274                   if len(tokens) == 2:
275                      continue
276                tmp=line[65:78]
277                tmp=tmp.strip()
278                ##print "HERE",tmp
279                if tmp=="":
280                   if lp_solution:
281                      soln.dual.add( tmpname,0.0 )
282                else:
283                   if tmp.strip() == "< eps":
284                      soln.dual.add( tmpname,0.0 )
285                   else:
286                      soln.dual.add( tmpname,tmp )
287          elif state==2:
288             #
289             # Process Variable Info
290             #
291             if len(tokens) == 1:
292                state=-1
293                continue
294             if True:
295                tmp=line[0:6]
296                tmp = tmp.strip()
297                if tmp == "------":
298                   continue
299                if tmp != "":
300                   tmpname = tokens[1]
301                   if len(tokens) == 2:
302                      continue
303                tmp=line[23:36]
304                tmp=tmp.strip()
305                if tmp=="":
306                   soln.variable.add( tmpname,0.0 )
307                else:
308                   soln.variable.add( tmpname,tmp )
309          if state==-1:
310             break
311        INPUT.close()
312
313
314
315class MockGLPK(GLPK,mockmip.MockMIP):
316    """A Mock GLPK solver used for testing
317    """
318
319    def __init__(self, **kwds):
320        try:
321           GLPK.__init__(self, **kwds)
322        except pyutilib.ApplicationError: #pragma:nocover
323           pass                        #pragma:nocover
324        mockmip.MockMIP.__init__(self,"glpk")
325
326    def available(self, exception_flag=True):
327        return GLPK.available(self,exception_flag)
328
329    def create_command_line(self,executable,problem_files):
330        command = GLPK.create_command_line(self,executable,problem_files)
331        mockmip.MockMIP.create_command_line(self,executable,problem_files)
332        return command
333
334    def executable(self):
335        return mockmip.MockMIP.executable(self)
336
337    def _execute_command(self,cmd):
338        return mockmip.MockMIP._execute_command(self,cmd)
339
340    def _convert_problem(self,args,pformat,valid_pformats):
341        if pformat in [ProblemFormat.mps,ProblemFormat.cpxlp]:
342           return (args,pformat)
343        else:
344           return (args,ProblemFormat.cpxlp)
345
346
347pyutilib.register_executable(name="glpsol")
348SolverRegistration("glpk", GLPK)
349SolverRegistration("_mock_glpk", MockGLPK)
Note: See TracBrowser for help on using the repository browser.