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

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

Reworking MIP plugins to more selectively print
branch-and-bound information. Don't print
this info unless solving a MIP.

File size: 10.5 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.plugin.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.plugin.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        #print "HERE",self._results_format, self._results_format is ResultsFormat.sol, self.results_reader
191        if self._results_format is ResultsFormat.sol:
192           return
193
194        #if os.path.exists(self.sol_file):
195            #results_reader = ReaderFactory(ResultsFormat.sol)
196            #results = results_reader(self.sol_file, results, results.solution(0))
197            #return
198
199        if not os.path.exists(self.soln_file):
200           return
201        soln = results.solution(0)
202        results.problem.num_objectives=1
203        tmp=[]
204        flag=False
205        INPUT = open(self.soln_file,"r")
206        lp_flag=None
207        for line in INPUT:
208            tokens = re.split('[ \t]+',line.strip())
209            if len(tokens) == 0 or (len(tokens) == 1 and tokens[0]==''):
210                continue
211            if tokens[0] == "Objective":
212                continue
213            #print "LINE",tokens
214            if lp_flag is None:
215                lp_flag = (tokens[0] == "LP")
216                continue
217            if tokens[0] == "Dual" and tokens[1] == "solution:":
218                # It looks like we've just been processing primal
219                # variables.
220                for (var,val) in tmp:
221                    soln.variable[var] = val
222                tmp=[]
223                continue
224            if len(tokens) < 3:
225                print "ERROR", line,tokens
226            tmp.append( (tokens[0],eval(tokens[2])) )
227        if lp_flag:
228            for (var,val) in tmp:
229                soln.constraint[var].dual = val
230        else:
231            for (var,val) in tmp:
232                soln.variable[var] = val
233        INPUT.close()
234
235
236class MockPICO(PICO,mockmip.MockMIP):
237    """A Mock PICO solver used for testing
238    """
239
240    def __init__(self, **kwds):
241        try:
242           PICO.__init__(self,**kwds)
243        except pyutilib.common.ApplicationError: #pragma:nocover
244           pass                        #pragma:nocover
245        mockmip.MockMIP.__init__(self,"pico")
246
247    def available(self, exception_flag=True):
248        return PICO.available(self,exception_flag)
249
250    def create_command_line(self,executable,problem_files):
251        command = PICO.create_command_line(self,executable,problem_files)
252        mockmip.MockMIP.create_command_line(self,executable,problem_files)
253        return command
254
255    def executable(self):
256        return mockmip.MockMIP.executable(self)
257
258    def _execute_command(self,cmd):
259        return mockmip.MockMIP._execute_command(self,cmd)
260
261
262pyutilib.services.register_executable(name="pico")
263SolverRegistration("pico", PICO)
264SolverRegistration("_mock_pico", MockPICO)
Note: See TracBrowser for help on using the repository browser.