def collapse_position(stepmon, tolerance=0.005, generations=50, mask=None): '''return a dict of {measure: pairs_of_indices} where the product_measure exhibits a dimensional collapse in position. Dimensional collapse in position is defined by: collapse will be ignored at (measure,pairs) as specified in the mask. Format of mask will determine the return value for this function. Default mask format is dict of {measure: pairs_of_indices}, with alternate formatting available as a set of tuples of (measure,pair). ''' #XXX: not mentioned, 'where' format also available np = _m.numpy # reject bad masks if mask is None: pass elif type(mask) is set: for i in mask: if not hasattr(i, '__len__') or len(i) != 2: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) if type(i[0]) is not int: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) if np.array(i[1]).ndim != 1: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) elif type(mask) is dict: for (i, j) in getattr(mask, 'iteritems', mask.items)(): if type(j) is not set or type(i) is not int: msg = "bad entry '%s:%s' in mask" % (str(i), str(j)) raise ValueError(msg) for k in j: # items in the set if not hasattr(k, '__len__') or len(k) != 2: msg = "bad entry '%s:%s' in mask" % (str(i), str(j)) raise ValueError(msg) elif hasattr(mask, '__len__') and len(mask) == 2: if np.array(mask[0]).ndim != 1: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) if np.array(mask[1]).ndim != 2: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) elif hasattr(mask, '__len__') and not len(mask): mask = type(mask)(((), ())) #XXX: HACK to get empty where mask else: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) # is the max position difference less than tolerance across all generations? distances = _m._positions(stepmon, generations) nindices = distances.shape[-1] from mystic.tools import pairwise distances, pairs = pairwise(distances, True) distances = distances.max(axis=0) <= tolerance # select off the desired pairs (of indices) counts = np.cumsum(distances.sum(axis=-1)) import warnings with warnings.catch_warnings(): #FIXME: python2.5 warnings.simplefilter('ignore') #XXX: throws a FutureWarning distances = np.split( np.array((pairs, ) * distances.shape[0])[distances], counts)[:-1] counts = (set(tuple(i) for i in j) for j in distances) # return in terms of pairs, b/c indexing alone doesn't give pairings # (keys are measure, and values are (index1,index2) pairs) distances = ((i, j) for (i, j) in enumerate(counts) if len(j)) # identify mask format and build filter select, pairs = _position_filter(mask) # convert to selected format... if pairs: # return explicit 'pairs' {(measure,indices)} import itertools mask = set() for i, j in distances: [ mask.add(k) for k in getattr(itertools, 'izip', zip)(*((i, ) * len(j), j)) ] elif pairs is None: # return 'where' format [measures,indices] import itertools # tuple of where,pairs measures, mask = (), () for (i, j) in (getattr(itertools, 'izip', zip)(*((j[0], i) for i in j[1])) for j in distances): measures += i mask += j mask = (measures, mask) if len(measures) else () else: # returns a dict of {measure, indices} mask = dict(distances) # apply mask return select(mask)
def collapse_position(stepmon, tolerance=0.005, generations=50, mask=None): '''return a dict of {measure: pairs_of_indices} where the product_measure exhibits a dimensional collapse in position. Dimensional collapse in position is defined by: collapse will be ignored at (measure,pairs) as specified in the mask. Format of mask will determine the return value for this function. Default mask format is dict of {measure: pairs_of_indices}, with alternate formatting available as a set of tuples of (measure,pair). ''' #XXX: not mentioned, 'where' format also available np = _m.numpy # reject bad masks if mask is None: pass elif type(mask) is set: for i in mask: if not hasattr(i, '__len__') or len(i) != 2: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) if type(i[0]) is not int: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) if np.array(i[1]).ndim != 1: msg = "bad element '%s' in mask" % str(i) raise ValueError(msg) elif type(mask) is dict: for (i,j) in getattr(mask, 'iteritems', mask.items)(): if type(j) is not set or type(i) is not int: msg = "bad entry '%s:%s' in mask" % (str(i),str(j)) raise ValueError(msg) for k in j: # items in the set if not hasattr(k, '__len__') or len(k) != 2: msg = "bad entry '%s:%s' in mask" % (str(i),str(j)) raise ValueError(msg) elif hasattr(mask, '__len__') and len(mask) == 2: if np.array(mask[0]).ndim != 1: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) if np.array(mask[1]).ndim != 2: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) elif hasattr(mask, '__len__') and not len(mask): mask = type(mask)(((),())) #XXX: HACK to get empty where mask else: msg = "%s is not a valid mask" % str(mask) raise TypeError(msg) # is the max position difference less than tolerance across all generations? distances = _m._positions(stepmon, generations) nindices = distances.shape[-1] from mystic.tools import pairwise distances, pairs = pairwise(distances, True) distances = distances.max(axis=0) <= tolerance # select off the desired pairs (of indices) counts = np.cumsum(distances.sum(axis=-1)) import warnings with warnings.catch_warnings(): #FIXME: python2.5 warnings.simplefilter('ignore') #XXX: throws a FutureWarning distances = np.split(np.array((pairs,)*distances.shape[0])[distances], counts)[:-1] counts = (set(tuple(i) for i in j) for j in distances) # return in terms of pairs, b/c indexing alone doesn't give pairings # (keys are measure, and values are (index1,index2) pairs) distances = ((i,j) for (i,j) in enumerate(counts) if len(j)) # identify mask format and build filter select, pairs = _position_filter(mask) # convert to selected format... if pairs: # return explicit 'pairs' {(measure,indices)} import itertools mask = set() for i,j in distances: [mask.add(k) for k in getattr(itertools, 'izip', zip)(*((i,)*len(j), j))] elif pairs is None: # return 'where' format [measures,indices] import itertools # tuple of where,pairs measures,mask = (),() for (i,j) in (getattr(itertools, 'izip', zip)(*((j[0],i) for i in j[1])) for j in distances): measures += i mask += j mask = (measures,mask) if len(measures) else () else: # returns a dict of {measure, indices} mask = dict(distances) # apply mask return select(mask)