def bounded(seq, bounds, index=None, clip=True, nearest=True): """bound a sequence by bounds = [min,max] For example: >>> sequence = [0.123, 1.244, -4.755, 10.731, 6.207] >>> >>> bounded(sequence, (0,5)) array([0.123, 1.244, 0. , 5. , 5. ]) >>> >>> bounded(sequence, (0,5), index=(0,2,4)) array([ 0.123, 1.244, 0. , 10.731, 5. ]) >>> >>> bounded(sequence, (0,5), clip=False) array([0.123 , 1.244 , 3.46621839, 1.44469038, 4.88937466]) >>> >>> bounds = [(0,5),(7,10)] >>> my.constraints.bounded(sequence, bounds) array([ 0.123, 1.244, 0. , 10. , 7. ]) >>> my.constraints.bounded(sequence, bounds, nearest=False) array([ 0.123, 1.244, 7. , 10. , 5. ]) >>> my.constraints.bounded(sequence, bounds, nearest=False, clip=False) array([0.123 , 1.244 , 0.37617154, 8.79013111, 7.40864242]) >>> my.constraints.bounded(sequence, bounds, clip=False) array([0.123 , 1.244 , 2.38186577, 7.41374049, 9.14662911]) >>> """ seq = array(seq) #XXX: asarray? if bounds is None or not bounds: return seq if isinstance(index, int): index = (index,) if not hasattr(bounds[0], '__len__'): bounds = (bounds,) bounds = asfarray(bounds).T # is [(min,min,...),(max,max,...)] # convert None to -inf or inf bounds[0][isnan(bounds[0])] = -inf bounds[1][isnan(bounds[1])] = inf # find indicies of the elements that are out of bounds at = where(sum((lo <= seq)&(seq <= hi) for (lo,hi) in bounds.T).astype(bool) == False)[-1] # find the intersection of out-of-bound and selected indicies at = at if index is None else intersect1d(at, index) if not len(at): return seq if clip: if nearest: # clip at closest bounds seq_at = seq[at] seq[at] = _clip(seq_at, *(b[abs(seq_at.reshape(-1,1)-b).argmin(axis=1)] for b in bounds)) else: # clip in randomly selected interval picks = choice(len(bounds.T), size=at.shape) seq[at] = _clip(seq[at], bounds[0][picks], bounds[1][picks]) return seq # limit to +/- 1e300 #XXX: better defaults? bounds[0][bounds[0] < -1e300] = -1e300 bounds[1][bounds[1] > 1e300] = 1e300 if nearest: seq_at = seq[at] seq[at] = choose(array([abs(seq_at.reshape(-1,1) - b).min(axis=1) for b in bounds.T]).argmin(axis=0), [uniform(0,1, size=at.shape) * (hi - lo) + lo for (lo,hi) in bounds.T]) else: # randomly choose a value in one of the intervals seq[at] = choose(choice(len(bounds.T), size=at.shape), [uniform(0,1, size=at.shape) * (hi - lo) + lo for (lo,hi) in bounds.T]) return seq
def bounded(seq, bounds, index=None, clip=True, nearest=True): """bound a sequence by bounds = [min,max] For example: >>> sequence = [0.123, 1.244, -4.755, 10.731, 6.207] >>> >>> bounded(sequence, (0,5)) array([0.123, 1.244, 0. , 5. , 5. ]) >>> >>> bounded(sequence, (0,5), index=(0,2,4)) array([ 0.123, 1.244, 0. , 10.731, 5. ]) >>> >>> bounded(sequence, (0,5), clip=False) array([0.123 , 1.244 , 3.46621839, 1.44469038, 4.88937466]) >>> >>> bounds = [(0,5),(7,10)] >>> my.constraints.bounded(sequence, bounds) array([ 0.123, 1.244, 0. , 10. , 7. ]) >>> my.constraints.bounded(sequence, bounds, nearest=False) array([ 0.123, 1.244, 7. , 10. , 5. ]) >>> my.constraints.bounded(sequence, bounds, nearest=False, clip=False) array([0.123 , 1.244 , 0.37617154, 8.79013111, 7.40864242]) >>> my.constraints.bounded(sequence, bounds, clip=False) array([0.123 , 1.244 , 2.38186577, 7.41374049, 9.14662911]) >>> """ seq = array(seq) #XXX: asarray? if bounds is None or not bounds: return seq if isinstance(index, int): index = (index,) if not hasattr(bounds[0], '__len__'): bounds = (bounds,) bounds = asfarray(bounds).T # is [(min,min,...),(max,max,...)] # convert None to -inf or inf bounds[0][bounds[0] == None] = -inf bounds[1][bounds[1] == None] = inf # find indicies of the elements that are out of bounds at = where(sum((lo <= seq)&(seq <= hi) for (lo,hi) in bounds.T).astype(bool) == False)[-1] # find the intersection of out-of-bound and selected indicies at = at if index is None else intersect1d(at, index) if not len(at): return seq if clip: if nearest: # clip at closest bounds seq_at = seq[at] seq[at] = _clip(seq_at, *(b[abs(seq_at.reshape(-1,1)-b).argmin(axis=1)] for b in bounds)) else: # clip in randomly selected interval picks = choice(len(bounds.T), size=at.shape) seq[at] = _clip(seq[at], bounds[0][picks], bounds[1][picks]) return seq # limit to +/- 1e300 #XXX: better defaults? bounds[0][bounds[0] < -1e300] = -1e300 bounds[1][bounds[1] > 1e300] = 1e300 if nearest: seq_at = seq[at] seq[at] = choose(array([abs(seq_at.reshape(-1,1) - b).min(axis=1) for b in bounds.T]).argmin(axis=0), [uniform(0,1, size=at.shape) * (hi - lo) + lo for (lo,hi) in bounds.T]) else: # randomly choose a value in one of the intervals seq[at] = choose(choice(len(bounds.T), size=at.shape), [uniform(0,1, size=at.shape) * (hi - lo) + lo for (lo,hi) in bounds.T]) return seq