source: trunk/coopr/opt/base/solver.py @ 1768

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

Rework of Coopr to use the new PyUtilib? package decomposition.

NOTE: to use Coopr with this update, we need to work with a new version of coopr_install.

File size: 7.4 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__all__ = ['ISolverRegistration', 'SolverRegistration',
12            'IOptSolver', 'OptSolver', 'SolverFactory']
13
14import os
15import sys
16from convert import convert_problem
17from formats import ResultsFormat, ProblemFormat
18import results
19from solution import SolverResults, SolverStatus
20from pyutilib.enum import Enum
21from pyutilib.plugin.core import *
22from pyutilib.plugin.config import *
23import pyutilib.common
24import pyutilib.misc
25
26
27class ISolverRegistration(Interface):
28    """An interface for accessing"""
29
30    def create(self, name=None):
31        """Create a solver, optionally specifying the name"""
32
33    def type(self):
34        """The type of solver supported by this service"""
35
36
37class SolverRegistration(Plugin):
38
39    implements(ISolverRegistration)
40
41    def __init__(self, type, cls):
42        self.name = type
43        self._type = type
44        self._cls = cls
45
46    def type(self):
47        return self._type
48
49    def create(self, **kwds):
50        return self._cls(**kwds)
51
52
53def SolverFactory(solver_name=None, **kwds):
54    ep = ExtensionPoint(ISolverRegistration)
55    if solver_name is None:
56        return map(lambda x:x.name, ep())
57    service = ep.service(solver_name)
58    if service is None:
59        ##print "Unknown solver=" + solver_name + " - no plugin registered for this solver type"
60        return None
61    else:
62        return ep.service(solver_name).create(**kwds)
63
64
65class IOptSolver(Interface):
66    """Interface class for creating optimization solvers"""
67
68    def available(self, exception_flag=True):
69        """Determine if this optimizer is available."""
70
71    def solve(self, *args, **kwds):
72        """Perform optimization and return an SolverResults object."""
73
74    def reset(self):
75        """Reset the state of an optimizer"""
76
77    def set_options(self, istr):
78        """Set the options in the optimizer from a string."""
79
80
81class OptSolver(ManagedPlugin):
82    """A generic optimization solver"""
83
84    implements(IOptSolver)
85
86    def __init__(self, **kwds):
87        """ Constructor """
88        ManagedPlugin.__init__(self,**kwds)
89        #
90        # The 'type' is the class type of the solver instance
91        #
92        if "type" in kwds:
93            self.type = kwds["type"]
94        else:                           #pragma:nocover
95            raise PluginError, "Expected option 'type' for OptSolver constructor"
96        #
97        # The 'name' is either the class type of the solver instance, or a
98        # assigned name.
99        #
100        if "name" in kwds:
101            self.name = kwds["name"]
102        else:
103            self.name = self.type
104        if "doc" in kwds:
105            self._doc = kwds["doc"]
106        else:
107            if self.type is None:           # pragma:nocover
108                self._doc = ""
109            elif self.name == self.type:
110                self._doc = "%s OptSolver" % self.name
111            else:
112                self._doc = "%s OptSolver (type %s)" % (self.name,self.type)
113        declare_option("options", cls=DictOption, section=self.name, doc=self._doc)
114        if 'options' in kwds:
115            for key in kwds['options']:
116                setattr(self.options,key,kwds['options'][key])
117        self._problem_format=None
118        self._results_format=None
119        self._valid_problem_formats=[]
120        self._valid_result_formats={}
121        self.results_reader=None
122        self.problem=None
123        self._assert_available=False
124
125    def available(self, exception_flag=True):
126        """ True if the solver is available """
127        if self._assert_available:
128            return True
129        tmp = self.enabled()
130        if exception_flag and not tmp:
131            raise pyutilib.common.ApplicationError, "OptSolver plugin %s is disabled" % self.name
132        return tmp
133
134    def solve(self, *args, **kwds):
135        """ Solve the problem """
136        self._presolve(*args, **kwds)
137        self._apply_solver()
138        return self._postsolve()
139
140    def _presolve(self, *args, **kwds):
141        self.available()
142        self._timelimit=None
143        self.tee=None
144        for key in kwds:
145          if key == "pformat":
146             self._problem_format=kwds[key]
147          elif key == "rformat":
148             self._results_format=kwds[key]
149          elif key == "logfile":
150             self.log_file=kwds[key]
151          elif key == "solnfile":
152             self.soln_file=kwds[key]
153          elif key == "timelimit":
154             self._timelimit=kwds[key]
155          elif key == "tee":
156             self.tee=kwds[key]
157          elif key == "options":
158             self.set_options(kwds[key])
159          elif key == "available":
160             self._assert_available=True
161          else:
162             raise ValueError, "Unknown option="+key+" for solver="+self.type
163
164        (self._problem_files,self._problem_format) = self._convert_problem(args, self._problem_format, self._valid_problem_formats)
165        if self._results_format is None:
166           self._results_format= self._default_results_format(self._problem_format)
167        if self._results_format not in self._valid_result_formats[self._problem_format]:
168           raise ValueError, "Results format `"+str(self._results_format)+"' cannot be used with problem format `"+str(self._problem_format)+"' in solver "+self.name
169        if self._results_format == ResultsFormat.log:
170            self.results_reader = None
171        else:
172            self.results_reader = results.ReaderFactory(self._results_format)
173
174    def _apply_solver(self):
175        """The routine that performs the solve"""
176        raise NotImplementedError       #pragma:nocover
177       
178    def _postsolve(self):
179        """The routine that does solve post-processing"""
180        return self.results
181       
182    def _convert_problem(self, args, pformat, valid_pformats):
183        #
184        # If the problem is not None, then we assume that it has already
185        # been appropriately defined.  Either it's a string name of the
186        # problem we want to solve, or its a functor object that we can
187        # evaluate directly.
188        #
189        if self.problem is not None:
190           return (self.problem,ProblemFormat.colin_optproblem)
191        #
192        # Otherwise, we try to convert the object explicitly.
193        #
194        return convert_problem(args, pformat, valid_pformats)
195
196    def _default_results_format(self, prob_format):
197        """Returns the default results format for different problem
198            formats.
199        """
200        return ResultsFormat.results
201
202    def reset(self):
203        """
204        Reset the state of the solver
205        """
206        pass
207
208    def set_options(self, istr):
209        istr = istr.strip()
210        if istr is '':
211            return
212        tokens = pyutilib.misc.quote_split('[ ]+',istr)
213        for token in tokens:
214            index = token.find('=')
215            if index is -1:
216                raise ValueError, "Solver options must have the form option=value"
217            try:
218                val = eval(token[(index+1):])
219            except:
220                val = token[(index+1):]
221            setattr(self.options, token[:index], val)
222           
223           
224   
Note: See TracBrowser for help on using the repository browser.