Package paramz :: Package core :: Module index_operations
[hide private]
[frames] | no frames]

Source Code for Module paramz.core.index_operations

  1  #=============================================================================== 
  2  # Copyright (c) 2015, Max Zwiessele 
  3  # All rights reserved. 
  4  #  
  5  # Redistribution and use in source and binary forms, with or without 
  6  # modification, are permitted provided that the following conditions are met: 
  7  #  
  8  # * Redistributions of source code must retain the above copyright notice, this 
  9  #   list of conditions and the following disclaimer. 
 10  #  
 11  # * Redistributions in binary form must reproduce the above copyright notice, 
 12  #   this list of conditions and the following disclaimer in the documentation 
 13  #   and/or other materials provided with the distribution. 
 14  #  
 15  # * Neither the name of paramax nor the names of its 
 16  #   contributors may be used to endorse or promote products derived from 
 17  #   this software without specific prior written permission. 
 18  #  
 19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 22  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
 23  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 24  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 25  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 26  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 27  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 28  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29  #=============================================================================== 
 30   
 31  import numpy 
 32  from numpy.lib.function_base import vectorize 
 33  from .lists_and_dicts import IntArrayDict 
 34  from functools import reduce 
35 36 -def extract_properties_to_index(index, props):
37 prop_index = dict() 38 for i, cl in enumerate(props): 39 for c in cl: 40 ind = prop_index.get(c, list()) 41 ind.append(index[i]) 42 prop_index[c] = ind 43 44 for c, i in prop_index.items(): 45 prop_index[c] = numpy.array(i, dtype=int) 46 47 return prop_index
48
49 50 -class ParameterIndexOperations(object):
51 """ 52 This object wraps a dictionary, whos keys are _operations_ that we'd like 53 to apply to a parameter array, and whose values are np integer arrays which 54 index the parameter array appropriately. 55 56 A model instance will contain one instance of this class for each thing 57 that needs indexing (i.e. constraints, ties and priors). Parameters within 58 the model constain instances of the ParameterIndexOperationsView class, 59 which can map from a 'local' index (starting 0) to this global index. 60 61 Here's an illustration:: 62 63 #======================================================================= 64 model : 0 1 2 3 4 5 6 7 8 9 65 key1: 4 5 66 key2: 7 8 67 68 param1: 0 1 2 3 4 5 69 key1: 2 3 70 key2: 5 71 72 param2: 0 1 2 3 4 73 key1: 0 74 key2: 2 3 75 #======================================================================= 76 77 The views of this global index have a subset of the keys in this global 78 (model) index. 79 80 Adding a new key (e.g. a constraint) to a view will cause the view to pass 81 the new key to the global index, along with the local index and an offset. 82 This global index then stores the key and the appropriate global index 83 (which can be seen by the view). 84 85 See also: 86 ParameterIndexOperationsView 87 88 """ 89 _offset = 0
90 - def __init__(self, constraints=None):
91 self._properties = IntArrayDict() 92 if constraints is not None: 93 #python 3 fix 94 for t, i in constraints.items(): 95 self.add(t, i)
96
97 - def items(self):
98 for i, ind in self._properties.items(): 99 if ind.size > 0: 100 yield i, ind
101
102 - def properties(self):
103 return [i[0] for i in self.items()]
104
105 - def indices(self):
106 return [i[1] for i in self.items()]
107
108 - def shift_right(self, start, size):
109 for ind in self.indices(): 110 toshift = ind>=start 111 ind[toshift] += size
112
113 - def shift_left(self, start, size):
114 for v, ind in list(self.items()): 115 todelete = (ind>=start) * (ind<start+size) 116 if todelete.sum() != 0: 117 ind = ind[~todelete] 118 toshift = ind>=start 119 if toshift.size != 0: 120 ind[toshift] -= size 121 if ind.size != 0: self._properties[v] = ind 122 else: del self._properties[v]
123
124 - def clear(self):
125 self._properties.clear()
126 127 @property
128 - def size(self):
129 return sum([i.size for i in self.indices()])
130 131
132 - def properties_for(self, index):
133 """ 134 Returns a list of properties, such that each entry in the list corresponds 135 to the element of the index given. 136 137 Example: 138 let properties: 'one':[1,2,3,4], 'two':[3,5,6] 139 140 >>> properties_for([2,3,5]) 141 [['one'], ['one', 'two'], ['two']] 142 """ 143 return vectorize(lambda i: [prop for prop in self.properties() if i in self[prop]], otypes=[list])(index)
144
145 - def properties_dict_for(self, index):
146 """ 147 Return a dictionary, containing properties as keys and indices as index 148 Thus, the indices for each constraint, which is contained will be collected as 149 one dictionary 150 151 Example: 152 let properties: 'one':[1,2,3,4], 'two':[3,5,6] 153 154 >>> properties_dict_for([2,3,5]) 155 {'one':[2,3], 'two':[3,5]} 156 """ 157 props = self.properties_for(index) 158 prop_index = extract_properties_to_index(index, props) 159 return prop_index
160
161 - def add(self, prop, indices):
162 self._properties[prop] = combine_indices(self._properties[prop], indices)
163
164 - def remove(self, prop, indices):
165 if prop in self._properties: 166 diff = remove_indices(self[prop], indices) 167 removed = numpy.intersect1d(self[prop], indices, True) 168 if not index_empty(diff): 169 self._properties[prop] = diff 170 else: 171 del self._properties[prop] 172 return removed.astype(int) 173 return numpy.array([]).astype(int)
174
175 - def update(self, parameter_index_view, offset=0):
176 #py3 fix 177 for i, v in parameter_index_view.items(): 178 self.add(i, v+offset)
179
180 - def copy(self):
181 return self.__deepcopy__(None)
182
183 - def __deepcopy__(self, memo):
184 #py3 fix 185 return ParameterIndexOperations(dict(self.items()))
186
187 - def __getitem__(self, prop):
188 return self._properties[prop]
189
190 - def __delitem__(self, prop):
191 del self._properties[prop]
192
193 - def __str__(self, *args, **kwargs):
194 import pprint 195 return pprint.pformat(dict(self._properties))
196
197 -def combine_indices(arr1, arr2):
198 return numpy.union1d(arr1, arr2)
199
200 -def remove_indices(arr, to_remove):
201 return numpy.setdiff1d(arr, to_remove, True)
202
203 -def index_empty(index):
204 return numpy.size(index) == 0
205
206 -class ParameterIndexOperationsView(object):
207 - def __init__(self, param_index_operations, offset, size):
208 self._param_index_ops = param_index_operations 209 self._offset = offset 210 self._size = size
211
212 - def __getstate__(self):
213 return [self._param_index_ops, self._offset, self._size]
214
215 - def __setstate__(self, state):
216 self._param_index_ops = state[0] 217 self._offset = state[1] 218 self._size = state[2]
219
220 - def _filter_index(self, ind):
221 return ind[(ind >= self._offset) * (ind < (self._offset + self._size))] - self._offset
222
223 - def items(self):
224 _items_list = self._param_index_ops.items() 225 for i, ind in _items_list: 226 ind2 = self._filter_index(ind) 227 if ind2.size > 0: 228 yield i, ind2
229
230 - def properties(self):
231 return [i[0] for i in self.items()]
232
233 - def indices(self):
234 return [i[1] for i in self.items()]
235
236 - def shift_right(self, start, size):
237 self._param_index_ops.shift_right(start+self._offset, size)
238
239 - def shift_left(self, start, size):
240 self._param_index_ops.shift_left(start+self._offset, size)
241
242 - def clear(self):
243 for i, ind in list(self.items()): 244 self._param_index_ops.remove(i, ind+self._offset)
245 246 @property
247 - def size(self):
248 return sum([i.size for i in self.indices()])
249
250 - def properties_for(self, index):
251 """ 252 Returns a list of properties, such that each entry in the list corresponds 253 to the element of the index given. 254 255 Example: 256 let properties: 'one':[1,2,3,4], 'two':[3,5,6] 257 258 >>> properties_for([2,3,5]) 259 [['one'], ['one', 'two'], ['two']] 260 """ 261 return vectorize(lambda i: [prop for prop in self.properties() if i in self[prop]], otypes=[list])(index)
262
263 - def properties_dict_for(self, index):
264 """ 265 Return a dictionary, containing properties as keys and indices as index 266 Thus, the indices for each constraint, which is contained will be collected as 267 one dictionary 268 269 Example: 270 let properties: 'one':[1,2,3,4], 'two':[3,5,6] 271 272 >>> property_dict_for([2,3,5]) 273 {'one':[2,3], 'two':[3,5]} 274 """ 275 return extract_properties_to_index(index, self.properties_for(index))
276 277
278 - def add(self, prop, indices):
279 self._param_index_ops.add(prop, indices+self._offset)
280 281
282 - def remove(self, prop, indices):
283 removed = self._param_index_ops.remove(prop, numpy.array(indices)+self._offset) 284 if removed.size > 0: 285 return removed-self._offset 286 return removed
287 288
289 - def __getitem__(self, prop):
290 ind = self._filter_index(self._param_index_ops[prop]) 291 return ind
292
293 - def __delitem__(self, prop):
294 self.remove(prop, self[prop])
295
296 - def __str__(self, *args, **kwargs):
297 import pprint 298 #py3 fixes 299 return pprint.pformat(dict(self.items()))
300
301 - def update(self, parameter_index_view, offset=0):
302 #py3 fixes 303 for i, v in parameter_index_view.items(): 304 self.add(i, v+offset)
305 306
307 - def copy(self):
308 return self.__deepcopy__(None)
309
310 - def __deepcopy__(self, memo):
311 #py3 fix 312 return ParameterIndexOperations(dict(self.items()))
313 pass
314