source: trunk/coopr/opt/base/solution.py @ 1794

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

Misc bug fixes that were introduced by the introduction of variable_map
data, which is now called symbol_map.

Note: some tests still fail, due to the fact that pico_convert does not
generate symbol mapping information. This is being resolved.

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