def sparse_fill_empty_rows(sp_input, default_value, name=None): """Fills empty rows in the input 2-D `SparseTensor` with a default value. This op adds entries with the specified `default_value` at index `[row, 0]` for any row in the input that does not already have a value. For example, suppose `sp_input` has shape `[5, 6]` and non-empty values: [0, 1]: a [0, 3]: b [2, 0]: c [3, 1]: d Rows 1 and 4 are empty, so the output will be of shape `[5, 6]` with values: [0, 1]: a [0, 3]: b [1, 0]: default_value [2, 0]: c [3, 1]: d [4, 0]: default_value Note that the input may have empty columns at the end, with no effect on this op. The output `SparseTensor` will be in row-major order and will have the same shape as the input. This op also returns an indicator vector such that empty_row_indicator[i] = True iff row i was an empty row. Args: sp_input: A `SparseTensor` with shape `[N, M]`. default_value: The value to fill for empty rows, with the same type as `sp_input.` name: A name prefix for the returned tensors (optional) Returns: sp_ordered_output: A `SparseTensor` with shape `[N, M]`, and with all empty rows filled in with `default_value`. empty_row_indicator: A bool vector of length `N` indicating whether each input row was empty. Raises: TypeError: If `sp_input` is not a `SparseTensor`. """ if not isinstance(sp_input, ops.SparseTensor): raise TypeError("Input must be a SparseTensor") with ops.op_scope([sp_input], name, "SparseFillEmptyRows"): default_value = ops.convert_to_tensor(default_value, dtype=sp_input.values.dtype) num_rows = math_ops.cast(sp_input.shape[0], dtypes.int32) all_row_indices = math_ops.cast(math_ops.range(num_rows), dtypes.int64) empty_row_indices, _ = array_ops.list_diff(all_row_indices, sp_input.indices[:, 0]) empty_row_indicator = sparse_to_dense( empty_row_indices, array_ops.expand_dims(sp_input.shape[0], -1), True, False) empty_row_indices_as_column = array_ops.reshape( empty_row_indices, [-1, 1]) additional_indices = array_ops.concat(1, [ empty_row_indices_as_column, array_ops.zeros_like(empty_row_indices_as_column) ]) additional_values = array_ops.fill(array_ops.shape(empty_row_indices), default_value) all_indices_unordered = array_ops.concat( 0, [sp_input.indices, additional_indices]) all_values_unordered = array_ops.concat( 0, [sp_input.values, additional_values]) sp_unordered_output = ops.SparseTensor(all_indices_unordered, all_values_unordered, sp_input.shape) sp_ordered_output = sparse_reorder(sp_unordered_output) return sp_ordered_output, empty_row_indicator
def sparse_fill_empty_rows(sp_input, default_value, name=None): """Fills empty rows in the input 2-D `SparseTensor` with a default value. This op adds entries with the specified `default_value` at index `[row, 0]` for any row in the input that does not already have a value. For example, suppose `sp_input` has shape `[5, 6]` and non-empty values: [0, 1]: a [0, 3]: b [2, 0]: c [3, 1]: d Rows 1 and 4 are empty, so the output will be of shape `[5, 6]` with values: [0, 1]: a [0, 3]: b [1, 0]: default_value [2, 0]: c [3, 1]: d [4, 0]: default_value Note that the input may have empty columns at the end, with no effect on this op. The output `SparseTensor` will be in row-major order and will have the same shape as the input. This op also returns an indicator vector such that empty_row_indicator[i] = True iff row i was an empty row. Args: sp_input: A `SparseTensor` with shape `[N, M]`. default_value: The value to fill for empty rows, with the same type as `sp_input.` name: A name prefix for the returned tensors (optional) Returns: sp_ordered_output: A `SparseTensor` with shape `[N, M]`, and with all empty rows filled in with `default_value`. empty_row_indicator: A bool vector of length `N` indicating whether each input row was empty. Raises: TypeError: If `sp_input` is not a `SparseTensor`. """ if not isinstance(sp_input, ops.SparseTensor): raise TypeError("Input must be a SparseTensor") with ops.op_scope([sp_input], name, "SparseFillEmptyRows"): default_value = ops.convert_to_tensor(default_value, dtype=sp_input.values.dtype) num_rows = math_ops.cast(sp_input.shape[0], dtypes.int32) all_row_indices = math_ops.cast(math_ops.range(num_rows), dtypes.int64) empty_row_indices, _ = array_ops.list_diff(all_row_indices, sp_input.indices[:, 0]) empty_row_indicator = sparse_to_dense( empty_row_indices, array_ops.expand_dims(sp_input.shape[0], -1), True, False) empty_row_indices_as_column = array_ops.reshape(empty_row_indices, [-1, 1]) additional_indices = array_ops.concat( 1, [empty_row_indices_as_column, array_ops.zeros_like(empty_row_indices_as_column)]) additional_values = array_ops.fill( array_ops.shape(empty_row_indices), default_value) all_indices_unordered = array_ops.concat(0, [sp_input.indices, additional_indices]) all_values_unordered = array_ops.concat(0, [sp_input.values, additional_values]) sp_unordered_output = ops.SparseTensor(all_indices_unordered, all_values_unordered, sp_input.shape) sp_ordered_output = sparse_reorder(sp_unordered_output) return sp_ordered_output, empty_row_indicator