source: trunk/coopr/opt/base/solution.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: 10.1 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__ = ['SolverResults', 'SolverStatus', 'ProblemSense', 'SolutionStatus', 'Solution']
12
13from pyutilib.misc import format_io
14from pyutilib.math import as_numeric
15from pyutilib.enum import Enum
16import sys
17import StringIO
18
19SolverStatus = Enum('error', 'warning', 'ok', 'aborted')
20ProblemSense = Enum('unknown', 'minimize', 'maximize')
21SolutionStatus = Enum('unbounded', 'globallyOptimal', 'locallyOptimal',
22                            'optimal', 'bestSoFar', 'feasible', 'infeasible',
23                            'stoppedByLimit', 'unsure', 'error', 'other')
24
25
26class _SolutionSuffix(object):
27
28    def __init__(self, description):
29        self._info = []
30        self._index = {}
31        self._count = {}
32        self.description = description
33
34    def add(self, index, value):
35        """ NOTE: this function is deprecated """
36        self.__setitem__(index, value)
37
38    def __getitem__(self, key):
39        if isinstance(key,basestring):
40            return self._index[key]
41        return self._count[key]
42
43    def __setitem__(self, index, value):
44        if isinstance(index, basestring):
45            index = index.replace('(','[')
46            index = index.replace(')',']')
47        if type(value) is str:
48           tmp = eval(value)
49        else:
50           tmp = value
51        self._count[len(self._info)]=tmp
52        self._info.append( (index, tmp) )
53        self._index[index]=tmp
54        #
55        # If the index has the format x(1,a) or x[3,4,5]
56        # then create a dictionary attribute 'x', which maps
57        # the tuple values to the corresponding value.
58        #
59        if isinstance(index, basestring):
60            if '[' in index:
61                pieces = index.split('[')
62                name = pieces[0]
63                rest = None
64                # when a variable is indexed by more than one parameter, you will
65                # see identifiers of the form "x((a,b))" instead of the "x(a)"
66                # one-dimensional form. this is due to the process of "stringifying"
67                # the index, which is fine. it just requires a bit of ugliness in
68                # the string splitting process.
69                if index.count("]") == 2:
70                   rest = pieces[2]
71                else:
72                   rest = pieces[1]
73                # we're always taking the first part of the index,
74                # so even in the two (or greater) dimensional case
75                # such as "x((a,b))", the first piece is what we want.
76                tpl = rest.split(']')[0]
77                tokens = tpl.split(',')
78                for i in xrange(len(tokens)):
79                    tokens[i] = as_numeric(tokens[i])
80                try:
81                    var = getattr(self, name)
82                except Exception, err:
83                    setattr(self, name, {})
84                    var = getattr(self, name)
85                if len(tokens) == 1:
86                    var[ tokens[0] ] = tmp
87                else:
88                    var[ tuple(tokens) ] = tmp
89            else:
90                setattr(self, index, tmp)
91           
92           
93
94    def __len__(self):
95        return len(self._info)
96
97    def __iter__(self):
98        return self._info.__iter__()
99
100    def pprint(self, ostream=None):
101        if ostream is None:
102           ostream = sys.stdout
103        if len(self._info) != 0:
104           print >>ostream, "  "+self.description
105           flag=True
106           for (name,value) in self._info:
107             if value != 0:
108                print >>ostream, "        "+str(name)+"\t"+format_io(value)
109                flag=False
110           if flag:
111              print >>ostream,   "        No nonzero values"
112
113
114class Solution(object):
115
116    def __init__(self):
117        self.__dict__["_suffix"] = []
118        self.value = None
119        self.gap = None
120        self.status = SolutionStatus.unsure
121        self.add_suffix("variable","Primal Variables")
122        self.add_suffix("dual","Dual Variables")
123        self.add_suffix("slack","Constraint Slacks")
124        self.add_suffix("constraint","Constraint Values")
125
126    def __getattr__(self, name):
127        try:
128            if name in self.__dict__['_suffix']:
129                return self.__dict__["_"+name]
130        except KeyError:
131            pass
132        try:
133           return self.__dict__[name]
134        except KeyError:
135           raise AttributeError, "Unknown attribute "+str(name)
136
137    def __setattr__(self, name, val):
138        if name in self._suffix:
139           raise AttributeError, "Cannot set attribute '"+name+"' which is reserved for suffix array"
140        self.__dict__[name]=val
141
142    def add_suffix(self,name,description):
143        self._suffix.append(name)
144        setattr(self, "_"+name, _SolutionSuffix(description))
145
146    def pprint(self, ostream=None, only_variables=False):
147        if ostream is None:
148           ostream = sys.stdout
149        print >>ostream, "----------------------------------------------------------"
150        print >>ostream, "------  Solution "+ str(self._counter+1)
151        print >>ostream, "----------------------------------------------------------"
152        tmp = self.__dict__.keys()
153        tmp.sort()
154        for key in tmp:
155          if key[0] != "_":
156             if key != "value":
157                print >>ostream, " ",key+":", format_io(getattr(self, key))
158             else:
159                tmp = getattr(self,key)
160                if isinstance(tmp, dict):
161                   print >>ostream, "  Objectives"
162                   for vkey in tmp:
163                     print >>ostream, "        "+str(vkey)+"\t"+format_io(tmp[vkey])
164                else:
165                   print >>ostream, "  value:",format_io(tmp)
166                   
167        for item in self._suffix:
168            if only_variables and item != "variable":
169                continue
170            getattr(self,"_"+item).pprint(ostream=ostream)
171
172
173class SolutionSet(object):
174
175    def __init__(self):
176        self._solution={}
177        self._counter=0
178        self._ndx=[]
179
180    def __len__(self):
181        return len(self._solution)
182
183    def __getitem__(self,i):
184        return self._solution[i]
185
186    def __call__(self,i=0):
187        return self._solution[self._ndx[i]]
188
189    def create(self):
190        tmp = Solution()
191        self.insert(tmp)
192        return tmp
193
194    def insert(self,solution):
195        solution._counter = self._counter
196        self._solution[self._counter] = solution
197        self._ndx.append(self._counter)
198        self._counter += 1
199
200    def delete(self,i):
201        del self._solution[i]
202        self._ndx.remove(i)
203
204
205class _Data_Container(object):
206    pass
207
208
209class SolverResults(object):
210
211    def __init__(self):
212        self.solver = _Data_Container()
213        self.problem = _Data_Container()
214        self.solution = SolutionSet()
215        self.initialize()
216
217    def initialize(self):
218        #
219        # Standard solver information
220        #
221        self.solver.status=SolverStatus.ok
222        self.solver.systime=None
223        self.solver.usrtime=None
224        #
225        # Standard problem information
226        #
227        self.problem.name=None
228        self.problem.sense=ProblemSense.unknown
229        self.problem.num_variables=None
230        self.problem.num_constraints=None
231        self.problem.num_objectives=None
232        self.problem.lower_bound=None
233        self.problem.upper_bound=None
234
235    def __str__(self):
236        output = StringIO.StringIO()
237        self.write(ostream=output, num=sys.maxint)
238        return output.getvalue()
239       
240    def write(self, filename=None, num=1, ostream=None, times=True, only_variables=False):
241        if ostream is None:
242           ostream = sys.stdout
243        if not filename is None:
244           OUTPUT=open(filename,"w")
245           self.write(num=num,ostream=OUTPUT,times=times)
246           OUTPUT.close()
247           return
248
249        print >>ostream, "=========================================================="
250        print >>ostream, "---  Solver Results                                    ---"
251        print >>ostream, "=========================================================="
252        print >>ostream, "----------------------------------------------------------"
253        print >>ostream, "------  Problem Information                         ------"
254        print >>ostream, "----------------------------------------------------------"
255        flag=False
256        tmp = self.problem.__dict__.keys()
257        tmp.sort()
258        for key in tmp:
259          if key[0] != "_":
260             print >>ostream, " ",key+":", format_io(getattr(self.problem, key))
261             flag=True
262        if not flag:        # pragma:nocover
263           print >>ostream, "  No Info"
264        #
265        print >>ostream, "----------------------------------------------------------"
266        print >>ostream, "------  Solver Information                          ------"
267        print >>ostream, "----------------------------------------------------------"
268        flag=False
269        tmp = self.solver.__dict__.keys()
270        tmp.sort()
271        for key in tmp:
272          if key[0] != "_":
273             if times or not key in ["systime","usrtime"]:
274                print >>ostream, " ",key+":", format_io(getattr(self.solver, key))
275             flag=True
276        if not flag:        # pragma:nocover
277           print >>ostream, "  No Info"
278        #
279        if not num is None:
280           print >>ostream, "  num_solutions: "+str(len(self.solution))
281           i=0
282           while i<min(num, len(self.solution)):
283             self.solution(i).pprint(ostream, only_variables=only_variables)
284             i += 1
285        else:
286           print >>ostream, "  num_solutions to display: 0"
287        print >>ostream, "----------------------------------------------------------"
288
289    def read(self, filename=None):          #pragma:nocover
290        raise IOError, "SolverResults.read is not defined!"
291
Note: See TracBrowser for help on using the repository browser.