source: coopr.opt/trunk/coopr/opt/results/solution.py @ 2109

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

Changing the API of the SolutionSet? object. Now, all variables, constraints, etc
can be indexed with 1-based integer indices (rather than 0-based). This change
makes this object consistent with the 1-based indexing API supported by Pyomo.

File size: 9.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#  _________________________________________________________________________
9
10__all__ = ['SolutionStatus', 'Solution']
11
12import math
13from container import *
14from pyutilib.misc import Bunch
15from pyutilib.enum import Enum
16from pyutilib.math import as_number
17
18default_print_options = Bunch(schema=False, sparse=True, num_solutions=None, ignore_time=False)
19
20SolutionStatus = Enum('globallyOptimal', 'locallyOptimal',
21                            'optimal', 'bestSoFar', 'feasible', 'infeasible', 'stoppedByLimit',
22                            'unknown', 'unsure', 'error', 'other')
23
24
25class SolutionMap(MapContainer):
26
27    def __init__(self, sparse=True):
28        MapContainer.__init__(self)
29        self._sparse=sparse
30        self._names = {}
31        self._prefix='x'
32        self._option = default_print_options
33
34    def __getitem__(self, name):
35        tmp = self._convert(name)
36        try:
37            return self.__dict__[tmp]
38        except:
39            pass
40        if type(name) in (int,long):
41            self.declare_item(tmp-1)
42        else:
43            self.declare_item(tmp)
44        if type(tmp) is int:
45            tmp = self._names[tmp-1]
46        item = dict.__getitem__(self, tmp)
47        if isinstance(item,ListContainer) or isinstance(item,MapContainer):
48            return item
49        return item.value
50
51    def _set_value(self, name, val):
52        #print "_set_value",name,val
53        if isinstance(name,basestring):
54            self.declare_item(name)
55        elif type(name) is int:
56            self.declare_item(name-1)
57        if type(name) is int:
58            name = self._names[name-1]
59        dict.__getitem__(self, name).value = as_number(val)
60        #print "_set_value",dict.__getitem__(self, name).value
61
62    def declare(self, name, **kwds):
63        if type(name) is int:
64            return
65        self.declare_item(name)
66
67    def declare_item(self, name, id=None):
68        self._active=True
69        if name in self:
70            return
71        if type(name) is int:
72            id = name
73            try:
74                name = self._names[name]
75            except:
76                name = self._prefix+str(name)
77        else:
78            if id is None:
79                id = len(self._names)
80        if name in self:
81            return
82        #print "DECL3",name
83        MapContainer.declare(self, name, value=MapContainer())
84        dict.__getitem__(self, name).id = id
85        self._names[id] = name
86        #
87        # If the name has the format x(1,a) or x[3,4,5]
88        # then create a dictionary attribute 'x', which maps
89        # the tuple values to the corresponding value.
90        #
91        if isinstance(name, basestring):
92            if '[' in name:
93                pieces = name.split('[')
94                varname = pieces[0]
95                rest = None
96                # when a variable is indexed by more than one parameter, you will
97                # see identifiers of the form "x((a,b))" instead of the "x(a)"
98                # one-dimensional form. this is due to the process of "stringifying"
99                # the name, which is fine. it just requires a bit of ugliness in
100                # the string splitting process.
101                if name.count("]") == 2:
102                   rest = pieces[2]
103                else:
104                   rest = pieces[1]
105                # we're always taking the first part of the name,
106                # so even in the two (or greater) dimensional case
107                # such as "x((a,b))", the first piece is what we want.
108                tpl = rest.split(']')[0]
109                tokens = tpl.split(',')
110                for i in xrange(len(tokens)):
111                    tokens[i] = as_number(tokens[i])
112                try:
113                    #print "GETTING",varname
114                    var = self.__dict__[varname]
115                    #var = dict.__getitem__(self, varname)
116                except Exception, err:
117                    #print "SETTING",varname
118                    self.__dict__[varname]={}
119                    var = self.__dict__[varname]
120                    #dict.__setitem__(self, varname, {})
121                    #var = dict.__getitem__(self, varname)
122                if len(tokens) == 1:
123                    var[ tokens[0] ] = dict.__getitem__(self, name)
124                else:
125                    #print "SETTING",varname,tokens,tuple(tokens)
126                    var[ tuple(tokens) ] = dict.__getitem__(self, name)
127            #else:
128                #self.__dict__[name]=dict.__getitem__(self, name)
129
130    def _convert(self, name):
131        if isinstance(name, basestring):
132            name = name.replace('(','[')
133            name = name.replace(')',']')
134        return name
135
136    def _repn_(self, option):
137        #print "SOLUTION",self._active,self._required
138        if not option.schema and not self._active and not self._required:
139            return ignore
140        if option.schema:
141            self[0] = 1.0
142            self[1] = 2.0
143            self[2] = 3.0
144            #print dict.keys(self)
145            #print self.keys()
146        tmp = {}
147        keys = self._names.keys()
148        keys.sort()
149        for i in keys:
150            key = self._names[i]
151            rep = dict.__getitem__(self, key)._repn_(option)
152            #print "HERE",type(dict.__getitem__(self, key))
153            #print "HERE",repr(dict.__getitem__(self, key))
154            #print "HERE",rep
155            if not rep == ignore:
156                if option.sparse and self._sparse:
157                    trep = {}
158                    for tkey in rep:
159                        if tkey == 'Id':
160                            trep[tkey] = rep[tkey]
161                            continue
162                        if not type(rep[tkey]) in (float,int,long) or math.fabs(rep[tkey]) > 1e-16:
163                            trep[tkey] = rep[tkey]
164                    if len(trep.keys()) > 1:
165                        tmp[key] = trep
166                else:
167                    tmp[key] = rep
168        if tmp == {}:
169            return "No nonzero values"
170        return tmp
171
172    def pprint(self, ostream, option, from_list=False, prefix="", repn=None):
173        if isinstance(repn,basestring):
174            print >>ostream, repn
175        else:
176            MapContainer.pprint(self, ostream, option, from_list=from_list, prefix=prefix, repn=repn)
177
178    def load(self, repn):
179        if isinstance(repn, basestring):
180            return
181        index = {}
182        for key in repn:
183            index[repn[key]['Id']] = key
184        keys = index.keys()
185        keys.sort()
186        for key in keys:
187            self.declare_item(index[key], id=key)
188            for elt in repn[index[key]]:
189                if elt == 'Id':
190                    continue
191                dict.__getitem__(self, index[key])[elt] = repn[index[key]][elt]
192
193
194class Solution(MapContainer):
195
196    def __init__(self):
197        MapContainer.__init__(self)
198
199        self.declare('gap')
200        self.declare('status', value=SolutionStatus.unknown)
201        self.declare('message')
202
203        self.declare('objective', value=SolutionMap(sparse=False), active=False)
204        self.declare('variable', value=SolutionMap(), active=False)
205        self.declare('constraint', value=SolutionMap(), active=False)
206
207        self._option = default_print_options
208
209
210class SolutionSet(ListContainer):
211
212    def __init__(self):
213        ListContainer.__init__(self,Solution)
214        self._option = default_print_options
215
216    def _repn_(self, option):
217        if not option.schema and not self._active and not self._required:
218            return ignore
219        if option.schema and len(self) == 0:
220            self.add()
221            self.add()
222        if option.num_solutions is None:
223            num = len(self)
224        else:
225            num = min(num, len(self))
226        i=0
227        tmp = []
228        for item in self._list:
229            tmp.append( item._repn_(option) )
230            i=i+1
231            if i == num:
232                break
233        return [{'number of solutions':len(self), 'number of solutions displayed':num}]+ tmp
234
235    def __len__(self):
236        return len(self._list)
237
238    def __call__(self, i=1):
239        return self._list[i-1]
240
241    def pprint(self, ostream, option, prefix="", repn=None):
242        if not option.schema and not self._active and not self._required:
243            return ignore
244        print >>ostream, ""
245        print >>ostream, prefix+"-",
246        spaces=""
247        for key in repn[0]:
248            print >>ostream, prefix+spaces+key+":",repn[0][key]
249            spaces="  "
250        i=0
251        for i in xrange(len(self._list)):
252            item = self._list[i]
253            print >>ostream, prefix+'-',
254            item.pprint(ostream, option, from_list=True, prefix=prefix+"  ", repn=repn[i+1])
255
256    def load(self, repn):
257        #
258        # Note: we ignore the first element of the repn list, since
259        # it was generated on the fly by the SolutionSet object.
260        #
261        for data in repn[1:]:
262            item = self.add()
263            item.load(data)
264
Note: See TracBrowser for help on using the repository browser.