def from_tuples(cls, bounds: Iterable[tuple]) -> "Bounds": """ Instantiate a :class:`Bounds` from a collection of tuples containing \ the higher and lower bounds for every dimension as a tuple. Args: bounds: Iterable that returns tuples containing the higher and lower \ bound for every dimension of the target bounds. Returns: :class:`Bounds` instance. Examples: >>> intervals = ((-1, 1), (-2, 1), (2, 3)) >>> bounds = Bounds.from_tuples(intervals) >>> print(bounds) Bounds shape int64 dtype (3,) low [-1 -2 2] high [1 1 3] """ low, high = [], [] for lo, hi in bounds: low.append(lo) high.append(hi) low, high = tensor(low, dtype=dtype.float), tensor(high, dtype=dtype.float) return Bounds(low=low, high=high)
def merge_one_name(states_list, name): vals = [] for state in states_list: data = state[name] # Attributes that are not tensors are not stacked. if not judo.is_tensor(data): return data state_len = len(state) if len(data.shape) == 0 and state_len == 1: # Name is scalar vector. Data is typing.Scalar value. Transform to array first value = tensor([data]).flatten() elif len(data.shape) == 1 and state_len == 1: if data.shape[0] == 1: # Name is typing.Scalar vector. Data already transformed to an array value = data else: # Name is a matrix of vectors. Data needs an additional dimension value = tensor([data]) elif len(data.shape) == 1 and state_len > 1: # Name is a typing.Scalar vector. Data already has is a one dimensional array value = data elif (len(data.shape) > 1 and state_len > 1 or len(data.shape) > 1 and len(state) == 1): # Name is a matrix of vectors. Data has the correct shape value = data else: raise ValueError( "Could not infer data concatenation for attribute %s with shape %s" % (name, data.shape), ) vals.append(value) return API.concatenate(vals)
def calculate_clone(virtual_rewards: Tensor, oobs: Tensor = None, eps=1e-3): """Calculate the clone indexes and masks from the virtual rewards.""" compas_ix = get_alive_indexes(oobs) if oobs is not None else judo.arange( len(virtual_rewards)) compas_ix = random_state.permutation(compas_ix) vir_rew = virtual_rewards.flatten() clone_probs = (vir_rew[compas_ix] - vir_rew) / judo.where( vir_rew > eps, vir_rew, tensor(eps)) will_clone = clone_probs.flatten() > random_state.random(len(clone_probs)) return compas_ix, will_clone
def get_scaled_intervals( low: Union[Tensor, float, int], high: Union[Tensor, float, int], scale: float, ) -> Tuple[Union[Tensor, float], Union[Tensor, float]]: """ Scale the high and low vectors by an scale factor. The value of the high and low will be proportional to the maximum and minimum values of \ the array. Scale defines the proportion to make the bounds bigger and smaller. For \ example, if scale is 1.1 the higher bound will be 10% higher, and the lower bounds 10% \ smaller. If scale is 0.9 the higher bound will be 10% lower, and the lower bound 10% \ higher. If scale is one, `high` and `low` will be equal to the maximum and minimum values \ of the array. Args: high: Higher bound to be scaled. low: Lower bound to be scaled. scale: Value representing the tolerance in percentage from the current maximum and \ minimum values of the array. Returns: :class:`Bounds` instance. """ pct = tensor(scale - 1) big_scale = 1 + API.abs(pct) small_scale = 1 - API.abs(pct) zero = judo.astype(tensor(0.0), low.dtype) if pct > 0: xmin_scaled = API.where(low < zero, low * big_scale, low * small_scale) xmax_scaled = API.where(high < zero, high * small_scale, high * big_scale) else: xmin_scaled = API.where(low < zero, low * small_scale, low * small_scale) xmax_scaled = API.where(high < zero, high * big_scale, high * small_scale) return xmin_scaled, xmax_scaled
def cross_clone( host_virtual_rewards: Tensor, ext_virtual_rewards: Tensor, host_oobs: Tensor = None, eps=1e-3, ): """Perform a clone operation between two different groups of points.""" compas_ix = random_state.permutation(judo.arange(len(ext_virtual_rewards))) host_vr = judo.astype(host_virtual_rewards.flatten(), dtype=dtype.float32) ext_vr = judo.astype(ext_virtual_rewards.flatten(), dtype=dtype.float32) clone_probs = (ext_vr[compas_ix] - host_vr) / judo.where( ext_vr > eps, ext_vr, tensor(eps, dtype=dtype.float32)) will_clone = clone_probs.flatten() > random_state.random(len(clone_probs)) if host_oobs is not None: will_clone[host_oobs] = True return compas_ix, will_clone
def __init__( self, high: Union[Tensor, Scalar] = numpy.inf, low: Union[Tensor, Scalar] = numpy.NINF, shape: Optional[tuple] = None, dtype: Optional[type] = None, ): """ Initialize a :class:`Bounds`. Args: high: Higher value for the bound interval. If it is an typing_.Scalar \ it will be applied to all the coordinates of a target vector. \ If it is a vector, the bounds will be checked coordinate-wise. \ It defines and closed interval. low: Lower value for the bound interval. If it is a typing_.Scalar it \ will be applied to all the coordinates of a target vector. \ If it is a vector, the bounds will be checked coordinate-wise. \ It defines and closed interval. shape: Shape of the array that will be bounded. Only needed if `high` and `low` are \ vectors and it is used to define the dimensions that will be bounded. dtype: Data type of the array that will be bounded. It can be inferred from `high` \ or `low` (the type of `high` takes priority). Examples: Initializing :class:`Bounds` using numpy arrays: >>> import numpy >>> high, low = numpy.ones(3, dtype=float), -1 * numpy.ones(3, dtype=int) >>> bounds = Bounds(high=high, low=low) >>> print(bounds) Bounds shape float64 dtype (3,) low [-1 -1 -1] high [1. 1. 1.] Initializing :class:`Bounds` using typing_.Scalars: >>> import numpy >>> high, low, shape = 4, 2.1, (5,) >>> bounds = Bounds(high=high, low=low, shape=shape) >>> print(bounds) Bounds shape float64 dtype (5,) low [2.1 2.1 2.1 2.1 2.1] high [4. 4. 4. 4. 4.] """ # Infer shape if not specified if shape is None and hasattr(high, "shape"): shape = high.shape elif shape is None and hasattr(low, "shape"): shape = low.shape elif shape is None: raise TypeError( "If shape is None high or low need to have .shape attribute.") # High and low will be arrays of target shape if not judo.is_tensor(high): high = tensor(high) if isinstance( high, _Iterable) else API.ones(shape) * high if not judo.is_tensor(low): low = tensor(low) if isinstance( low, _Iterable) else API.ones(shape) * low self.high = judo.astype(high, dtype) self.low = judo.astype(low, dtype) if dtype is not None: self.dtype = dtype elif hasattr(high, "dtype"): self.dtype = high.dtype elif hasattr(low, "dtype"): self.dtype = low.dtype else: self.dtype = type(high) if high is not None else type(low)
def clip(x, a_min, a_max, out=None): _tensor = min(x, other=astype(tensor(a_max), dtype=x.dtype)) return max(_tensor, other=astype(tensor(a_min), dtype=x.dtype), out=out)