source: coopr.plugins/trunk/coopr/plugins/mip/PICO.py @ 2308

Last change on this file since 2308 was 2308, checked in by wehart, 10 years ago

Generalizing the suffix management in the MIP solvers so
they match regular expressions for suffixes. This allows
the user to specify the '.*' suffix, which matches everything.

Reworked the MIP tests, which all pass now.

File size: 10.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 re
13from coopr.opt.base import *
14from coopr.opt.results import *
15from coopr.opt.solver import *
16import pyutilib.services
17import pyutilib.common
18import pyutilib.common
19import pyutilib.component.core
20import mockmip
21import os
22import copy
23
24
25class PICO(SystemCallSolver):
26    """The PICO LP/MIP solver
27    """
28
29    def __init__(self, **kwds):
30        #
31        # Call base constructor
32        #
33        kwds["type"] = "pico"
34        SystemCallSolver.__init__(self, **kwds)
35        #
36        # Setup valid problem formats, and valid results for each problem format
37        #
38        self._valid_problem_formats=[ProblemFormat.cpxlp, ProblemFormat.nl, ProblemFormat.mps]
39        self._valid_result_formats = {}
40        self._valid_result_formats[ProblemFormat.cpxlp] = [ResultsFormat.soln]
41        self._valid_result_formats[ProblemFormat.nl] = [ResultsFormat.sol]
42        self._valid_result_formats[ProblemFormat.mps] = [ResultsFormat.soln]
43
44    def executable(self):
45        executable = pyutilib.services.registered_executable("PICO")
46        if executable is None:
47            pyutilib.component.core.PluginGlobals.env().log.error("Could not locate the 'PICO' executable, which is required for solver %s" % self.name)
48            self.enable = False
49            return None
50        return executable.get_path()
51
52    def create_command_line(self,executable,problem_files):
53        #
54        # Define log file
55        #
56        if self.log_file is None:
57           self.log_file = pyutilib.services.TempfileManager.create_tempfile(suffix="PICO.log")
58        fname = problem_files[0].split(os.sep)[-1]
59        if '.' in fname:
60            tmp = fname.split('.')
61            if len(tmp) > 2:
62                fname = '.'.join(tmp[:-1])
63            else:
64                fname = tmp[0]
65        if self.soln_file is None:
66           self.soln_file = pyutilib.services.TempfileManager.create_tempfile(suffix=fname+".soln")
67        self.sol_file = fname+".sol"
68        #
69        # Define results file
70        #
71        if self._results_format is None or self._results_format == ResultsFormat.soln:
72           self.results_file = self.soln_file
73        elif self._results_format == ResultsFormat.sol:
74           self.results_file = self.sol_file
75       
76        # Eventually, these formats will be added to PICO...
77        #
78        #elif self._results_format == ResultsFormat.osrl:
79           #self.results_file = self.tmpDir+os.sep+"PICO.osrl.xml"
80        #
81        # Define command line
82        #
83        if (self.mipgap is not None):
84           raise ValueError, "The mipgap parameter is currently not being processed by PICO solver plugin"       
85        env=copy.copy(os.environ)
86        if self._problem_format is None or self._problem_format == ProblemFormat.nl:
87           if "debug" in self.options:
88                opts = []
89           else:
90                opts = ["debug=2"]
91           for key in self.options:
92                if isinstance(self.options[key],basestring) and ' ' in self.options[key]:
93                    opts.append(key+"=\""+str(self.options[key])+"\"")
94                else:
95                    opt.append(key+"="+str(self.options[key]))
96           env["PICO_options"] = " ".join(opts)
97           proc = self._timer + " " + executable + " " + problem_files[0] + " -AMPL"
98        elif self._problem_format == ProblemFormat.cpxlp or self._problem_format == ProblemFormat.mps:
99           if "debug" in self.options:
100                opt = ""
101           else:
102                opt = " --debug 2"
103           for key in self.options:
104                if isinstance(self.options[key],basestring) and ' ' in self.options[key]:
105                    opt += " --"+key+"=\""+str(self.options[key])+"\""
106                else:
107                    opt += " --"+key+"="+str(self.options[key])
108           proc = self._timer + " " + executable + opt + " --output " + self.soln_file + " " + problem_files[0]
109        return pyutilib.misc.Bunch(cmd=proc, log_file=self.log_file, env=env)
110
111    def process_logfile(self):
112        """
113        Process a logfile
114        """
115        results = SolverResults()
116        #
117        # Initial values
118        #
119        #results.solver.statistics.branch_and_bound.number_of_created_subproblems=0
120        #results.solver.statistics.branch_and_bound.number_of_bounded_subproblems=0
121        soln = results.solution.add()
122        soln.objective['f'].value = None
123        #
124        # Process logfile
125        #
126        OUTPUT = open(self.log_file)
127        output = "".join(OUTPUT.readlines())
128        OUTPUT.close()
129        #
130        # Parse logfile lines
131        #
132        for line in output.split("\n"):
133          tokens = re.split('[ \t]+',line.strip())
134          if len(tokens) > 3 and tokens[0] == "ABORTED:":
135             results.solver.status=SolverStatus.aborted
136          elif len(tokens) == 5 and tokens[0] == "Final" and tokens[1] == "Solution:":
137             soln.objective['f'].value = tokens[4]
138             soln.status = SolutionStatus.optimal
139          elif len(tokens) == 3 and tokens[0] == "LP" and tokens[1] == "value=":
140             soln.objective['f'].value = tokens[2]
141             soln.status=SolutionStatus.optimal
142             if results.problem.sense == ProblemSense.minimize:
143                results.problem.lower_bound = tokens[2]
144             else:
145                results.problem.upper_bound = tokens[2]
146          elif len(tokens) == 2 and tokens[0] == "Bound:":
147             if results.problem.sense == ProblemSense.minimize:
148                results.problem.lower_bound = tokens[1]
149             else:
150                results.problem.upper_bound = tokens[1]
151          elif len(tokens) == 3 and tokens[0] == "Created":
152             results.solver.statistics.branch_and_bound.number_of_created_subproblems = tokens[1]
153          elif len(tokens) == 3 and tokens[0] == "Bounded":
154             results.solver.statistics.branch_and_bound.number_of_bounded_subproblems = tokens[1]
155          elif len(tokens) == 2 and tokens[0] == "sys":
156             results.solver.system_time=tokens[1]
157          elif len(tokens) == 2 and tokens[0] == "user":
158             results.solver.user_time=tokens[1]
159          elif len(tokens) == 3 and tokens[0] == "Solving" and tokens[1] == "problem:":
160             results.problem.name = tokens[2]
161          elif len(tokens) == 4 and tokens[2] == "constraints:":
162             results.problem.number_of_constraints = tokens[3]
163          elif len(tokens) == 4 and tokens[2] == "variables:":
164             results.problem.number_of_variables = tokens[3]
165          elif len(tokens) == 4 and tokens[2] == "nonzeros:":
166             results.problem.number_of_nonzeros = tokens[3]
167          elif len(tokens) == 3 and tokens[1] == "Sense:":
168             if tokens[2] == "minimization":
169                results.problem.sense = ProblemSense.minimize
170             else:
171                results.problem.sense = ProblemSense.maximize
172
173        if results.solver.status is SolverStatus.aborted:
174           soln.optimality=SolutionStatus.unsure
175        if soln.status is SolutionStatus.optimal:
176           soln.gap=0.0
177           if results.problem.sense == ProblemSense.minimize:
178                results.problem.lower_bound = soln.objective['f'].value
179                if "upper_bound" in dir(results.problem):
180                    del results.problem.upper_bound
181           else:
182                results.problem.upper_bound = soln.objective['f'].value
183                if "lower_bound" in dir(results.problem):
184                    del results.problem.lower_bound
185        if results.solver.status is SolverStatus.error:
186           results.solution.delete(0)
187        return results
188
189    def process_soln_file(self,results):
190
191        if self._results_format is ResultsFormat.sol:
192           return
193
194        # the only suffixes that we extract from PICO are
195        # constraint duals. scan through the solver suffix
196        # list and throw an exception if the user has
197        # specified any others.
198        extract_duals = False
199        for suffix in self.suffixes:
200           if re.match(suffix,"dual"):
201              extract_duals = True
202           else:
203              raise RuntimeError,"***PICO solver plugin cannot extract solution suffix="+suffix
204
205        #if os.path.exists(self.sol_file):
206            #results_reader = ReaderFactory(ResultsFormat.sol)
207            #results = results_reader(self.sol_file, results, results.solution(0))
208            #return
209
210        if not os.path.exists(self.soln_file):
211           return
212        soln = results.solution(0)
213        results.problem.num_objectives=1
214        tmp=[]
215        flag=False
216        INPUT = open(self.soln_file,"r")
217        lp_flag=None
218        for line in INPUT:
219            tokens = re.split('[ \t]+',line.strip())
220            if len(tokens) == 0 or (len(tokens) == 1 and tokens[0]==''):
221                continue
222            if tokens[0] == "Objective":
223                continue
224            #print "LINE",tokens
225            if lp_flag is None:
226                lp_flag = (tokens[0] == "LP")
227                continue
228            if tokens[0] == "Dual" and tokens[1] == "solution:":
229                # It looks like we've just been processing primal
230                # variables.
231                for (var,val) in tmp:
232                    soln.variable[var] = val
233                tmp=[]
234                continue
235            if len(tokens) < 3:
236                print "ERROR", line,tokens
237            tmp.append( (tokens[0],eval(tokens[2])) )
238        if (lp_flag is True) and (extract_duals is True):
239            for (var,val) in tmp:
240                soln.constraint[var].dual = val
241        else:
242            for (var,val) in tmp:
243                soln.variable[var] = val
244        INPUT.close()
245
246
247class MockPICO(PICO,mockmip.MockMIP):
248    """A Mock PICO solver used for testing
249    """
250
251    def __init__(self, **kwds):
252        try:
253           PICO.__init__(self,**kwds)
254        except pyutilib.common.ApplicationError: #pragma:nocover
255           pass                        #pragma:nocover
256        mockmip.MockMIP.__init__(self,"pico")
257
258    def available(self, exception_flag=True):
259        return PICO.available(self,exception_flag)
260
261    def create_command_line(self,executable,problem_files):
262        command = PICO.create_command_line(self,executable,problem_files)
263        mockmip.MockMIP.create_command_line(self,executable,problem_files)
264        return command
265
266    def executable(self):
267        return mockmip.MockMIP.executable(self)
268
269    def _execute_command(self,cmd):
270        return mockmip.MockMIP._execute_command(self,cmd)
271
272
273pyutilib.services.register_executable(name="pico")
274SolverRegistration("pico", PICO)
275SolverRegistration("_mock_pico", MockPICO)
Note: See TracBrowser for help on using the repository browser.