def repeat_ranges(params, splits, repeats): """Repeats each range of `params` (as specified by `splits`) `repeats` times. Let the `i`th range of `params` be defined as `params[splits[i]:splits[i + 1]]`. Then this function returns a tensor containing range 0 repeated `repeats[0]` times, followed by range 1 repeated `repeats[1]`, ..., followed by the last range repeated `repeats[-1]` times. Args: params: The `Tensor` whose values should be repeated. splits: A splits tensor indicating the ranges of `params` that should be repeated. repeats: The number of times each range should be repeated. Supports broadcasting from a scalar value. Returns: A `Tensor` with the same rank and type as `params`. #### Example: >>> print(repeat_ranges( ... params=tf.constant(['a', 'b', 'c']), ... splits=tf.constant([0, 2, 3]), ... repeats=tf.constant(3))) tf.Tensor([b'a' b'b' b'a' b'b' b'a' b'b' b'c' b'c' b'c'], shape=(9,), dtype=string) """ # Divide `splits` into starts and limits, and repeat them `repeats` times. if repeats.shape.ndims != 0: repeated_starts = repeat(splits[:-1], repeats, axis=0) repeated_limits = repeat(splits[1:], repeats, axis=0) else: # Optimization: we can just call repeat once, and then slice the result. repeated_splits = repeat(splits, repeats, axis=0) n_splits = array_ops.shape(repeated_splits, out_type=repeats.dtype)[0] repeated_starts = repeated_splits[:n_splits - repeats] repeated_limits = repeated_splits[repeats:] # Get indices for each range from starts to limits, and use those to gather # the values in the desired repetition pattern. one = array_ops.ones((), repeated_starts.dtype) offsets = gen_ragged_math_ops.ragged_range(repeated_starts, repeated_limits, one) return array_ops.gather(params, offsets.rt_dense_values)
def repeat_ranges(params, splits, repeats): """Repeats each range of `params` (as specified by `splits`) `repeats` times. Let the `i`th range of `params` be defined as `params[splits[i]:splits[i + 1]]`. Then this function returns a tensor containing range 0 repeated `repeats[0]` times, followed by range 1 repeated `repeats[1]`, ..., followed by the last range repeated `repeats[-1]` times. Args: params: The `Tensor` whose values should be repeated. splits: A splits tensor indicating the ranges of `params` that should be repeated. repeats: The number of times each range should be repeated. Supports broadcasting from a scalar value. Returns: A `Tensor` with the same rank and type as `params`. #### Example: ```python >>> repeat_ranges(['a', 'b', 'c'], [0, 2, 3], 3) ['a', 'b', 'a', 'b', 'a', 'b', 'c', 'c', 'c'] ``` """ # Divide `splits` into starts and limits, and repeat them `repeats` times. if repeats.shape.ndims != 0: repeated_starts = repeat(splits[:-1], repeats, axis=0) repeated_limits = repeat(splits[1:], repeats, axis=0) else: # Optimization: we can just call repeat once, and then slice the result. repeated_splits = repeat(splits, repeats, axis=0) n_splits = array_ops.shape(repeated_splits, out_type=repeats.dtype)[0] repeated_starts = repeated_splits[:n_splits - repeats] repeated_limits = repeated_splits[repeats:] # Get indices for each range from starts to limits, and use those to gather # the values in the desired repetition pattern. one = array_ops.ones((), repeated_starts.dtype) offsets = gen_ragged_math_ops.ragged_range( repeated_starts, repeated_limits, one) return array_ops.gather(params, offsets.rt_dense_values)
def range(starts, limits=None, deltas=1, dtype=None, name=None): """Returns a `RaggedTensor` containing the specified sequences of numbers. Each row of the returned `RaggedTensor` contains a single sequence: ```python ragged.range(starts, limits, deltas)[i] == tf.range(starts[i], limits[i], deltas[i]) ``` If `start[i] < limits[i] and deltas[i] > 0`, then `output[i]` will be an empty list. Similarly, if `start[i] > limits[i] and deltas[i] < 0`, then `output[i]` will be an empty list. This behavior is consistent with the Python `range` function, but differs from the `tf.range` op, which returns an error for these cases. Examples: ```python >>> ragged.range([3, 5, 2]).eval().tolist() [[0, 1, 2], [0, 1, 2, 3, 4], [0, 1]] >>> ragged.range([0, 5, 8], [3, 3, 12]).eval().tolist() [[0, 1, 2], [], [8, 9, 10, 11]] >>> ragged.range([0, 5, 8], [3, 3, 12], 2).eval().tolist() [[0, 2], [], [8, 10]] ``` The input tensors `starts`, `limits`, and `deltas` may be scalars or vectors. The vector inputs must all have the same size. Scalar inputs are broadcast to match the size of the vector inputs. Args: starts: Vector or scalar `Tensor`. Specifies the first entry for each range if `limits` is not `None`; otherwise, specifies the range limits, and the first entries default to `0`. limits: Vector or scalar `Tensor`. Specifies the exclusive upper limits for each range. deltas: Vector or scalar `Tensor`. Specifies the increment for each range. Defaults to `1`. dtype: The type of the elements of the resulting tensor. If not specified, then a value is chosen based on the other args. name: A name for the operation. Returns: A `RaggedTensor` of type `dtype` with `ragged_rank=1`. """ if limits is None: starts, limits = 0, starts with ops.name_scope(name, 'RaggedRange', [starts, limits, deltas]) as name: starts = ops.convert_to_tensor(starts, dtype=dtype, name='starts') limits = ops.convert_to_tensor(limits, dtype=dtype, name='limits') deltas = ops.convert_to_tensor(deltas, dtype=dtype, name='deltas') # infer dtype if not explicitly provided if dtype is None: starts, limits, deltas = _infer_matching_dtype( [starts, limits, deltas], [dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64]) result = gen_ragged_math_ops.ragged_range(starts, limits, deltas, name=name) return ragged_factory_ops.from_row_splits(result.rt_dense_values, result.rt_nested_splits)
def range(starts, limits=None, deltas=1, dtype=None, name=None, row_splits_dtype=dtypes.int64): """Returns a `RaggedTensor` containing the specified sequences of numbers. Each row of the returned `RaggedTensor` contains a single sequence: ```python ragged.range(starts, limits, deltas)[i] == tf.range(starts[i], limits[i], deltas[i]) ``` If `start[i] < limits[i] and deltas[i] > 0`, then `output[i]` will be an empty list. Similarly, if `start[i] > limits[i] and deltas[i] < 0`, then `output[i]` will be an empty list. This behavior is consistent with the Python `range` function, but differs from the `tf.range` op, which returns an error for these cases. Examples: >>> tf.ragged.range([3, 5, 2]).to_list() [[0, 1, 2], [0, 1, 2, 3, 4], [0, 1]] >>> tf.ragged.range([0, 5, 8], [3, 3, 12]).to_list() [[0, 1, 2], [], [8, 9, 10, 11]] >>> tf.ragged.range([0, 5, 8], [3, 3, 12], 2).to_list() [[0, 2], [], [8, 10]] The input tensors `starts`, `limits`, and `deltas` may be scalars or vectors. The vector inputs must all have the same size. Scalar inputs are broadcast to match the size of the vector inputs. Args: starts: Vector or scalar `Tensor`. Specifies the first entry for each range if `limits` is not `None`; otherwise, specifies the range limits, and the first entries default to `0`. limits: Vector or scalar `Tensor`. Specifies the exclusive upper limits for each range. deltas: Vector or scalar `Tensor`. Specifies the increment for each range. Defaults to `1`. dtype: The type of the elements of the resulting tensor. If not specified, then a value is chosen based on the other args. name: A name for the operation. row_splits_dtype: `dtype` for the returned `RaggedTensor`'s `row_splits` tensor. One of `tf.int32` or `tf.int64`. Returns: A `RaggedTensor` of type `dtype` with `ragged_rank=1`. """ row_splits_dtype = dtypes.as_dtype(row_splits_dtype) if limits is None: starts, limits = 0, starts with ops.name_scope(name, 'RaggedRange', [starts, limits, deltas]) as name: starts = ops.convert_to_tensor(starts, dtype=dtype, name='starts') limits = ops.convert_to_tensor(limits, dtype=dtype, name='limits') deltas = ops.convert_to_tensor(deltas, dtype=dtype, name='deltas') # infer dtype if not explicitly provided if dtype is None: starts, limits, deltas = _infer_matching_dtype( [starts, limits, deltas], [dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64]) result = gen_ragged_math_ops.ragged_range( starts, limits, deltas, Tsplits=row_splits_dtype, name=name) return ragged_tensor.RaggedTensor.from_row_splits( result.rt_dense_values, result.rt_nested_splits, validate=False)