def __init__( self, *args ): self.__name__ = 'C_CAE' self.mstr_obj = 'C_CAE'; # name of object class self.mstr_name = 'unnamed'; # name of object variable self.mstr_def = 'void'; # name of function being processed self.m_id = -1; # int id self.m_iter = 0; # current iteration in an #+ arbitrary processing #+ scheme self.m_verbosity = 0; # debug related value for #+ object self.m_warnings = 0; # show warnings #+ (and warnings level) # The core data containers are grids of cellular automata # machines self.mgg_current = None # Current grid self.mgg_next = None # Next iteration grid self.mb_syncGridSpectralArray = False # Controls whether or not # to synchronize grid spectra # and grid helper array # For the most part, the CAE accepts the same constructor # pattern as the C_ggrid: if len( args ) == 2: # Grid spectral elements are of type C_spectrum_CAM print "Creating current state grid...", ; misc.tic() self.mgg_current = C_ggrid( *args, name='currentState' ) print "done. %s" % misc.toc() print "Creating next state grid...", ; misc.tic() self.mgg_next = C_ggrid( *args, name='nextState' ) print "done. %s" % misc.toc() self.m_rows = self.mgg_current.rows_get() self.m_cols = self.mgg_current.cols_get() self.__neighbors = {}
str_yordFile = '%s.yord' % str_stem # We need to setup the grid with the proper size, which # is a slight chicken-and-egg problem. First, we read # one of the ord files, determine the string length # and there we go :-) if not count: f = open(str_xordFile) str_file = f.readline() str_xord = str_file.splitlines()[0] gridSize = len(str_xord) l_keys = list(str_xord) l_keys.sort() f.close() gridSpect = spectrum.C_spectrum(l_keys) Cg = grid.C_ggrid(str_gridFile, gridSpect) print Cg if not count: Cg_sum = Cg Csp_xord = spectrum.C_spectrum_permutation(Cg_sum.cols_get()) Csp_xord.printAsHistogram_set(True) Csp_xord.name_set('X-ordering') Csp_yord = spectrum.C_spectrum_permutation(Cg_sum.cols_get()) Csp_yord.printAsHistogram_set(True) Csp_yord.name_set('Y-ordering') Csp_xyord = spectrum.C_spectrum_permutation2D(Cg_sum.cols_get()) Csp_xyord.printAsHistogram_set(True) Csp_xyord.name_set('XY-ordering') Csp_xyord.printConcise_set(True) else: Cg_sum = Cg_sum + Cg
# o Initial development implementation. # from numpy import * from C_ggrid import * from C_spectrum import * import copy Csp = C_spectrum(['R', 'G', 'B']); Csp.component_add('R'); Csp.component_add('G'); Csp.component_add('B'); print Csp Cg0 = C_ggrid(2, Csp, name='Cg0'); Cg1 = C_ggrid(np.array((2,2)), Csp, name='Cg1') Cg00 = copy.deepcopy(Cg0) ; Cg00.mstr_name = 'Cg00' print Cg0 print Cg00 Cg2 = Cg0 + Cg1 print Cg2 Cg0.spectralArray_set( np.array( [[0,0],[1,1]] ), np.array((10, 10, 10))) print Cg0 print Cg00 a_sp = Cg0.spectralArray_get( np.array( [[1,0],[0,0]] )) print a_sp
class C_CAE: # # Class member variables -- if declared here are shared # across all instances of this class # mdictErr = { 'Keys' : { 'action' : 'initializing base class, ', 'error' : 'it seems that no member keys are defined.', 'exitCode' : 10}, 'Save' : { 'action' : 'attempting to pickle save self, ', 'error' : 'a PickleError occured', 'exitCode' : 12}, 'SaveMat' : { 'action' : 'attempting to save MatLAB friendly spectrum, ', 'error' : 'an IOerror occured', 'exitCode' : 13}, 'Load' : { 'action' : 'attempting to pickle load object, ', 'error' : 'a PickleError occured', 'exitCode' : 14} } # # Methods # # Core methods - construct, initialise, id def dprint( self, level, str_txt ): """ Simple "debug" print... based on verbosity level. """ if level <= self.m_verbosity: print str_txt def verbosity_set( self, level ): self.m_verbosity = level def error_exit( self, astr_key, ab_exitToOs=1 ): print "%s:: FATAL ERROR" % self.mstr_obj print "\tSorry, some error seems to have occurred in <%s::%s>" \ % ( self.__name__, self.mstr_def ) print "\tWhile %s" % C_spectrum.mdictErr[astr_key]['action'] print "\t%s" % C_spectrum.mdictErr[astr_key]['error'] print "" if ab_exitToOs: print "Returning to system with error code %d" % \ C_spectrum.mdictErr[astr_key]['exitCode'] sys.exit( C_spectrum.mdictErr[astr_key]['exitCode'] ) return C_spectrum.mdictErr[astr_key]['exitCode'] def fatal( self, astr_key, astr_extraMsg="" ): if len( astr_extraMsg ): print astr_extraMsg self.error_exit( astr_key ) def warn( self, astr_key, astr_extraMsg="" ): b_exitToOS = 0 if len( astr_extraMsg ): print astr_extraMsg self.error_exit( astr_key, b_exitToOS ) def __init__( self, *args ): self.__name__ = 'C_CAE' self.mstr_obj = 'C_CAE'; # name of object class self.mstr_name = 'unnamed'; # name of object variable self.mstr_def = 'void'; # name of function being processed self.m_id = -1; # int id self.m_iter = 0; # current iteration in an #+ arbitrary processing #+ scheme self.m_verbosity = 0; # debug related value for #+ object self.m_warnings = 0; # show warnings #+ (and warnings level) # The core data containers are grids of cellular automata # machines self.mgg_current = None # Current grid self.mgg_next = None # Next iteration grid self.mb_syncGridSpectralArray = False # Controls whether or not # to synchronize grid spectra # and grid helper array # For the most part, the CAE accepts the same constructor # pattern as the C_ggrid: if len( args ) == 2: # Grid spectral elements are of type C_spectrum_CAM print "Creating current state grid...", ; misc.tic() self.mgg_current = C_ggrid( *args, name='currentState' ) print "done. %s" % misc.toc() print "Creating next state grid...", ; misc.tic() self.mgg_next = C_ggrid( *args, name='nextState' ) print "done. %s" % misc.toc() self.m_rows = self.mgg_current.rows_get() self.m_cols = self.mgg_current.cols_get() self.__neighbors = {} def initialize( self, *args, **kwargs ): """ ARGS *args[0] nparray initialize each CAM with corresponding element of nparray. Assumes that size(nparray) == size(grid). Passes array value at [row, col] to CAM at [row, col]. DESC Generates an initial distribution across the world grid. KWARGS The pattern of initialization is specified by the kwargs: pattern = "random" | "corners" | "diagonal" Choose elements either randomly on the grid, or only on the corners, or only along the diagonal. elements = "canonical" | <N> | "all" "canonical" The number of grid elements to initialize. If "canonical", initialize only as many elements as there are spectral components in the CAM. Each successive element initializes a single successive spectral component. <N> Initialize <N> elements. "all" Initialize all elements. PRECONIDTIONS: o Internal grids must exist and contain valid objects. POSTCONDITIONS: o The "current" and "next" are initialized based on pattern of args. o If an array is passed as first unnamed argument, values in the array are used to initialize the grid (provided that the array is the same size as grid). In such a case, all kwargs are ignored. If array size is not same as grid, no initialization is performed. """ l_components = self.mgg_current.spectrum_get( 0, 0 ).spectrumKeys_get() numComponents = len( l_components ) maxEnergy = 255 maxQuanta = maxEnergy / numComponents if len( args ): a_init = args[0] if type( a_init ).__name__ == 'ndarray': rows, cols = a_init.shape if rows == self.m_rows and cols == self.m_cols: # In this case, an initialization matrix has been supplied # by the caller. The value at each cell index is used # to initialize the corresponding spectrum object. In order # for the initialization to be "uniform" across the RGB # space, we need to re-scale the observed values such that # a uniform partitioning of the domain results in a uniform # partitioning of the values, too. a_norm = misc.arr_normalize( a_init, scale=maxEnergy ) a_round = a_norm.round() # We bin the cdf with a '+1' since the 'zeros' in the # input matrix are a special case. This also simplifies # the value lookup in the cdf partitions. a_cdf = misc.cdf( a_round, bins=a_round.max() + 1 ) l_v = misc.cdf_distribution( a_cdf, numComponents ) for row in np.arange( 0, rows ): for col in np.arange( 0, cols ): value = a_round[row, col] self.mgg_current.spectrum_get( row, col ).\ spectrum_init( value, l_v ) # self.mgg_next = copy.deepcopy( self.mgg_current ) # use cPickle instead of deepcopy self.mgg_next = cPickle.loads( cPickle.dumps( self.mgg_current, -1 ) ) def dict_createFromGridLocations( self, A_points ): """ Given an array of grid locations, <A_points>, construct and return a dictionary of next state spectra located at each of the <A_points> and indexed by the spectra name. """ dict_spectrum = {} if A_points != None: for point in A_points: row, col = point dict_spectrum[self.mgg_next.spectrum_get( row, col ).name_get()] = \ self.mgg_next.spectrum_get( row, col ) return dict_spectrum def state_transition( self ): """ The state transition machine for the CAE; determines the "next" state from the "current". PRECONDITIONS: o The "current" == "next" state TRANSITION: o The "next" state is changed according to "current" state in a decoupled element-by-element fashion. POSTCONDITIONS: o Once each element in the "current" state has been processed, the "next" state is copied into the "current" state. o A state transition is now complete. o Returns the number of elements processed. Primitive support for multithreaded/parallelization is planned... """ # Process the current grid, and determine all the changes required to # transition to the next state. elementProcessedCount = 0 misc.tic() for row in np.arange( 0, self.m_rows ): for col in np.arange( 0, self.m_cols ): dict_nextStateNeighbourSpectra = {} A_neighbours = None key = str( row ) + ':' + str( col ) if self.__neighbors.has_key( key ): # we already have the neighbors A_neighbours = self.__neighbors[key] else: # we don't have the neighbors, so let's calculate them A_neighbours = \ misc.neighbours_findFast( 2, 1, np.array( ( row, col ) ), gridSize=np.array( ( self.m_rows, self.m_cols ) ), wrapGridEdges=False, returnUnion=True, includeOrigin=False ) self.__neighbors[key] = A_neighbours dict_nextStateNeighbourSpectra = \ self.dict_createFromGridLocations( A_neighbours ) deltaSelf, deltaNeighbour = \ self.mgg_current.spectrum_get( row, col ).nextStateDelta_determine( dict_nextStateNeighbourSpectra ) if deltaNeighbour: for update in deltaNeighbour.keys(): elementProcessedCount += 1 updateRule = deltaNeighbour[update] dict_nextStateNeighbourSpectra[update].nextState_process( updateRule ) print "Update loop time: %f seconds (%d elements processed)." % \ ( misc.toc(), elementProcessedCount ) # Now update the current state with the next state misc.tic() b_setFromArray = False if self.mb_syncGridSpectralArray: self.mgg_next.internals_sync( b_setFromArray ) print misc.toc( sysprint="Synchronization: %f seconds." ) misc.tic() # self.mgg_current = copy.deepcopy(self.mgg_next) # use cPickle instead of deepcopy self.mgg_current = cPickle.loads( cPickle.dumps( self.mgg_next, -1 ) ) print misc.toc( sysprint="next->current deepcopy: %f seconds.\n" ) return elementProcessedCount def currentSpectralArray_get( self, anp_gridLocation ): """ Return the spectral array at a given location in the current grid. """ return self.mgg_current.spectralArray_get( anp_gridLocation ) def spectrum_get( self, row, col ): """ Return the spectrum (from the current state) at the given location """ return self.mgg_current.spectrum_get( row, col ) def currentgrid_get( self, synced=False, next=False ): """ Return the current or next grid as a np-array which is synced on request. """ if next: grid = self.mgg_next else: grid = self.mgg_current if synced: grid.internals_sync( False ) return grid.gridarr_get() def currentGridCorners_areAllDominant(self): """ DESC Simple conditional that returns a True if all the grid corners have a dominant spectral harmonic. If any of the corners do not have a dominant harmonic, return False. This method is mostly used as a conditional end check on the evolutionary state of a system. """ nTopLeft = len(self.spectrum_get(0, 0).max_harmonics()) nTopRight = len(self.spectrum_get(0, self.m_cols-1).max_harmonics()) nBottomLeft = len(self.spectrum_get(self.m_rows-1, 0).max_harmonics()) nBottomRight = len(self.spectrum_get(self.m_rows-1, self.m_cols-1).max_harmonics()) return nTopLeft | nTopRight | nBottomLeft | nBottomRight == 1