Path: blob/main/tools/contributed/sumopy/agilepy/lib_base/arrayman.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file arrayman.py15# @author Joerg Schweizer16# @date 20121718from classman import *19import numpy as np202122class ArrayConfMixin:23def __init__(self, attrname, default, dtype=None, is_index=False, **attrs):24self._is_index = is_index25self._dtype = dtype26AttrConf.__init__(self, attrname, default,27struct='array',28**attrs)2930if is_index:31self._init_indexing()3233def get_dtype(self):34return self._dtype3536def convert_type(self, array):37return np.array(array, dtype=self._dtype)3839def get_defaults(self, ids):40# create a list, should work for all types and dimensions41# default can be scalar or an array of any dimension42# print '\n\nget_defaults',self._name,ids43default = self.get_default()4445if hasattr(default, '__iter__'):46default = np.asarray(default)47if self._dtype is not None:48dtype = self._dtype49else:50dtype = type(default.flatten()[0])51# print ' default=',default,len(default)52if len(ids) > 0:53defaults = np.array(len(ids)*[default], dtype)54# print ' size,type',len(ids)*[default], type(default.flatten()[0])55else:56#defaults = np.zeros( (0,len(default)),type(default.flatten()[0]) )57defaults = np.zeros((0,)+default.shape, dtype)58# print ' return',defaults,defaults.shape,defaults.dtype59return defaults60else:61if self._dtype is not None:62dtype = self._dtype63else:64dtype = type(default)65#defaults= np.array( len(ids)*[default], dtype )66# print ' return 1D',defaults,defaults.shape,defaults.dtype67return np.array(len(ids)*[default], dtype)6869def get_init(self):70"""71Returns initialization of attribute.72Usually same as get_default for scalars.73Overridden by table configuration classes74"""75ids = self._manager.get_ids()7677# print '\n\nget_init',self.attrname,ids,self._is_localvalue78values = self.get_defaults(ids)7980# store locally if required81if self._is_localvalue:82self.value = values83# pass on to calling instance84# in this cas the data is stored under self._obj85return values8687def get_ids_sorted(self):88inds = self._manager.get_inds()89return self._manager.get_ids(inds[np.argsort(self.get_value()[inds])])9091#sortarray = np.concatenate((self.get_value()[inds],inds))9293def _del_rows(self, ids_del, inds_remain):94"""95Multiple row delete method used by attrsman96"""97self.set_value(self.get_value()[inds_remain])9899def delete_ind(self, i):100# called from del_rows101if self._is_index:102_id = self._manager._ids[i]103self.del_index(_id)104arr = self.get_value()105self.set_value(np.concatenate((arr[:i], arr[i+1:])))106107def __delitem__(self, ids):108# print ' before=\n',self.__dict__[attr]109#attr = self.attrconf.get_attr()110if hasattr(ids, '__iter__'):111for i in self._manager._inds[ids]:112self.delete_ind[i]113else:114self.delete_ind(self._manager._inds[ids])115116def __getitem__(self, ids):117# print '__getitem__',key118return self.get_value()[self._manager._inds[ids]]119120def __setitem__(self, ids, values):121# print '__setitem__',ids,values,type(self.get_value()),self.get_value().dtype122123if self._is_index:124if hasattr(ids, '__iter__'):125self.set_indices(ids, values)126127else:128self.set_index(ids, values)129130self.get_value()[self._manager._inds[ids]] = values131132def set(self, ids, values):133if values is None:134return135136if not hasattr(ids, '__iter__'):137_ids = [ids]138_values = np.array([values], self._dtype)139140else:141_ids = ids142_values = np.array(values, self._dtype)143# print 'set', _ids ,_values144self[_ids] = _values145if self._is_index:146self.set_indices(_ids, _values)147self._is_modified = True148149def set_plugin(self, ids, values):150if not hasattr(ids, '__iter__'):151_ids = [ids]152_values = np.array([values], self._dtype)153154else:155_ids = ids156_values = np.array(values, self._dtype)157158self[ids] = _values159if self._is_index:160self.set_indices(_ids, _values)161self._is_modified = True162self.plugin.exec_events_ids(EVTSETITEM, _ids)163164def add(self, ids, values=None):165if not hasattr(ids, '__iter__'):166_ids = [ids]167if values is not None:168_values = np.array([values], self._dtype)169else:170_values = self.get_defaults(_ids)171172else:173# if values is None:174# print 'WARNING:',self.attrname, ids,self._dtype175_ids = ids176if values is not None:177_values = np.array(values, self._dtype)178else:179_values = self.get_defaults(_ids)180# if values is None:181# _values = self.get_defaults(_ids)182183# print 'add ids',self.attrname,ids,_ids,self._is_modified184# print ' values',values185# print ' _values',_values186# print ' self.get_value()',self.get_value()187# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())188# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape189190#newvalue = np.concatenate((self.get_value(),_values))191# print ' ', type(newvalue),newvalue.dtype192self.set_value(np.concatenate((self.get_value(), _values)))193# print ' done:',self.attrname,self.get_value()194if self._is_index:195self.add_indices(_ids, _values)196self._is_modified = True197198def add_plugin(self, ids, values=None):199# print 'add_plugin',self.attrname200if not hasattr(ids, '__iter__'):201_ids = [ids]202if values is not None:203_values = np.array([values], self._dtype)204205else:206_ids = ids207if values is not None:208_values = np.array(values, self._dtype)209210if values is None:211_values = self.get_defaults(_ids)212self._is_modified = True213# print 'add ids',self.attrname,ids,_ids,self._is_modified214# print ' values',values215# print ' _values',_values216# print ' self.get_value()',self.get_value()217# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())218# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape219220#newvalue = np.concatenate((self.get_value(),_values))221# print ' ', type(newvalue),newvalue.dtype222self.set_value(np.concatenate((self.get_value(), _values)))223# print ' done:',self.attrname,self.get_value()224225if self._is_index:226self.add_indices(_ids, _values)227228self.plugin.exec_events_ids(EVTADDITEM, _ids)229230# use original one from AttrConfig231# def _write_xml_value(self,val,fd):232# #print 'write_xml',self.xmltag,type(val),hasattr(val, '__iter__')233# if hasattr(val, '__iter__'):234# if len(val)>0:235# if hasattr(val[0], '__iter__'):236# # matrix237# fd.write(xm.mat(self.xmltag,val))238# else:239# if type(val)==np.ndarray:240# # vector241# fd.write(xm.arr(self.xmltag,val,sep=','))242# else:243# # list244# fd.write(xm.arr(self.xmltag,val))245# else:246# # empty list247# fd.write(xm.arr(self.xmltag,val))248# else:249# # scalar number or string250# fd.write(xm.num(self.xmltag,val))251252def format_value(self, _id, show_unit=False, show_parentesis=False):253# TODO: handle also linked ids, etc...254if show_unit:255unit = ' '+self.format_unit(show_parentesis)256else:257unit = ''258# return repr(self[_id])+unit259260#self.min = minval261#self.max = maxval262#self.digits_integer = digits_integer263#self.digits_fraction = digits_fraction264val = self[_id]265tt = type(val)266267if tt in (np.int, np.int32, np.float64):268return str(val)+unit269270elif tt in (np.float, np.float32, np.float64):271if hasattr(self, 'digits_fraction'):272digits_fraction = self.digits_fraction273else:274digits_fraction = 3275276s = "%."+str(digits_fraction)+"f"277# print 'format_value df=',digits_fraction,'val=',val278279return s % (val)+unit280281else:282return str(val)+unit283284285class ArrayConf(ArrayConfMixin, ColConf):286"""287Column made of numeric array.288289"""290pass291292293class ListArrayConf(ArrayConfMixin, ColConf):294"""295Column made of an array of lists.296297"""298299def __init__(self, attrname, dtype=None, **attrs):300ArrayConfMixin.__init__(self, attrname, None, dtype=np.object, **attrs)301302def add(self, ids, values=None):303if not hasattr(ids, '__iter__'):304_ids = [ids]305if values is not None:306_values = np.zeros(1, self._dtype)307_values[0] = values308309else:310311_ids = ids312if values is not None:313_values = np.zeros(len(ids), self._dtype)314_values[:] = values315316if values is None:317_values = self.get_defaults(_ids)318319# print 'add ids, _values',self.attrname,ids320# print ' values',values321# print ' _values',_values322# print ' self.get_value()',self.get_value()323# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())324# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape325326newvalue = np.concatenate((self.get_value(), _values))327# print ' ', type(newvalue),newvalue.dtype328self.set_value(np.concatenate((self.get_value(), _values)))329330if self._is_index:331self.add_indices(_ids, _values)332333def add_plugin(self, ids, values=None):334# print 'add_plugin',self.attrname,ids335if not hasattr(ids, '__iter__'):336_ids = [ids]337if values is not None:338_values = np.zeros(1, self._dtype)339_values[0] = values340341else:342343_ids = ids344if values is not None:345_values = np.zeros(len(ids), self._dtype)346_values[:] = values347348if values is None:349_values = self.get_defaults(_ids)350351# print 'add ids, _values',self.attrname,ids352# print ' values',values353# print ' _values',_values354# print ' self.get_value()',self.get_value()355# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())356# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape357358newvalue = np.concatenate((self.get_value(), _values))359# print ' ', type(newvalue),newvalue.dtype360self.set_value(np.concatenate((self.get_value(), _values)))361362if self._is_index:363self.add_indices(_ids, _values)364365if self.plugin:366self.plugin.exec_events_ids(EVTADDITEM, _ids)367368369class NumArrayConf(ArrayConfMixin, ColConf):370"""371Column made of numeric array.372373"""374# def __init__(self, **attrs):375# print 'ColConf',attrs376377def __init__(self, attrname, default,378digits_integer=None, digits_fraction=None,379minval=None, maxval=None,380**attrs):381382self.min = minval383self.max = maxval384self.digits_integer = digits_integer385self.digits_fraction = digits_fraction386387ArrayConfMixin.__init__(self, attrname, default, metatype='number', **attrs)388389def format_value(self, _id, show_unit=False, show_parentesis=False):390# TODO: handle also linked ids, etc...391if show_unit:392unit = ' '+self.format_unit(show_parentesis)393else:394unit = ''395# return repr(self[_id])+unit396397#self.min = minval398#self.max = maxval399#self.digits_integer = digits_integer400#self.digits_fraction = digits_fraction401val = self[_id]402if self.digits_fraction is None:403digits_fraction = 3404else:405digits_fraction = self.digits_fraction406407s = "%."+str(digits_fraction)+"f"408# print 'format_value df=',digits_fraction,'val=',val409410return s % (val)+unit411412413class IdsArrayConf(ArrayConfMixin, ColConf):414"""415Column, where each entry is the id of a single Table.416"""417418def __init__(self, attrname, tab, is_index=False, id_default=-1, perm='r', **kwargs):419self._tab = tab420ArrayConfMixin.__init__(self, attrname,421id_default, # default id422dtype=np.int32,423metatype='id',424perm=perm,425is_index=is_index,426**kwargs427)428self.init_xml()429# print 'IdsConf.__init__',attrname430# print ' ',self._tab.xmltag,self._attrconfig_id_tab431432def get_defaults(self, ids):433# create a list, should work for all types and dimensions434# default can be scalar or an array of any dimension435# print '\n\nget_defaults',self.attrname,ids,self.get_default()436return self.get_default()*np.ones(len(ids), dtype=self._dtype)437438439# -------------------------------------------------------------------------------440# copied from IdsConf!!!441442def set_linktab(self, tab):443self._tab = tab444445def get_linktab(self):446return self._tab447448def init_xml(self):449# print 'init_xml',self.attrname,self._tab450if self._tab.xmltag is not None:451xmltag_tab, xmltag_item_tab, attrname_id_tab = self._tab.xmltag452if (attrname_id_tab is None) | (attrname_id_tab is ''):453self._attrconfig_id_tab = None454else:455self._attrconfig_id_tab = getattr(self._tab, attrname_id_tab) # tab = tabman !456457if not hasattr(self, 'is_xml_include_tab'):458# this means that entire table rows will be included459self.is_xml_include_tab = False460# print ' xmltag_tab, xmltag_item_tab, attrname_id_tab',xmltag_tab, xmltag_item_tab, attrname_id_tab,self.is_xml_include_tab461462else:463self._attrconfig_id_tab = None464self.is_xml_include_tab = False465466def write_xml(self, fd, _id, indent=0):467# print 'write_xml',self.attrname468if (self.xmltag is not None) & (np.all(self[_id] >= 0)):469# print 'write_xml',self.attrname, _id,'value',self[_id]470if self._attrconfig_id_tab is None:471self._write_xml_value(self[_id], fd)472elif self.is_xml_include_tab:473# print ' write table row(s)',self[_id]474self._tab.write_xml(fd, indent, ids=self[_id],475is_print_begin_end=False)476else:477# print ' write id(s)',self[_id]478self._write_xml_value(self._attrconfig_id_tab[self[_id]], fd)479480def _write_xml_value(self, val, fd):481# print 'write_xml',self.xmltag,hasattr(val, '__iter__')482if hasattr(val, '__iter__'):483if len(val) > 0:484if hasattr(val[0], '__iter__'):485# matrix486fd.write(xm.mat(self.xmltag, val))487else:488# list489fd.write(xm.arr(self.xmltag, val, self.xmlsep))490else:491# empty list492# fd.write(xm.arr(self.xmltag,val))493# don't even write empty lists494pass495496elif type(self._default) in (types.UnicodeType, types.StringType):497if len(val) > 0:498fd.write(xm.num(self.xmltag, val))499500else:501# scalar number or string502fd.write(xm.num(self.xmltag, val))503504def _getstate_specific(self, state):505"""506Called by __getstate__ to add/change specific states,507before returning states.508To be overridden.509"""510if self._is_save:511# if self._is_child:512# # OK self.value already set in513# pass514# else:515# # remove table reference and create ident516# print '_getstate_specific',self.attrname517# print ' self._tab',self._tab518# print '_getstate_specific',self._tab.ident, self._tab.get_ident_abs()519state['_tab'] = None520# try:521state['_ident_tab'] = self._tab.get_ident_abs()522# except:523# print 'WARNING:_getstate_specific',self._tab,self._tab.attrname524525def init_postload_internal(self, man, obj):526# print 'IdsConf.init_postload_internal',self.attrname,hasattr(self,'value'),self._is_save,self._is_localvalue,'obj:',obj.ident527528AttrConf.init_postload_internal(self, man, obj)529# print 'IdsConf.init_postload_internal',self.attrname,self.get_value().dtype,self.get_value().dtype == np.int64530if self.get_value().dtype == np.int64:531print 'WARNING in init_postload_internal: convert ids array to 32 bit'532self.set_value(np.array(self.get_value(), dtype=np.int32))533# if self._is_child:534# print ' make sure children get initialized'535# print ' call init_postload_internal of',self._tab.ident536# self._tab.init_postload_internal(obj)537538def init_postload_external(self):539# if self._is_child:540# # restore normally541# AttrConf.init_postload_external(self)542# self._tab.init_postload_external()543# else:544545# Substitute absolute ident with link object.546# Called from init_postload_external of attrsman during load_obj547#548ident_abs = self._ident_tab549# print 'init_postload_external',self.attrname,ident_abs550obj = self.get_obj()551rootobj = obj.get_root()552# print ' obj,rootobj',obj,rootobj553linkobj = rootobj.get_obj_from_ident(ident_abs)554# print ' linkobj',linkobj.ident555self._tab = linkobj556self.init_xml()557558def is_modified(self):559return False560561def set_modified(self, is_modified):562pass563564565class IdlistsArrayConf(IdsArrayConf):566"""567Column, where each entry is a list of ids of a single Table.568"""569570def __init__(self, attrname, tab, metatype=None, perm='r', **kwargs):571self._is_index = False572self._tab = tab573ArrayConfMixin.__init__(self, attrname,574None, # default, will be substituted by id list575dtype='object',576metatype='ids',577perm=perm,578**kwargs579)580self.init_xml()581582def get_defaults(self, ids):583# here we initialize with None for reach element584return np.array(len(ids)*[None, ], self._dtype)585586def add(self, ids, values=None):587if not hasattr(ids, '__iter__'):588_ids = [ids]589if values is not None:590_values = np.zeros(1, self._dtype)591_values[0] = values592593else:594595_ids = ids596_values = np.zeros(len(ids), self._dtype)597_values[:] = values598599if values is None:600_values = self.get_defaults(_ids)601602# print 'add ids, _values',self.attrname,ids603# print ' values',values604# print ' _values',_values605# print ' self.get_value()',self.get_value()606# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())607# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape608609newvalue = np.concatenate((self.get_value(), _values))610# print ' ', type(newvalue),newvalue.dtype611self.set_value(np.concatenate((self.get_value(), _values)))612613if self._is_index:614self.add_indices(_ids, _values)615616617class TabIdListArrayConf(ArrayConfMixin, ColConf):618"""619Column made of an array of lists with (table,id) tupels.620The tables are linked, and will not be saved.621"""622623def __init__(self, attrname, dtype=None, perm='r', **attrs):624ArrayConfMixin.__init__(self, attrname, None, # default, will be substituted by (table,id) list625dtype='object',626metatype='tabidlist',627perm=perm, **attrs)628629def add(self, ids, values=None):630if not hasattr(ids, '__iter__'):631_ids = [ids]632if values is not None:633_values = np.zeros(1, self._dtype)634_values[0] = values635636else:637638_ids = ids639_values = np.zeros(len(ids), self._dtype)640_values[:] = values641642if values is None:643_values = self.get_defaults(_ids)644645# print 'add ids, _values',self.attrname,ids646# print ' values',values647# print ' _values',_values648# print ' self.get_value()',self.get_value()649# print ' type(_values),type(self.get_value())',type(_values),type(self.get_value())650# print ' _values.shape,self.get_value().shape',_values.shape,self.get_value().shape651652newvalue = np.concatenate((self.get_value(), _values))653# print ' ', type(newvalue),newvalue.dtype654self.set_value(np.concatenate((self.get_value(), _values)))655656if self._is_index:657self.add_indices(_ids, _values)658659def add_plugin(self, ids, values=None):660if not hasattr(ids, '__iter__'):661_ids = [ids]662if values is not None:663_values = np.zeros(1, self._dtype)664_values[0] = values665666else:667668_ids = ids669_values = np.zeros(len(ids), self._dtype)670_values[:] = values671672if values is None:673_values = self.get_defaults(_ids)674675###676677def format_value(self, _id, show_unit=False, show_parentesis=False):678s = ''679rowlist = self[_id]680if rowlist is None:681return s682# elif (type(rowlist)in STRINGTYPES):683# return rowlist684elif len(rowlist) == 0:685return s686elif len(rowlist) == 1:687tab, ids = rowlist[0]688return str(tab)+'['+str(ids)+']'689elif len(rowlist) > 1:690tab, ids = rowlist[0]691s = str(tab)+'['+str(ids)+']'692for tab, ids in rowlist[1:]:693s += ','+str(tab)+'['+str(ids)+']'694return s695696def _getstate_specific(self, state):697"""698Called by __getstate__ to add/change specific states,699before returning states.700To be overridden.701"""702# print '_getstate_specific',self.attrname, self._is_save703# print ' self.get_value',self.get_value()704# print len(self.get_value())705if self._is_save:706n = len(state['value'])707state['value'] = None708_tabidlists_save = n*[None]709i = 0710for rowlist in self.get_value():711if rowlist is not None:712rowlist_save = []713for tab, ids in rowlist:714rowlist_save.append([tab.get_ident_abs(), ids])715# print ' tab.get_ident'.get_ident()716# print ' appended',[tab.get_ident_abs(), ids]717_tabidlists_save[i] = rowlist_save718# print ' ',i,rowlist_save719i += 1720state['_tabidlists_save'] = _tabidlists_save721722def init_postload_external(self):723# Substitute absolute ident with link object.724# Called from init_postload_external of attrsman during load_obj725#726# print 'init_postload_external',self.attrname, len(self._tabidlists_save)727#obj = self.get_obj()728#rootobj = obj.get_root()729# print ' rootobj',rootobj.ident730#linkobj = rootobj.get_obj_from_ident(ident_abs)731# print ' linkobj',linkobj.ident732#self._tab = linkobj733734# Substitute absolute ident with link object.735# Called from init_postload_external of attrsman during load_obj736#737_tabidlists_save = self._tabidlists_save738#ident_abs = self._ident_value739# print 'init_postload_external',self.attrname,_tabids_save740obj = self.get_obj()741rootobj = obj.get_root()742# print ' rootobj',rootobj.ident743tabidlists = np.zeros(len(_tabidlists_save), dtype=self._dtype)744745i = 0746for rowlist_save in _tabidlists_save:747rowlist = []748# print ' rowlist_save',rowlist_save749if rowlist_save is not None:750for tabident, ids in rowlist_save:751tab = rootobj.get_obj_from_ident(tabident)752# print ' recovered tab',tab.get_ident_abs(), ids753rowlist.append([tab, ids])754tabidlists[i] = rowlist755else:756tabidlists[i] = None757i += 1758# print ' tabidlists', tabidlists759self.set_value(tabidlists)760761def is_modified(self):762return False763764def set_modified(self, is_modified):765pass766767768class TabIdsArrayConf(ArrayConfMixin, ColConf):769"""770Column, where each entry contains a tuple with table object and id.771The tables are linked, and will not be saved.772"""773774def __init__(self, attrname, is_index=False, perm='r', **kwargs):775self._is_index = is_index776ArrayConfMixin.__init__(self, attrname,777(None, -1), # default id778dtype=[('ob', object), ('id', np.int)],779metatype='tabid',780perm=perm,781**kwargs782)783784def get_defaults(self, ids):785# create a list, should work for all types and dimensions786# default can be scalar or an array of any dimension787# print '\n\nget_defaults',self.attrname,ids,self.get_default()788return np.zeros(len(ids), dtype=self._dtype)789790def _getstate_specific(self, state):791"""792Called by __getstate__ to add/change specific states,793before returning states.794To be overridden.795"""796if self._is_save:797n = len(state['value'])798state['value'] = None799_tabids_save = n*[None]800i = 0801for tab, ids in self.get_value():802_tabids_save[i] = [tab.get_ident_abs(), ids]803i += 1804state['_tabids_save'] = _tabids_save805806def init_postload_external(self):807# if self._is_child:808# # restore normally809# AttrConf.init_postload_external(self)810# self._tab.init_postload_external()811# else:812813# Substitute absolute ident with link object.814# Called from init_postload_external of attrsman during load_obj815#816#ident_abs = self._ident_tab817# print 'reset_linkobj',self.attrname,ident_abs818#obj = self.get_obj()819#rootobj = obj.get_root()820# print ' rootobj',rootobj.ident821#linkobj = rootobj.get_obj_from_ident(ident_abs)822# print ' linkobj',linkobj.ident823#self._tab = linkobj824825# Substitute absolute ident with link object.826# Called from init_postload_external of attrsman during load_obj827#828_tabids_save = self._tabids_save829#ident_abs = self._ident_value830# print 'init_postload_external',self.attrname,_tabids_save831obj = self.get_obj()832rootobj = obj.get_root()833# print ' rootobj',rootobj.ident834tabids = np.zeros(len(self._tabids_save), dtype=self._dtype)835836i = 0837for tabident, ids in self._tabids_save:838tab = rootobj.get_obj_from_ident(tabident)839# print ' ',tab.get_ident_abs(), ids840tabids[i] = (tab, ids)841i += 1842843self.set_value(tabids)844845def is_modified(self):846return False847848def set_modified(self, is_modified):849pass850851852class Arrayman(Tabman):853"""854Manages all table attributes of an object.855856if argument obj is specified with an instance857then column attributes are stored under this instance.858The values of attrname is then directly accessible with859860obj.attrname861862If nothing is specified, then column attribute will be stored under863the respective config instance of this tab man (self).864The values of attrname is then directly accessible with865866self.attrname.value867868"""869870def __init__(self, obj=None, **kwargs):871872Attrsman.__init__(self, obj, **kwargs)873self._colconfigs = []874self._inds = np.zeros((0,), dtype=np.int32)875self._ids = np.zeros((0,), dtype=np.int32)876877def get_inds(self, ids=None):878if ids is not None:879return self._inds[ids]880else:881return self._inds[self._ids]882883def get_ids(self, inds=None):884if inds is not None:885return self._ids[inds]886else:887return self._ids888889return890891def __getitem__(self, args):892if type(args) == types.TupleType:893attrnames = args[0]894ids = args[1]895else:896attrnames = args897ids = self._ids898899if hasattr(attrnames, '__iter__'):900n_rows = len(ids)901n_cols = len(attrnames)902# print ' n_rows',n_rows,'n_cols',n_cols,attrnames903if (n_rows == 0) | (n_cols == 0):904return np.array([[]])905else:906#attrconf = getattr(self,attrnames[0])907# TODO: detect dtype by adding numbers or use fields!!!908dtype = np.float32909out = np.zeros((n_rows, n_cols), dtype=dtype)910for i, attrname in zip(xrange(n_cols), attrnames):911out[:, i] = getattr(self, attrname)[ids]912return out913else:914return getattr(self, attrnames)[ids]915916def get_ind(self, id):917return self._inds[id]918919def select_ids(self, mask):920# print 'select_ids'921# print ' mask\n=',mask922# print ' self._ids\n=',self._ids923# if len(self)>0:924return np.take(self._ids, np.flatnonzero(mask))925# else:926# return np.zeros(0,int)927928def suggest_id(self, is_zeroid=False):929"""930Returns a an availlable id.931932Options:933is_zeroid=True allows id to be zero.934935"""936return self.suggest_ids(1, is_zeroid)[0]937938def format_id(self, id):939return self.format_ids([id])940941def format_ids(self, ids):942return ', '.join(np.array(ids, dtype='|S24'))943944def get_id_from_formatted(self, idstr):945return int(idstr)946947def get_ids_from_formatted(self, idstrs):948idstrs_arr = idstrs.split(',')949ids = np.zeros(len(idstrs_arr), dtype=np.float32)950i = 0951for idstr in idstrs_arr:952ids[i] = int[idstr]953954return ids955956def suggest_ids(self, n, is_zeroid=False):957"""958Returns a list of n availlable ids.959It returns even a list for n=1.960961Options:962is_zeroid=True allows id to be zero.963"""964# TODO: does always return 1 if is_index is True ?????965# print 'suggest_ids',n,is_zeroid,self._inds,len(self._inds),self._inds.dtype966ids_unused_orig = np.flatnonzero(np.less(self._inds, 0))967968if not is_zeroid:969if len(self._inds) == 0:970ids_unused = np.zeros(0, dtype=np.int32)971else:972# avoid 0 as id:973# ids_unused=take(ids_unused,flatnonzero(greater(ids_unused,0)))974# print ' ids_unused_orig',ids_unused_orig,type(ids_unused_orig)975# print ' len(ids_unused_orig)',len(ids_unused_orig),ids_unused_orig.shape976# print ' greater(ids_unused_orig,0)',greater(ids_unused_orig,0)977# print ' len(greater(ids_unused_orig,0))',len(greater(ids_unused_orig,0))978# print ' flatnonzero(greater(ids_unused_orig,0))',flatnonzero(greater(ids_unused_orig,0))979# print ' len(flatnonzero(greater(ids_unused_orig,0)))=',len(flatnonzero(greater(ids_unused_orig,0)) )980ids_unused = ids_unused_orig[np.flatnonzero(np.greater(ids_unused_orig, 0))]981zid = 1982else:983if len(self._inds) == 0:984ids_unused = np.zeros(0, dtype=np.int32)985else:986ids_unused = ids_unused_orig.copy()987988zid = 0989990n_unused = len(ids_unused)991n_max = len(self._inds)-1992# print ' ids_unused',ids_unused993# print ' ids_unused.shape',ids_unused.shape994# print ' len(ids_unused)',len(ids_unused)995# print ' n_unused,n_max,zid=',n_unused,n_max,zid996997if n_max < zid:998# first id generation999ids = np.arange(zid, n+zid, dtype=np.int32)10001001elif n_unused > 0:1002if n_unused >= n:1003ids = ids_unused[:n]1004else:1005# print ' ids_unused',ids_unused1006# print ' from to',n_max+1,n_max+1+n-n_unused1007# print ' arange=',arange(n_max+1,n_max+1+n-n_unused)1008# print ' type(ids_unused)',type(ids_unused)1009# print ' dtype(ids_unused)',ids_unused.dtype1010ids = np.concatenate((ids_unused, np.arange(n_max+1, n_max+1+n-n_unused)))10111012else:1013ids = np.arange(n_max+1, n_max+1+n, dtype=np.int32)10141015return ids10161017def _add_ids(self, ids):1018n = len(ids)1019if n == 0:1020return10211022id_max = max(ids)1023id_max_old = len(self._inds)-11024n_array_old = len(self)10251026ids_existing = np.take(ids, np.flatnonzero(np.less(ids, id_max_old)))1027# print ' ids',ids,'id_max_old',id_max_old,'ids_existing',ids_existing10281029# check here if ids are still available1030# if np.sometrue( np.not_equal( np.take(self._inds, ids_existing), -1) ):1031# print 'WARNING in create_ids: some ids already in use',ids_existing1032# return np.zeros(0,int)10331034# extend index map with -1 as necessary1035if id_max > id_max_old:1036# print 'ext',-1*ones(id_max-id_max_old)1037self._inds = np.concatenate((self._inds, -1*np.ones(id_max-id_max_old, int)))10381039# assign n new indexes to new ids1040ind_new = np.arange(n_array_old, n_array_old+n, dtype=np.int32)10411042# print 'ind_new',ind_new1043np.put(self._inds, ids, ind_new)10441045# print ' concat ids..',self._ids,ids1046self._ids = np.concatenate((self._ids, ids))10471048def add_rows(self, n=None, ids=[], **attrs):10491050if n is not None:1051ids = self.suggest_ids(n)1052elif (len(ids) == 0) & (len(attrs) > 0):1053# get number of rows from any value vector provided1054ids = self.suggest_ids(len(attrs.values()[0]))1055elif (n is None) & (len(ids) == 0) & (len(attrs) > 0):1056# nothing given really-> do nothing1057return np.zeros((0), np.int)10581059else:1060# ids already given , no ids to create1061pass10621063# print 'add_rows ids', ids, type(ids)1064self._add_ids(ids)10651066for colconfig in self._colconfigs:1067colconfig.add(ids, values=attrs.get(colconfig.attrname, None))1068if self.plugin:1069self.plugin.exec_events_ids(EVTADDITEM, ids)1070return ids10711072def copy_cols(self, attrman2, ids=None):1073# WARNING: this method is unsafe for indexed colums as values are1074# copied and are no longer unique1075# print 'copy_cols'1076if ids is None:1077ids2 = attrman2.get_ids()1078else:1079ids2 = ids1080#ids_new = self.suggest_ids(ids2)1081ids_new = self.add_rows(n=len(ids2))10821083for colconfig2 in attrman2._colconfigs:1084if hasattr(self, colconfig2.attrname):1085colconfig = getattr(self, colconfig2.attrname)1086colconfig.set(ids_new, values=colconfig2[ids2].copy())10871088return ids_new10891090def set_rows(self, ids, **attrs):10911092for colconfig in self._colconfigs:1093colconfig.set(ids, values=attrs.get(colconfig.attrname, None))1094if self.plugin:1095self.plugin.exec_events_ids(EVTSETITEM, ids)10961097def add_row(self, _id=None, **attrs):1098if _id is None:1099_id = self.suggest_id()11001101self._add_ids([_id])1102#ids = self.add_rows(1, **attrs)1103for colconfig in self._colconfigs:1104# print ' add_row',colconfig.attrname,attrs.get(colconfig.attrname, None )1105colconfig.add(_id, values=attrs.get(colconfig.attrname, None))11061107if self.plugin:1108self.plugin.exec_events_ids(EVTADDITEM, [id])1109return _id11101111def set_row(self, _id, **attrs):1112# if _id is None:1113# print ' set_row ',self.get_ident(),attrs1114for colconfig in self._colconfigs: # TODO: run through keys!!!!1115# print ' add_row',_id,colconfig.attrname,attrs.get(colconfig.attrname, None )1116# if attrs.has_key(colconfig.attrname):1117#colconfig.set(_id, values = attrs[colconfig.attrname])1118colconfig.set(_id, values=attrs.get(colconfig.attrname, None))11191120if self.plugin:1121self.plugin.exec_events_ids(EVTSETITEM, [id])11221123def del_rows(self, ids_del):1124# print '\n\ndel_rows',self.ident,ids_del1125# remaining index1126if self.plugin:1127self.plugin.exec_events_ids(EVTDELITEM, ids_del)11281129inds_remain = np.ones(len(self), dtype=np.bool_)1130inds_remain[self._inds[ids_del]] = False1131inds_remain = np.flatnonzero(inds_remain)1132for colconfig in self._colconfigs:1133colconfig._del_rows(ids_del, inds_remain)1134self._ids = self._ids[inds_remain]1135if len(self._ids) == 0:1136n = 01137else:1138n = np.max(self._ids)1139self._inds = np.zeros(n+1, dtype=np.int32)1140self._inds[self._ids] = np.arange(len(self._ids))11411142def del_row(self, _id):1143# print 'del_row',id1144self.del_rows_simple([_id])11451146def del_rows_simple(self, ids):1147# print '\n\ndel_rows',self.ident,ids1148# print ' self._ids',self._ids1149# print ' self._inds',self._inds1150# TODO: this could be done in with array methods11511152if self.plugin:1153self.plugin.exec_events_ids(EVTDELITEM, ids)1154for _id in ids:1155i = self._inds[_id]1156# print ' id to eliminate _id=',_id1157# print ' index to eliminate i=',i1158for colconfig in self._colconfigs:1159# print ' colconfig',colconfig.attrname,i1160# colconfig.delete_ind(i)1161del colconfig[_id] # this is universal, also for cm.ColConfigs11621163# print ' del from id lookup'1164self._ids = np.concatenate((self._ids[:i], self._ids[i+1:]))1165# print ' ids after cut',self._ids11661167# print ' free index',id1168if _id == len(self._inds)-1:1169# id is highest, let's shrink index array by 11170self._inds = self._inds[:-1]1171else:1172self._inds[_id] = -111731174# get ids of all indexes which are above i1175ids_above = np.flatnonzero(self._inds > i)11761177# decrease index from those wich are above the deleted one1178#put(self._inds, ids_above,take(self._inds,ids_above)-1)1179self._inds[ids_above] -= 111801181# print ' inds after cut',self._inds11821183# print ' self._inds',self._inds11841185# print ' del',ids,' done.'11861187def clear_rows(self):1188# attention: overridden by ArrayObjman1189# print 'clear_rows',self.ident11901191if self.plugin:1192self.plugin.exec_events_ids(EVTDELITEM, self.get_ids())1193self._ids = []1194self._inds = np.zeros((0,), int)1195self._ids = np.zeros((0,), int)11961197for colconfig in self._colconfigs:1198# print 'clear_rows',colconfig.attrname,len(colconfig.get_value())1199colconfig.clear()1200# print ' done',len(colconfig.get_value())120112021203class ArrayObjman(Arrayman, TableMixin):1204"""1205Array Object management manages objects with numeric Python arrays1206based columns. Can also handle list and dict based columns.1207"""12081209def __init__(self, ident, **kwargs):1210self._init_objman(ident, **kwargs)12111212def _init_objman(self, ident, is_plugin=False, **kwargs):1213BaseObjman._init_objman(self, ident, managertype='table', **kwargs)1214Arrayman.__init__(self, is_plugin=is_plugin)1215self.set_attrsman(self)12161217def init_postload_internal(self, parent):1218"""1219Called after set state.1220Link internal states.1221"""1222TableMixin.init_postload_internal(self, parent)1223attrman = self.get_attrsman()12241225# this should no longer happen in the future as ind and ids1226# have been formatted propperly1227if attrman._inds.dtype != np.int32:1228print 'WARNING: 64 bit ids and inds...will adjust to 32 bit'1229attrman._inds = np.array(attrman._inds, dtype=np.int32)1230attrman._ids = np.array(attrman._ids, dtype=np.int32)12311232def init_postload_external(self):1233"""1234Called after set state.1235Link internal states.1236"""1237TableMixin.init_postload_external(self)1238self._init_attributes()1239self._init_constants()12401241def clear_rows(self):1242if self.plugin:1243self.plugin.exec_events_ids(EVTDELITEM, self.get_ids())1244self._inds = np.zeros((0,), dtype=np.int32)1245self._ids = np.zeros((0,), dtype=np.int32)1246for colconfig in self.get_attrsman()._colconfigs:1247# print 'ArrayObjman.clear_rows',colconfig.attrname,len(colconfig.get_value())1248colconfig.clear()1249# print ' done',len(colconfig.get_value())12501251def clear(self):1252# print 'ArrayObjman.clear',self.ident1253# clear/reset scalars1254for attrconfig in self.get_attrsman().get_configs(structs=STRUCTS_SCALAR):1255attrconfig.clear()1256self.clear_rows()1257self._init_constants()1258self.set_modified()12591260# print ' check: suggest_ids',self.suggest_ids(5)126112621263