From: Benny Brown Date: May 23, 2010 3:33:20 PM PDT To: "James P. Crutchfield" Subject: One-D map tool Reply-To: brown@cse.ucdavis.edu Hi Jim, Here's the object-oriented solution to the one-D map tool. I updated it to more cleanly separate code for interface & plot generation and map class definitions; also added the __call__ method. Of course, feel free to add/modify. Benny # OneDTool.py # try importing modules, catch exceptions if a module isn't installed try: import sys import matplotlib.pyplot as plt import numpy as np import OneDMapClasses as odm except ImportError, msg: print 'Error importing modules:', msg sys.exit() mapList = odm.maps.keys() # convenient for looping in order mapList.sort() # dictionaries do not necessarily automatically sort, even if # items are entered in correct order, so we have to manually # sort keys mapChoice = None # main loop... while mapChoice != '0': # prompt user for map choice print '\nOne Dimensional Map Bifurcation Tool' print 'Maps available:' for item in mapList: print item, '-', odm.maps[item][0] # get choice from user mapChoice = raw_input('Enter choice (%s-%s) or 0 to quit): ' % (mapList[0], mapList[-1])) # check if user wants to quit if mapChoice == '0': print 'Exiting One-D bifurcation tool...' break # break out of main loop # else check if valid choice elif mapChoice not in mapList: print '\n-->Invalid choice! Please try again...' continue # skip to beginning of main loop to try again # this is where we actually create a map object OneDMap = odm.maps[mapChoice][1]() # get initial condition from user while True: ic = raw_input('Enter initial condition (leave blank for default of %0.2f): ' \ % OneDMap.defaults[0]).strip() if ic != '': # something was entered try: OneDMap.ic = float(ic) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # get lower parameter limit while True: rLow = raw_input('Enter lower limit of r (leave blank for default of %0.2f): ' \ % OneDMap.defaults[1]).strip() if rLow != '': # something was entered try: OneDMap.rLow = float(rLow) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # get upper parameter limit while True: rHi = raw_input('Enter upper limit of r (leave blank for default of %0.2f): ' \ % OneDMap.defaults[2]).strip() if rHi != '': # something was entered try: OneDMap.rHi = float(rHi) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # now compute and plot the bifurcation diagram plt.figure() # Title for plot plt.title(OneDMap.mapStr + '\nBifurcation diagram for r in [%g,%g]' \ % (OneDMap.rLow,OneDMap.rHi)) # Label axes plt.xlabel('Control parameter r') plt.ylabel('{X(n)}') # The iterates we'll throw away nTransients = 200 # This sets how much the attractor is filled in nIterates = 250 # This sets how dense the bifurcation diagram will be nSteps = 400 # Sweep the control parameter over the desired range rInc = (OneDMap.rHi-OneDMap.rLow)/float(nSteps) for OneDMap.r in np.arange(OneDMap.rLow, OneDMap.rHi, rInc): # Set the initial condition to the reference value OneDMap.state = OneDMap.ic # Throw away the transient iterations OneDMap(nTransients) # Now store the next batch of iterates rsweep = np.repeat(OneDMap.r, nIterates)   # array of parameter values x = [ ]        # The iterates for i in xrange(nIterates): OneDMap(1) # iterate the map once x.append( OneDMap.state ) # save the new state for plotting plt.plot(rsweep, x, 'k,') # Plot the list of (r,x) pairs as pixels plt.show() # delete object before creating a new one del OneDMap ## end main loop ## # OneDMapClasses.py # import in a try-except statement in case a module is not installed try: import numpy as np import matplotlib.pyplot as plt except ImportError, msg: # catch any import exceptions, print error message print 'Error importing modules:', msg class OneDimMap(): """ Base class for all map classes. This provides methods common to all map classes. """ def __init__(self): """Constructor for the OneDMap base class.""" # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.0, 0.0, 1.0] self.resetVals() # set map values to defaults self.mapStr = 'One Dimensional Map f(x) = x' # place holder for map string def __repr__(self): """String representation of map.""" return self.mapStr # defined in __init__ def __call__(self, num_its): """Iterates the map num_its times and saves the state.""" for n in xrange(num_its): self.func() # compute the maps's function # state of last iteration is saved in self.state def func(self): """Computes f(x). This is a place holder for all map classes.""" self.state = 0.0 # in this case, f(x) = 0.0 def resetVals(self): """Set map values to their respective defaults.""" # set default values for state and parameters/limits self.ic = self.defaults[0] self.state = self.defaults[0] self.r = self.defaults[1] self.rLow = self.defaults[1] self.rHi = self.defaults[2] ## end class OneDMap ## class LogisticMap(OneDimMap): """The logistic map class.""" def __init__(self): """Constructor for a LogisticMap object.""" OneDimMap.__init__(self) # invoke constructor of base class # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.3, 0.0, 4.0] self.resetVals() # descriptive string of map self.mapStr = 'Logistic Map: f(x) = rx(1-x)' def func(self): """Defines the logistic map function.""" self.state = self.r * self.state * (1.0 - self.state) ## end class LogisticMap ## class CosineMap(OneDimMap): """The cosine map class.""" def __init__(self): """Constructor for a CosineMap object.""" OneDimMap.__init__(self) # invoke constructor of base class # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.3, -5.0, 5.0] self.resetVals() # descriptive string of map self.mapStr = 'Cosine Map: f(x)=rcos(x)' def func(self): """Defines the cosine map function.""" self.state = self.r * np.cos(self.state) ## end class CosineMap ## class TentMap(OneDimMap): """The tent map class.""" def __init__(self): """Constructor for a TentMap object.""" OneDimMap.__init__(self) # invoke constructor of base class # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.3, 0.0, 2.0] self.resetVals() # descriptive string of map self.mapStr = 'Tent Map: f(x)=rx (x<0.5), f(x)=r(1-x) (x>=0.5)' def func(self): """Defines the tent map function.""" if self.state < 0.5: self.state = self.r * self.state else: self.state = self.r * (1.0 - self.state) # Create a dictionary of map choices with pointers to their classes. # Note that only references to the classes are stored below and no objects # are actually created until the main loop. maps = { '1' : ['Logistic Map: f(x)=rx(1-x)', LogisticMap], '2' : ['Cosine Map: f(x)=rcos(x)', CosineMap], '3' : ['Tent Map: f(x)=rx (x<0.5), f(x)=r(1-x) (x>=0.5)', TentMap] }