1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15
16# pylint: disable=g-short-docstring-punctuation
17"""Sparse Tensor Representation. See the @{$python/sparse_ops} guide.
18
19@@SparseTensor
20@@SparseTensorValue
21@@sparse_to_dense
22@@sparse_tensor_to_dense
23@@sparse_to_indicator
24@@sparse_merge
25@@sparse_concat
26@@sparse_reorder
27@@sparse_reshape
28@@sparse_slice
29@@sparse_split
30@@sparse_retain
31@@sparse_reset_shape
32@@sparse_fill_empty_rows
33@@sparse_transpose
34@@sparse_reduce_max
35@@sparse_reduce_max_sparse
36@@sparse_reduce_sum
37@@sparse_reduce_sum_sparse
38@@sparse_add
39@@sparse_softmax
40@@sparse_tensor_dense_matmul
41@@sparse_maximum
42@@sparse_minimum
43"""
44
45from __future__ import absolute_import
46from __future__ import division
47from __future__ import print_function
48
49import collections
50import numbers
51
52import numpy as np
53
54from tensorflow.python.framework import dtypes
55from tensorflow.python.framework import ops
56from tensorflow.python.framework import sparse_tensor
57from tensorflow.python.framework import tensor_util
58from tensorflow.python.ops import array_ops
59from tensorflow.python.ops import check_ops
60from tensorflow.python.ops import control_flow_ops
61from tensorflow.python.ops import gen_sparse_ops
62from tensorflow.python.ops import math_ops
63# go/tf-wildcard-import
64# pylint: disable=wildcard-import
65from tensorflow.python.ops.gen_sparse_ops import *
66# pylint: enable=wildcard-import
67from tensorflow.python.util import deprecation
68from tensorflow.python.util.tf_export import tf_export
69
70
71def _convert_to_sparse_tensor(sp_input):
72  """Convert `sp_input` to `SparseTensor` and return it.
73
74  Args:
75    sp_input: `SparseTensor` or `SparseTensorValue`.
76
77  Returns:
78    `sp_input` converted to `SparseTensor`.
79
80  Raises:
81    ValueError: if `sp_input` is neither `SparseTensor` nor `SparseTensorValue`.
82  """
83  if isinstance(sp_input, sparse_tensor.SparseTensorValue):
84    return sparse_tensor.SparseTensor.from_value(sp_input)
85  if not isinstance(sp_input, sparse_tensor.SparseTensor):
86    raise TypeError("Input must be a SparseTensor.")
87  return sp_input
88
89
90def _convert_to_sparse_tensors(sp_inputs):
91  """Convert `sp_inputs` to `SparseTensor` objects and return them.
92
93  Args:
94    sp_inputs: `list` or `tuple` of `SparseTensor` or `SparseTensorValue`
95      objects.
96
97  Returns:
98    `sp_inputs` converted to `SparseTensor` objects.
99
100  Raises:
101    ValueError: if any item in `sp_inputs` is neither `SparseTensor` nor
102      `SparseTensorValue`.
103  """
104  if isinstance(sp_inputs, list):
105    return [_convert_to_sparse_tensor(sp_input) for sp_input in sp_inputs]
106  if isinstance(sp_inputs, tuple):
107    return (_convert_to_sparse_tensor(sp_input) for sp_input in sp_inputs)
108  raise TypeError("Inputs must be a list or tuple.")
109
110
111# pylint: disable=protected-access
112@tf_export("sparse_concat")
113def sparse_concat(axis,
114                  sp_inputs,
115                  name=None,
116                  expand_nonconcat_dim=False,
117                  concat_dim=None):
118  """Concatenates a list of `SparseTensor` along the specified dimension.
119
120  Concatenation is with respect to the dense versions of each sparse input.
121  It is assumed that each inputs is a `SparseTensor` whose elements are ordered
122  along increasing dimension number.
123
124  If expand_nonconcat_dim is False, all inputs' shapes must match, except for
125  the concat dimension. If expand_nonconcat_dim is True, then inputs' shapes are
126  allowed to vary among all inputs.
127
128  The `indices`, `values`, and `shapes` lists must have the same length.
129
130  If expand_nonconcat_dim is False, then the output shape is identical to the
131  inputs', except along the concat dimension, where it is the sum of the inputs'
132  sizes along that dimension.
133
134  If expand_nonconcat_dim is True, then the output shape along the non-concat
135  dimensions will be expand to be the largest among all inputs, and it is the
136  sum of the inputs sizes along the concat dimension.
137
138  The output elements will be resorted to preserve the sort order along
139  increasing dimension number.
140
141  This op runs in `O(M log M)` time, where `M` is the total number of non-empty
142  values across all inputs. This is due to the need for an internal sort in
143  order to concatenate efficiently across an arbitrary dimension.
144
145  For example, if `axis = 1` and the inputs are
146
147      sp_inputs[0]: shape = [2, 3]
148      [0, 2]: "a"
149      [1, 0]: "b"
150      [1, 1]: "c"
151
152      sp_inputs[1]: shape = [2, 4]
153      [0, 1]: "d"
154      [0, 2]: "e"
155
156  then the output will be
157
158      shape = [2, 7]
159      [0, 2]: "a"
160      [0, 4]: "d"
161      [0, 5]: "e"
162      [1, 0]: "b"
163      [1, 1]: "c"
164
165  Graphically this is equivalent to doing
166
167      [    a] concat [  d e  ] = [    a   d e  ]
168      [b c  ]        [       ]   [b c          ]
169
170  Another example, if 'axis = 1' and the inputs are
171
172      sp_inputs[0]: shape = [3, 3]
173      [0, 2]: "a"
174      [1, 0]: "b"
175      [2, 1]: "c"
176
177      sp_inputs[1]: shape = [2, 4]
178      [0, 1]: "d"
179      [0, 2]: "e"
180
181  if expand_nonconcat_dim = False, this will result in an error. But if
182  expand_nonconcat_dim = True, this will result in:
183
184      shape = [3, 7]
185      [0, 2]: "a"
186      [0, 4]: "d"
187      [0, 5]: "e"
188      [1, 0]: "b"
189      [2, 1]: "c"
190
191  Graphically this is equivalent to doing
192
193      [    a] concat [  d e  ] = [    a   d e  ]
194      [b    ]        [       ]   [b            ]
195      [  c  ]                    [  c          ]
196
197
198  Args:
199    axis: Dimension to concatenate along. Must be in range [-rank, rank),
200      where rank is the number of dimensions in each input `SparseTensor`.
201    sp_inputs: List of `SparseTensor` to concatenate.
202    name: A name prefix for the returned tensors (optional).
203    expand_nonconcat_dim: Whether to allow the expansion in the non-concat
204      dimensions. Defaulted to False.
205    concat_dim: The old (deprecated) name for axis.
206
207  Returns:
208    A `SparseTensor` with the concatenated output.
209
210  Raises:
211    TypeError: If `sp_inputs` is not a list of `SparseTensor`.
212  """
213  axis = deprecation.deprecated_argument_lookup("axis", axis, "concat_dim",
214                                                concat_dim)
215  sp_inputs = _convert_to_sparse_tensors(sp_inputs)
216
217  if len(sp_inputs) == 1:  # Degenerate case of one tensor.
218    return sp_inputs[0]
219
220  inds = [sp_input.indices for sp_input in sp_inputs]
221  vals = [sp_input.values for sp_input in sp_inputs]
222  shapes = [sp_input.dense_shape for sp_input in sp_inputs]
223
224  if expand_nonconcat_dim:
225    max_shape = math_ops.reduce_max(
226        array_ops.concat(
227            [array_ops.reshape(shape, [1, -1]) for shape in shapes], 0), 0)
228    shapes = [
229        array_ops.concat([
230            max_shape[:axis], shape[-1:]
231            if axis == -1 else shape[axis:axis + 1], []
232            if axis == -1 else max_shape[axis + 1:]
233        ], 0) for shape in shapes
234    ]
235
236  output_ind, output_val, output_shape = (
237      gen_sparse_ops._sparse_concat(inds, vals, shapes, axis, name=name))
238
239  return sparse_tensor.SparseTensor(output_ind, output_val, output_shape)
240
241
242@tf_export("sparse_add")
243def sparse_add(a, b, thresh=0):
244  """Adds two tensors, at least one of each is a `SparseTensor`.
245
246  If one `SparseTensor` and one `Tensor` are passed in, returns a `Tensor`.  If
247  both arguments are `SparseTensor`s, this returns a `SparseTensor`.  The order
248  of arguments does not matter.  Use vanilla `tf.add()` for adding two dense
249  `Tensor`s.
250
251  The shapes of the two operands must match: broadcasting is not supported.
252
253  The indices of any input `SparseTensor` are assumed ordered in standard
254  lexicographic order.  If this is not the case, before this step run
255  `SparseReorder` to restore index ordering.
256
257  If both arguments are sparse, we perform "clipping" as follows.  By default,
258  if two values sum to zero at some index, the output `SparseTensor` would still
259  include that particular location in its index, storing a zero in the
260  corresponding value slot.  To override this, callers can specify `thresh`,
261  indicating that if the sum has a magnitude strictly smaller than `thresh`, its
262  corresponding value and index would then not be included.  In particular,
263  `thresh == 0.0` (default) means everything is kept and actual thresholding
264  happens only for a positive value.
265
266  For example, suppose the logical sum of two sparse operands is (densified):
267
268      [       2]
269      [.1     0]
270      [ 6   -.2]
271
272  Then,
273
274      * `thresh == 0` (the default): all 5 index/value pairs will be returned.
275      * `thresh == 0.11`: only .1 and 0 will vanish, and the remaining three
276          index/value pairs will be returned.
277      * `thresh == 0.21`: .1, 0, and -.2 will vanish.
278
279  Args:
280    a: The first operand; `SparseTensor` or `Tensor`.
281    b: The second operand; `SparseTensor` or `Tensor`.  At least one operand
282      must be sparse.
283    thresh: A 0-D `Tensor`.  The magnitude threshold that determines if an
284    output value/index pair takes space.  Its dtype should match that of the
285    values if they are real; if the latter are complex64/complex128, then the
286    dtype should be float32/float64, correspondingly.
287
288  Returns:
289    A `SparseTensor` or a `Tensor`, representing the sum.
290
291  Raises:
292    TypeError: If both `a` and `b` are `Tensor`s.  Use `tf.add()` instead.
293  """
294  sparse_classes = (sparse_tensor.SparseTensor, sparse_tensor.SparseTensorValue)
295  if not any(isinstance(inp, sparse_classes) for inp in [a, b]):
296    raise TypeError("At least one input should be SparseTensor; do you mean to"
297                    " use tf.add()?")
298
299  if all(isinstance(inp, sparse_classes) for inp in [a, b]):
300    a = _convert_to_sparse_tensor(a)
301    b = _convert_to_sparse_tensor(b)
302    thresh = ops.convert_to_tensor(
303        thresh, dtype=a.values.dtype.real_dtype.base_dtype, name="thresh")
304    output_ind, output_val, output_shape = (
305        gen_sparse_ops._sparse_add(a.indices, a.values, a.dense_shape,
306                                   b.indices, b.values, b.dense_shape, thresh))
307
308    # Attempt to get output_shape statically.
309    a.get_shape().assert_is_compatible_with(b.get_shape())
310    static_shape = array_ops.broadcast_static_shape(a.get_shape(),
311                                                    b.get_shape())
312    if static_shape.is_fully_defined():
313      output_shape = static_shape.as_list()
314
315    return sparse_tensor.SparseTensor(output_ind, output_val, output_shape)
316  else:
317    # swap to make `a` the SparseTensor.
318    if isinstance(b, sparse_classes):
319      a, b = b, a
320    return gen_sparse_ops._sparse_tensor_dense_add(a.indices, a.values,
321                                                   a.dense_shape, b)
322
323
324def _sparse_cross(inputs, name=None):
325  """Generates sparse cross from a list of sparse and dense tensors.
326
327  For example, if the inputs are
328  * inputs[0]: SparseTensor with shape = [2, 2]
329    [0, 0]: "a"
330    [1, 0]: "b"
331    [1, 1]: "c"
332  * inputs[1]: SparseTensor with shape = [2, 1]
333    [0, 0]: "d"
334    [1, 0]: "e"
335  * inputs[2]: Tensor [["f"], ["g"]]
336
337  then the output will be:
338    shape = [2, 2]
339    [0, 0]: "a_X_d_X_f"
340    [1, 0]: "b_X_e_X_g"
341    [1, 1]: "c_X_e_X_g"
342
343  Args:
344    inputs: An iterable of `Tensor` or `SparseTensor`.
345    name: Optional name for the op.
346
347  Returns:
348    A `SparseTensor` of type `string`.
349  """
350  return _sparse_cross_internal(inputs=inputs, hashed_output=False, name=name)
351
352
353def _sparse_cross_hashed(inputs, num_buckets=0, hash_key=None, name=None):
354  """Generates hashed sparse cross from a list of sparse and dense tensors.
355
356  For example, if the inputs are
357  * inputs[0]: SparseTensor with shape = [2, 2]
358    [0, 0]: "a"
359    [1, 0]: "b"
360    [1, 1]: "c"
361  * inputs[1]: SparseTensor with shape = [2, 1]
362    [0, 0]: "d"
363    [1, 0]: "e"
364  * inputs[2]: Tensor [["f"], ["g"]]
365
366  then the output will be:
367    shape = [2, 2]
368    [0, 0]: FingerprintCat64(
369                Fingerprint64("f"), FingerprintCat64(
370                    Fingerprint64("d"), Fingerprint64("a")))
371    [1, 0]: FingerprintCat64(
372                Fingerprint64("g"), FingerprintCat64(
373                    Fingerprint64("e"), Fingerprint64("b")))
374    [1, 1]: FingerprintCat64(
375                Fingerprint64("g"), FingerprintCat64(
376                    Fingerprint64("e"), Fingerprint64("c")))
377
378  Args:
379    inputs: An iterable of `Tensor` or `SparseTensor`.
380    num_buckets: An `int` that is `>= 0`.
381      output = hashed_value%num_buckets if num_buckets > 0 else hashed_value.
382    hash_key: Integer hash_key that will be used by the `FingerprintCat64`
383      function. If not given, will use a default key.
384    name: Optional name for the op.
385
386  Returns:
387    A `SparseTensor` of type `int64`.
388  """
389  return _sparse_cross_internal(
390      inputs=inputs,
391      hashed_output=True,
392      num_buckets=num_buckets,
393      hash_key=hash_key,
394      name=name)
395
396
397_DEFAULT_HASH_KEY = 0xDECAFCAFFE
398
399
400def _sparse_cross_internal(inputs,
401                           hashed_output=False,
402                           num_buckets=0,
403                           hash_key=None,
404                           name=None):
405  """See gen_sparse_ops._sparse_cross."""
406  if not isinstance(inputs, list):
407    raise TypeError("Inputs must be a list")
408  if not all(
409      isinstance(i, sparse_tensor.SparseTensor) or isinstance(i, ops.Tensor)
410      for i in inputs):
411    raise TypeError("All inputs must be SparseTensors")
412
413  sparse_inputs = [
414      i for i in inputs if isinstance(i, sparse_tensor.SparseTensor)
415  ]
416  dense_inputs = [
417      i for i in inputs if not isinstance(i, sparse_tensor.SparseTensor)
418  ]
419
420  indices = [sp_input.indices for sp_input in sparse_inputs]
421  values = [sp_input.values for sp_input in sparse_inputs]
422  shapes = [sp_input.dense_shape for sp_input in sparse_inputs]
423  out_type = dtypes.int64 if hashed_output else dtypes.string
424
425  internal_type = dtypes.string
426  for i in range(len(values)):
427    if values[i].dtype != dtypes.string:
428      values[i] = math_ops.to_int64(values[i])
429      internal_type = dtypes.int64
430  for i in range(len(dense_inputs)):
431    if dense_inputs[i].dtype != dtypes.string:
432      dense_inputs[i] = math_ops.to_int64(dense_inputs[i])
433      internal_type = dtypes.int64
434
435  indices_out, values_out, shape_out = gen_sparse_ops._sparse_cross(
436      indices=indices,
437      values=values,
438      shapes=shapes,
439      dense_inputs=dense_inputs,
440      hashed_output=hashed_output,
441      num_buckets=num_buckets,
442      hash_key=hash_key or _DEFAULT_HASH_KEY,
443      out_type=out_type,
444      internal_type=internal_type,
445      name=name)
446
447  return sparse_tensor.SparseTensor(indices_out, values_out, shape_out)
448
449
450def sparse_dense_cwise_add(sp_t, dense_t):
451  """Adds up a SparseTensor and a dense Tensor, using these special rules:
452
453  (1) Broadcasts the dense side to have the same shape as the sparse side, if
454      eligible;
455  (2) Then, only the dense values pointed to by the indices of the SparseTensor
456      participate in the cwise addition.
457
458  By the rules, the result is a logical SparseTensor with exactly the same
459  indices and shape, but possibly with different non-zero values.  The output of
460  this Op is the resultant non-zero values.
461
462  Args:
463    sp_t: the SparseTensor operand.
464    dense_t: the dense Tensor operand; must have the same dtype and a
465      broadcast-compatible shape as `sp_t`.
466
467  Returns:
468    output: the SparseTensor output.
469  """
470  result = gen_sparse_ops.sparse_dense_cwise_add(sp_t.indices, sp_t.values,
471                                                 sp_t.dense_shape, dense_t)
472  return sparse_tensor.SparseTensor(sp_t.indices, result, sp_t.dense_shape)
473
474
475@tf_export("sparse_reorder")
476def sparse_reorder(sp_input, name=None):
477  """Reorders a `SparseTensor` into the canonical, row-major ordering.
478
479  Note that by convention, all sparse ops preserve the canonical ordering
480  along increasing dimension number. The only time ordering can be violated
481  is during manual manipulation of the indices and values to add entries.
482
483  Reordering does not affect the shape of the `SparseTensor`.
484
485  For example, if `sp_input` has shape `[4, 5]` and `indices` / `values`:
486
487      [0, 3]: b
488      [0, 1]: a
489      [3, 1]: d
490      [2, 0]: c
491
492  then the output will be a `SparseTensor` of shape `[4, 5]` and
493  `indices` / `values`:
494
495      [0, 1]: a
496      [0, 3]: b
497      [2, 0]: c
498      [3, 1]: d
499
500  Args:
501    sp_input: The input `SparseTensor`.
502    name: A name prefix for the returned tensors (optional)
503
504  Returns:
505    A `SparseTensor` with the same shape and non-empty values, but in
506    canonical ordering.
507
508  Raises:
509    TypeError: If `sp_input` is not a `SparseTensor`.
510  """
511  sp_input = _convert_to_sparse_tensor(sp_input)
512
513  reordered_ind, reordered_val = (
514      gen_sparse_ops._sparse_reorder(
515          sp_input.indices, sp_input.values, sp_input.dense_shape, name=name))
516
517  if sp_input.get_shape().is_fully_defined():
518    dense_shape = sp_input.get_shape().as_list()
519  else:
520    dense_shape = array_ops.identity(sp_input.dense_shape)
521
522  return sparse_tensor.SparseTensor(reordered_ind, reordered_val, dense_shape)
523
524
525@tf_export("sparse_reshape")
526def sparse_reshape(sp_input, shape, name=None):
527  """Reshapes a `SparseTensor` to represent values in a new dense shape.
528
529  This operation has the same semantics as `reshape` on the represented dense
530  tensor.  The indices of non-empty values in `sp_input` are recomputed based
531  on the new dense shape, and a new `SparseTensor` is returned containing the
532  new indices and new shape.  The order of non-empty values in `sp_input` is
533  unchanged.
534
535  If one component of `shape` is the special value -1, the size of that
536  dimension is computed so that the total dense size remains constant.  At
537  most one component of `shape` can be -1.  The number of dense elements
538  implied by `shape` must be the same as the number of dense elements
539  originally represented by `sp_input`.
540
541  For example, if `sp_input` has shape `[2, 3, 6]` and `indices` / `values`:
542
543      [0, 0, 0]: a
544      [0, 0, 1]: b
545      [0, 1, 0]: c
546      [1, 0, 0]: d
547      [1, 2, 3]: e
548
549  and `shape` is `[9, -1]`, then the output will be a `SparseTensor` of
550  shape `[9, 4]` and `indices` / `values`:
551
552      [0, 0]: a
553      [0, 1]: b
554      [1, 2]: c
555      [4, 2]: d
556      [8, 1]: e
557
558  Args:
559    sp_input: The input `SparseTensor`.
560    shape: A 1-D (vector) int64 `Tensor` specifying the new dense shape of the
561      represented `SparseTensor`.
562    name: A name prefix for the returned tensors (optional)
563
564  Returns:
565    A `SparseTensor` with the same non-empty values but with indices calculated
566    by the new dense shape.
567
568  Raises:
569    TypeError: If `sp_input` is not a `SparseTensor`.
570    ValueError:  If argument `shape` requests a `SparseTensor` with a different
571      number of elements than `sp_input`.
572    ValueError:  If `shape` has more than one inferred (== -1) dimension.
573  """
574  sp_input = _convert_to_sparse_tensor(sp_input)
575  shape = math_ops.cast(shape, dtype=dtypes.int64)
576
577  with ops.name_scope(name, "SparseReshape", [sp_input]) as name:
578    reshaped_ind, reshaped_shape = gen_sparse_ops._sparse_reshape(
579        sp_input.indices, sp_input.dense_shape, shape, name=name)
580
581    reshaped_shape_const = tensor_util.constant_value(shape)
582    if (reshaped_shape_const is not None and
583        sp_input.get_shape().is_fully_defined()):
584      num_implied = sum((dim == -1) for dim in reshaped_shape_const)
585      if num_implied > 1:
586        raise ValueError("At most one dimension can be inferred (-1). Found: %s"
587                         % reshaped_shape_const)
588      original_reshaped_shape = list(reshaped_shape_const)  # Copy.
589      in_shape_size = np.prod(sp_input.get_shape().as_list())
590      if num_implied:
591        implied_idx = original_reshaped_shape.index(-1)
592        non_implied_idx = (
593            original_reshaped_shape[:implied_idx] +
594            original_reshaped_shape[implied_idx + 1:])
595        reshaped_shape_const[implied_idx] = (
596            in_shape_size // np.prod(non_implied_idx))
597      reshaped_size = np.prod(reshaped_shape_const)
598      if reshaped_size != in_shape_size:
599        raise ValueError("Cannot reshape a tensor with %d elements to shape %s "
600                         "(%d elements)." %
601                         (in_shape_size, original_reshaped_shape,
602                          reshaped_size))
603      reshaped_shape = reshaped_shape_const
604
605    return sparse_tensor.SparseTensor(reshaped_ind,
606                                      array_ops.identity(sp_input.values),
607                                      reshaped_shape)
608
609
610# TODO(aselle): Remove keyword required once for 1.0 final
611class KeywordRequired(object):
612
613  def __repr__(self):
614    # This is needed to make documentation without fully qualified module paths
615    return "KeywordRequired()"
616
617
618@tf_export("sparse_split")
619def sparse_split(keyword_required=KeywordRequired(),
620                 sp_input=None,
621                 num_split=None,
622                 axis=None,
623                 name=None,
624                 split_dim=None):
625  """Split a `SparseTensor` into `num_split` tensors along `axis`.
626
627  If the `sp_input.dense_shape[axis]` is not an integer multiple of `num_split`
628  each slice starting from 0:`shape[axis] % num_split` gets extra one
629  dimension. For example, if `axis = 1` and `num_split = 2` and the
630  input is:
631
632      input_tensor = shape = [2, 7]
633      [    a   d e  ]
634      [b c          ]
635
636  Graphically the output tensors are:
637
638      output_tensor[0] =
639      [    a ]
640      [b c   ]
641
642      output_tensor[1] =
643      [ d e  ]
644      [      ]
645
646  Args:
647    keyword_required: Python 2 standin for * (temporary for argument reorder)
648    sp_input: The `SparseTensor` to split.
649    num_split: A Python integer. The number of ways to split.
650    axis: A 0-D `int32` `Tensor`. The dimension along which to split.
651    name: A name for the operation (optional).
652    split_dim: Deprecated old name for axis.
653
654  Returns:
655    `num_split` `SparseTensor` objects resulting from splitting `value`.
656
657  Raises:
658    TypeError: If `sp_input` is not a `SparseTensor`.
659    ValueError: If the deprecated `split_dim` and `axis` are both non None.
660  """
661  if not isinstance(keyword_required, KeywordRequired):
662    raise ValueError("Keyword arguments are required for this function.")
663  if sp_input is None:
664    raise ValueError("sp_input is required")
665  if num_split is None:
666    raise ValueError("num_split is required")
667  if axis is None:
668    raise ValueError("axis is required")
669  axis = deprecation.deprecated_argument_lookup("axis", axis, "split_dim",
670                                                split_dim)
671  sp_input = _convert_to_sparse_tensor(sp_input)
672
673  output_inds, output_vals, output_shapes = (
674      gen_sparse_ops._sparse_split(
675          axis,
676          sp_input.indices,
677          sp_input.values,
678          sp_input.dense_shape,
679          num_split,
680          name=name))
681  sparse_tensors = []
682  for i in range(0, num_split):
683    sparse_tensors.append(
684        sparse_tensor.SparseTensor(output_inds[i], output_vals[i],
685                                   output_shapes[i]))
686  return sparse_tensors
687
688
689@tf_export("sparse_slice")
690def sparse_slice(sp_input, start, size, name=None):
691  """Slice a `SparseTensor` based on the `start` and `size.
692
693  For example, if the input is
694
695      input_tensor = shape = [2, 7]
696      [    a   d e  ]
697      [b c          ]
698
699  Graphically the output tensors are:
700
701      sparse_slice([0, 0], [2, 4]) = shape = [2, 4]
702      [    a  ]
703      [b c    ]
704
705      sparse_slice([0, 4], [2, 3]) = shape = [2, 3]
706      [ d e  ]
707      [      ]
708
709  Args:
710    sp_input: The `SparseTensor` to split.
711    start: 1-D. tensor represents the start of the slice.
712    size: 1-D. tensor represents the size of the slice.
713    name: A name for the operation (optional).
714
715  Returns:
716    A `SparseTensor` objects resulting from splicing.
717
718  Raises:
719    TypeError: If `sp_input` is not a `SparseTensor`.
720  """
721  sp_input = _convert_to_sparse_tensor(sp_input)
722  start = ops.convert_to_tensor(start, dtypes.int64)
723  size = ops.convert_to_tensor(size, dtypes.int64)
724
725  with ops.name_scope(name, "SparseSlice", [sp_input]) as name:
726    output_indices, output_values, output_shape = gen_sparse_ops.sparse_slice(
727        sp_input.indices,
728        sp_input.values,
729        sp_input.dense_shape,
730        start,
731        size,
732        name=name)
733
734    return sparse_tensor.SparseTensor(output_indices, output_values,
735                                      output_shape)
736
737
738@tf_export("sparse_to_dense")
739def sparse_to_dense(sparse_indices,
740                    output_shape,
741                    sparse_values,
742                    default_value=0,
743                    validate_indices=True,
744                    name=None):
745  """Converts a sparse representation into a dense tensor.
746
747  Builds an array `dense` with shape `output_shape` such that
748
749  ```python
750  # If sparse_indices is scalar
751  dense[i] = (i == sparse_indices ? sparse_values : default_value)
752
753  # If sparse_indices is a vector, then for each i
754  dense[sparse_indices[i]] = sparse_values[i]
755
756  # If sparse_indices is an n by d matrix, then for each i in [0, n)
757  dense[sparse_indices[i][0], ..., sparse_indices[i][d-1]] = sparse_values[i]
758  ```
759
760  All other values in `dense` are set to `default_value`.  If `sparse_values`
761  is a scalar, all sparse indices are set to this single value.
762
763  Indices should be sorted in lexicographic order, and indices must not
764  contain any repeats. If `validate_indices` is True, these properties
765  are checked during execution.
766
767  Args:
768    sparse_indices: A 0-D, 1-D, or 2-D `Tensor` of type `int32` or `int64`.
769      `sparse_indices[i]` contains the complete index where `sparse_values[i]`
770      will be placed.
771    output_shape: A 1-D `Tensor` of the same type as `sparse_indices`.  Shape
772      of the dense output tensor.
773    sparse_values: A 0-D or 1-D `Tensor`.  Values corresponding to each row of
774      `sparse_indices`, or a scalar value to be used for all sparse indices.
775    default_value: A 0-D `Tensor` of the same type as `sparse_values`.  Value
776      to set for indices not specified in `sparse_indices`.  Defaults to zero.
777    validate_indices: A boolean value.  If True, indices are checked to make
778      sure they are sorted in lexicographic order and that there are no repeats.
779    name: A name for the operation (optional).
780
781  Returns:
782    Dense `Tensor` of shape `output_shape`.  Has the same type as
783    `sparse_values`.
784  """
785  return gen_sparse_ops._sparse_to_dense(
786      sparse_indices,
787      output_shape,
788      sparse_values,
789      default_value=default_value,
790      validate_indices=validate_indices,
791      name=name)
792
793
794@tf_export("sparse_reduce_max")
795def sparse_reduce_max(sp_input, axis=None, keep_dims=False,
796                      reduction_axes=None):
797  """Computes the max of elements across dimensions of a SparseTensor.
798
799  This Op takes a SparseTensor and is the sparse counterpart to
800  `tf.reduce_max()`.  In particular, this Op also returns a dense `Tensor`
801  instead of a sparse one.
802
803  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
804  `keep_dims` is true, the rank of the tensor is reduced by 1 for each entry in
805  `reduction_axes`. If `keep_dims` is true, the reduced dimensions are retained
806  with length 1.
807
808  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
809  with a single element is returned.  Additionally, the axes can be negative,
810  similar to the indexing rules in Python.
811
812  For example:
813
814  ```python
815  # 'x' represents [[1, ?, 2]
816  #                 [?, 3, ?]]
817  # where ? is implicitly-zero.
818  tf.sparse_reduce_max(x) ==> 3
819  tf.sparse_reduce_max(x, 0) ==> [1, 3, 2]
820  tf.sparse_reduce_max(x, 1) ==> [2, 3]  # Can also use -1 as the axis.
821  tf.sparse_reduce_max(x, 1, keep_dims=True) ==> [[2], [3]]
822  tf.sparse_reduce_max(x, [0, 1]) ==> 3
823  ```
824
825  Args:
826    sp_input: The SparseTensor to reduce. Should have numeric type.
827    axis: The dimensions to reduce; list or scalar. If `None` (the
828      default), reduces all dimensions.
829    keep_dims: If true, retain reduced dimensions with length 1.
830    reduction_axes: Deprecated name of axis.
831
832  Returns:
833    The reduced Tensor.
834  """
835  return gen_sparse_ops.sparse_reduce_max(
836      sp_input.indices, sp_input.values, sp_input.dense_shape,
837      math_ops._ReductionDims(sp_input, axis, reduction_axes), keep_dims)
838
839
840@tf_export("sparse_reduce_max_sparse")
841def sparse_reduce_max_sparse(sp_input,
842                             axis=None,
843                             keep_dims=False,
844                             reduction_axes=None):
845  """Computes the max of elements across dimensions of a SparseTensor.
846
847  This Op takes a SparseTensor and is the sparse counterpart to
848  `tf.reduce_max()`.  In contrast to SparseReduceSum, this Op returns a
849  SparseTensor.
850
851  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
852  `keep_dims` is true, the rank of the tensor is reduced by 1 for each entry in
853  `reduction_axes`. If `keep_dims` is true, the reduced dimensions are retained
854  with length 1.
855
856  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
857  with a single element is returned.  Additionally, the axes can be negative,
858  which are interpreted according to the indexing rules in Python.
859
860  Args:
861    sp_input: The SparseTensor to reduce. Should have numeric type.
862    axis: The dimensions to reduce; list or scalar. If `None` (the
863      default), reduces all dimensions.
864    keep_dims: If true, retain reduced dimensions with length 1.
865    reduction_axes: Deprecated name of axis
866
867  Returns:
868    The reduced SparseTensor.
869  """
870  output_ind, output_val, output_shape = (
871      gen_sparse_ops.sparse_reduce_max_sparse(
872          sp_input.indices, sp_input.values, sp_input.dense_shape,
873          math_ops._ReductionDims(sp_input, axis, reduction_axes), keep_dims))
874
875  return sparse_tensor.SparseTensor(output_ind, output_val, output_shape)
876
877
878@tf_export("sparse_reduce_sum")
879def sparse_reduce_sum(sp_input, axis=None, keep_dims=False,
880                      reduction_axes=None):
881  """Computes the sum of elements across dimensions of a SparseTensor.
882
883  This Op takes a SparseTensor and is the sparse counterpart to
884  `tf.reduce_sum()`.  In particular, this Op also returns a dense `Tensor`
885  instead of a sparse one.
886
887  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
888  `keep_dims` is true, the rank of the tensor is reduced by 1 for each entry in
889  `reduction_axes`. If `keep_dims` is true, the reduced dimensions are retained
890  with length 1.
891
892  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
893  with a single element is returned.  Additionally, the axes can be negative,
894  similar to the indexing rules in Python.
895
896  For example:
897
898  ```python
899  # 'x' represents [[1, ?, 1]
900  #                 [?, 1, ?]]
901  # where ? is implicitly-zero.
902  tf.sparse_reduce_sum(x) ==> 3
903  tf.sparse_reduce_sum(x, 0) ==> [1, 1, 1]
904  tf.sparse_reduce_sum(x, 1) ==> [2, 1]  # Can also use -1 as the axis.
905  tf.sparse_reduce_sum(x, 1, keep_dims=True) ==> [[2], [1]]
906  tf.sparse_reduce_sum(x, [0, 1]) ==> 3
907  ```
908
909  Args:
910    sp_input: The SparseTensor to reduce. Should have numeric type.
911    axis: The dimensions to reduce; list or scalar. If `None` (the
912      default), reduces all dimensions.
913    keep_dims: If true, retain reduced dimensions with length 1.
914    reduction_axes: Deprecated name of axis.
915
916  Returns:
917    The reduced Tensor.
918  """
919  return gen_sparse_ops.sparse_reduce_sum(
920      sp_input.indices, sp_input.values, sp_input.dense_shape,
921      math_ops._ReductionDims(sp_input, axis, reduction_axes), keep_dims)
922
923
924@tf_export("sparse_reduce_sum_sparse")
925def sparse_reduce_sum_sparse(sp_input,
926                             axis=None,
927                             keep_dims=False,
928                             reduction_axes=None):
929  """Computes the sum of elements across dimensions of a SparseTensor.
930
931  This Op takes a SparseTensor and is the sparse counterpart to
932  `tf.reduce_sum()`.  In contrast to SparseReduceSum, this Op returns a
933  SparseTensor.
934
935  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
936  `keep_dims` is true, the rank of the tensor is reduced by 1 for each entry in
937  `reduction_axes`. If `keep_dims` is true, the reduced dimensions are retained
938  with length 1.
939
940  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
941  with a single element is returned.  Additionally, the axes can be negative,
942  which are interpreted according to the indexing rules in Python.
943
944  Args:
945    sp_input: The SparseTensor to reduce. Should have numeric type.
946    axis: The dimensions to reduce; list or scalar. If `None` (the
947      default), reduces all dimensions.
948    keep_dims: If true, retain reduced dimensions with length 1.
949    reduction_axes: Deprecated name of axis
950
951  Returns:
952    The reduced SparseTensor.
953  """
954  output_ind, output_val, output_shape = (
955      gen_sparse_ops.sparse_reduce_sum_sparse(
956          sp_input.indices, sp_input.values, sp_input.dense_shape,
957          math_ops._ReductionDims(sp_input, axis, reduction_axes), keep_dims))
958
959  return sparse_tensor.SparseTensor(output_ind, output_val, output_shape)
960
961
962@tf_export("sparse_tensor_to_dense")
963def sparse_tensor_to_dense(sp_input,
964                           default_value=0,
965                           validate_indices=True,
966                           name=None):
967  """Converts a `SparseTensor` into a dense tensor.
968
969  This op is a convenience wrapper around `sparse_to_dense` for `SparseTensor`s.
970
971  For example, if `sp_input` has shape `[3, 5]` and non-empty string values:
972
973      [0, 1]: a
974      [0, 3]: b
975      [2, 0]: c
976
977  and `default_value` is `x`, then the output will be a dense `[3, 5]`
978  string tensor with values:
979
980      [[x a x b x]
981       [x x x x x]
982       [c x x x x]]
983
984  Indices must be without repeats.  This is only
985  tested if validate_indices is True.
986
987  Args:
988    sp_input: The input `SparseTensor`.
989    default_value: Scalar value to set for indices not specified in
990      `sp_input`.  Defaults to zero.
991    validate_indices: A boolean value.  If `True`, indices are checked to make
992      sure they are sorted in lexicographic order and that there are no repeats.
993    name: A name prefix for the returned tensors (optional).
994
995  Returns:
996    A dense tensor with shape `sp_input.dense_shape` and values specified by
997    the non-empty values in `sp_input`. Indices not in `sp_input` are assigned
998    `default_value`.
999
1000  Raises:
1001    TypeError: If `sp_input` is not a `SparseTensor`.
1002  """
1003  sp_input = _convert_to_sparse_tensor(sp_input)
1004
1005  return sparse_to_dense(
1006      sp_input.indices,
1007      sp_input.dense_shape,
1008      sp_input.values,
1009      default_value=default_value,
1010      validate_indices=validate_indices,
1011      name=name)
1012
1013
1014@tf_export("sparse_to_indicator")
1015def sparse_to_indicator(sp_input, vocab_size, name=None):
1016  """Converts a `SparseTensor` of ids into a dense bool indicator tensor.
1017
1018  The last dimension of `sp_input.indices` is discarded and replaced with
1019  the values of `sp_input`.  If `sp_input.dense_shape = [D0, D1, ..., Dn, K]`,
1020  then `output.shape = [D0, D1, ..., Dn, vocab_size]`, where
1021
1022      output[d_0, d_1, ..., d_n, sp_input[d_0, d_1, ..., d_n, k]] = True
1023
1024  and False elsewhere in `output`.
1025
1026  For example, if `sp_input.dense_shape = [2, 3, 4]` with non-empty values:
1027
1028      [0, 0, 0]: 0
1029      [0, 1, 0]: 10
1030      [1, 0, 3]: 103
1031      [1, 1, 2]: 150
1032      [1, 1, 3]: 149
1033      [1, 1, 4]: 150
1034      [1, 2, 1]: 121
1035
1036  and `vocab_size = 200`, then the output will be a `[2, 3, 200]` dense bool
1037  tensor with False everywhere except at positions
1038
1039      (0, 0, 0), (0, 1, 10), (1, 0, 103), (1, 1, 149), (1, 1, 150),
1040      (1, 2, 121).
1041
1042  Note that repeats are allowed in the input SparseTensor.
1043  This op is useful for converting `SparseTensor`s into dense formats for
1044  compatibility with ops that expect dense tensors.
1045
1046  The input `SparseTensor` must be in row-major order.
1047
1048  Args:
1049    sp_input: A `SparseTensor` with `values` property of type `int32` or
1050      `int64`.
1051    vocab_size: A scalar int64 Tensor (or Python int) containing the new size
1052      of the last dimension, `all(0 <= sp_input.values < vocab_size)`.
1053    name: A name prefix for the returned tensors (optional)
1054
1055  Returns:
1056    A dense bool indicator tensor representing the indices with specified value.
1057
1058  Raises:
1059    TypeError: If `sp_input` is not a `SparseTensor`.
1060  """
1061  sp_input = _convert_to_sparse_tensor(sp_input)
1062
1063  with ops.name_scope(name, "SparseToIndicator", [sp_input]) as name:
1064    num_entries = array_ops.shape(sp_input.indices)[0]
1065    new_values = array_ops.fill(array_ops.expand_dims(num_entries, 0), True)
1066    sp_values = sparse_tensor.SparseTensor(sp_input.indices, new_values,
1067                                           sp_input.dense_shape)
1068
1069    sp_new = sparse_merge(sp_input, sp_values, vocab_size, name)
1070
1071    # validate_indices may be False because we allow duplicates in new_indices:
1072    # repeated indices are allowed when creating an indicator matrix.
1073    return sparse_tensor_to_dense(
1074        sp_new, default_value=False, validate_indices=False, name=name)
1075
1076
1077@tf_export("sparse_merge")
1078def sparse_merge(sp_ids, sp_values, vocab_size, name=None,
1079                 already_sorted=False):
1080  """Combines a batch of feature ids and values into a single `SparseTensor`.
1081
1082  The most common use case for this function occurs when feature ids and
1083  their corresponding values are stored in `Example` protos on disk.
1084  `parse_example` will return a batch of ids and a batch of values, and this
1085  function joins them into a single logical `SparseTensor` for use in
1086  functions such as `sparse_tensor_dense_matmul`, `sparse_to_dense`, etc.
1087
1088  The `SparseTensor` returned by this function has the following properties:
1089
1090    - `indices` is equivalent to `sp_ids.indices` with the last
1091      dimension discarded and replaced with `sp_ids.values`.
1092    - `values` is simply `sp_values.values`.
1093    - If `sp_ids.dense_shape = [D0, D1, ..., Dn, K]`, then
1094      `output.shape = [D0, D1, ..., Dn, vocab_size]`.
1095
1096  For example, consider the following feature vectors:
1097
1098  ```python
1099    vector1 = [-3, 0, 0, 0, 0, 0]
1100    vector2 = [ 0, 1, 0, 4, 1, 0]
1101    vector3 = [ 5, 0, 0, 9, 0, 0]
1102  ```
1103
1104  These might be stored sparsely in the following Example protos by storing
1105  only the feature ids (column number if the vectors are treated as a matrix)
1106  of the non-zero elements and the corresponding values:
1107
1108  ```python
1109    examples = [Example(features={
1110                    "ids": Feature(int64_list=Int64List(value=[0])),
1111                    "values": Feature(float_list=FloatList(value=[-3]))}),
1112                Example(features={
1113                    "ids": Feature(int64_list=Int64List(value=[1, 4, 3])),
1114                    "values": Feature(float_list=FloatList(value=[1, 1, 4]))}),
1115                Example(features={
1116                    "ids": Feature(int64_list=Int64List(value=[0, 3])),
1117                    "values": Feature(float_list=FloatList(value=[5, 9]))})]
1118  ```
1119
1120  The result of calling parse_example on these examples will produce a
1121  dictionary with entries for "ids" and "values". Passing those two objects
1122  to this function along with vocab_size=6, will produce a `SparseTensor` that
1123  sparsely represents all three instances. Namely, the `indices` property will
1124  contain the coordinates of the non-zero entries in the feature matrix (the
1125  first dimension is the row number in the matrix, i.e., the index within the
1126  batch, and the second dimension is the column number, i.e., the feature id);
1127  `values` will contain the actual values. `shape` will be the shape of the
1128  original matrix, i.e., (3, 6). For our example above, the output will be
1129  equal to:
1130
1131  ```python
1132    SparseTensor(indices=[[0, 0], [1, 1], [1, 3], [1, 4], [2, 0], [2, 3]],
1133                 values=[-3, 1, 4, 1, 5, 9],
1134                 dense_shape=[3, 6])
1135  ```
1136
1137  This method generalizes to higher-dimensions by simply providing a list for
1138  both the sp_ids as well as the vocab_size.
1139  In this case the resulting `SparseTensor` has the following properties:
1140    - `indices` is equivalent to `sp_ids[0].indices` with the last
1141      dimension discarded and concatenated with
1142      `sp_ids[0].values, sp_ids[1].values, ...`.
1143    - `values` is simply `sp_values.values`.
1144    - If `sp_ids.dense_shape = [D0, D1, ..., Dn, K]`, then
1145      `output.shape = [D0, D1, ..., Dn] + vocab_size`.
1146
1147  Args:
1148    sp_ids: A single `SparseTensor` with `values` property of type `int32`
1149      or `int64` or a Python list of such `SparseTensor`s or a list thereof.
1150    sp_values: A `SparseTensor` of any type.
1151    vocab_size: A scalar `int64` Tensor (or Python int) containing the new size
1152      of the last dimension, `all(0 <= sp_ids.values < vocab_size)`.
1153      Or a list thereof with `all(0 <= sp_ids[i].values < vocab_size[i])` for
1154      all `i`.
1155    name: A name prefix for the returned tensors (optional)
1156    already_sorted: A boolean to specify whether the per-batch values in
1157     `sp_values` are already sorted. If so skip sorting, False by default
1158     (optional).
1159
1160  Returns:
1161    A `SparseTensor` compactly representing a batch of feature ids and values,
1162    useful for passing to functions that expect such a `SparseTensor`.
1163
1164  Raises:
1165    TypeError: If `sp_values` is not a `SparseTensor`. Or if `sp_ids` is neither
1166      a `SparseTensor` nor a list thereof. Or if `vocab_size` is not a
1167      `Tensor` or a Python int and `sp_ids` is a `SparseTensor`. Or if
1168      `vocab_size` is not a or list thereof and `sp_ids` is a list.
1169    ValueError: If `sp_ids` and `vocab_size` are lists of different lengths.
1170  """
1171  if isinstance(sp_ids, sparse_tensor.SparseTensorValue) or isinstance(
1172      sp_ids, sparse_tensor.SparseTensor):
1173    sp_ids = [sp_ids]
1174    if not (isinstance(vocab_size, ops.Tensor) or
1175            isinstance(vocab_size, numbers.Integral)):
1176      raise TypeError("vocab_size has to be a Tensor or Python int. Found %s" %
1177                      type(vocab_size))
1178    vocab_size = [vocab_size]
1179  else:
1180    if not isinstance(sp_ids, collections.Iterable):
1181      raise TypeError("sp_ids has to be a SparseTensor or list thereof. "
1182                      "Found %s" % type(sp_ids))
1183    if not isinstance(vocab_size, collections.Iterable):
1184      raise TypeError("vocab_size has to be a list of Tensors or Python ints. "
1185                      "Found %s" % type(vocab_size))
1186    for dim in vocab_size:
1187      if not (isinstance(dim, ops.Tensor) or isinstance(dim, numbers.Integral)):
1188        raise TypeError(
1189            "vocab_size has to be a list of Tensors or Python ints. Found %s" %
1190            type(dim))
1191  if len(sp_ids) != len(vocab_size):
1192    raise ValueError("sp_ids and vocab_size have to have equal lengths.")
1193
1194  with ops.name_scope(name, "SparseMerge", [sp_ids, sp_values]):
1195    sp_ids = [_convert_to_sparse_tensor(sp_ids_dim) for sp_ids_dim in sp_ids]
1196    sp_values = _convert_to_sparse_tensor(sp_values)
1197    ids = []
1198    for sp_ids_dim in sp_ids:
1199      ids_dim = sp_ids_dim.values
1200      if sp_ids_dim.dtype != dtypes.int64:
1201        ids_dim = math_ops.cast(ids_dim, dtypes.int64)
1202      ids += [array_ops.expand_dims(ids_dim, axis=1)]
1203
1204    vocab_size = [math_ops.cast(x, dtypes.int64) for x in vocab_size]
1205
1206    # Slice off the last dimension of indices, then tack on the ids
1207    indices_columns_to_preserve = sp_ids[0].indices[:, :-1]
1208    new_indices = array_ops.concat([indices_columns_to_preserve] + ids, 1)
1209
1210    new_values = sp_values.values
1211    new_shape = array_ops.concat([sp_ids[0].dense_shape[:-1], vocab_size], 0)
1212
1213    result = sparse_tensor.SparseTensor(new_indices, new_values, new_shape)
1214    return result if already_sorted else sparse_reorder(result)
1215
1216
1217@tf_export("sparse_retain")
1218def sparse_retain(sp_input, to_retain):
1219  """Retains specified non-empty values within a `SparseTensor`.
1220
1221  For example, if `sp_input` has shape `[4, 5]` and 4 non-empty string values:
1222
1223      [0, 1]: a
1224      [0, 3]: b
1225      [2, 0]: c
1226      [3, 1]: d
1227
1228  and `to_retain = [True, False, False, True]`, then the output will
1229  be a `SparseTensor` of shape `[4, 5]` with 2 non-empty values:
1230
1231      [0, 1]: a
1232      [3, 1]: d
1233
1234  Args:
1235    sp_input: The input `SparseTensor` with `N` non-empty elements.
1236    to_retain: A bool vector of length `N` with `M` true values.
1237
1238  Returns:
1239    A `SparseTensor` with the same shape as the input and `M` non-empty
1240    elements corresponding to the true positions in `to_retain`.
1241
1242  Raises:
1243    TypeError: If `sp_input` is not a `SparseTensor`.
1244  """
1245  sp_input = _convert_to_sparse_tensor(sp_input)
1246
1247  to_retain = ops.convert_to_tensor(to_retain)
1248
1249  # Shape checking, if shape is known at graph construction time
1250  retain_shape = to_retain.get_shape()
1251  retain_shape.assert_has_rank(1)
1252  sp_input.values.get_shape()[0].merge_with(retain_shape[0])
1253
1254  where_true = array_ops.reshape(array_ops.where(to_retain), [-1])
1255  new_indices = array_ops.gather(sp_input.indices, where_true)
1256  new_values = array_ops.gather(sp_input.values, where_true)
1257  return sparse_tensor.SparseTensor(new_indices, new_values,
1258                                    array_ops.identity(sp_input.dense_shape))
1259
1260
1261@tf_export("sparse_reset_shape")
1262def sparse_reset_shape(sp_input, new_shape=None):
1263  """Resets the shape of a `SparseTensor` with indices and values unchanged.
1264
1265  If `new_shape` is None, returns a copy of `sp_input` with its shape reset
1266  to the tight bounding box of `sp_input`. This will be a shape consisting of
1267  all zeros if sp_input has no values.
1268
1269  If `new_shape` is provided, then it must be larger or equal in all dimensions
1270  compared to the shape of `sp_input`. When this condition is met, the returned
1271  SparseTensor will have its shape reset to `new_shape` and its indices and
1272  values unchanged from that of `sp_input.`
1273
1274  For example:
1275
1276    Consider a `sp_input` with shape [2, 3, 5]:
1277
1278      [0, 0, 1]: a
1279      [0, 1, 0]: b
1280      [0, 2, 2]: c
1281      [1, 0, 3]: d
1282
1283    - It is an error to set `new_shape` as [3, 7] since this represents a
1284      rank-2 tensor while `sp_input` is rank-3. This is either a ValueError
1285      during graph construction (if both shapes are known) or an OpError during
1286      run time.
1287
1288    - Setting `new_shape` as [2, 3, 6] will be fine as this shape is larger or
1289      equal in every dimension compared to the original shape [2, 3, 5].
1290
1291    - On the other hand, setting new_shape as [2, 3, 4] is also an error: The
1292      third dimension is smaller than the original shape [2, 3, 5] (and an
1293      `InvalidArgumentError` will be raised).
1294
1295    - If `new_shape` is None, the returned SparseTensor will have a shape
1296      [2, 3, 4], which is the tight bounding box of `sp_input`.
1297
1298  Args:
1299    sp_input: The input `SparseTensor`.
1300    new_shape: None or a vector representing the new shape for the returned
1301      `SparseTensor`.
1302
1303  Returns:
1304    A `SparseTensor` indices and values unchanged from `input_sp`. Its shape is
1305      `new_shape` if that is set. Otherwise it is the tight bounding box of
1306       `input_sp`
1307
1308  Raises:
1309    TypeError: If `sp_input` is not a `SparseTensor`.
1310    ValueError: If `new_shape` represents a tensor with a different rank from
1311      that of `sp_input` (if shapes are known when graph is constructed).
1312    ValueError:  If `new_shape` is determined during graph build to have
1313      dimension sizes that are too small.
1314    OpError:
1315      - If `new_shape` has dimension sizes that are too small.
1316      - If shapes are not known during graph construction time, and during run
1317        time it is found out that the ranks do not match.
1318  """
1319  sp_input = _convert_to_sparse_tensor(sp_input)
1320
1321  in_indices = array_ops.identity(sp_input.indices)
1322  in_values = array_ops.identity(sp_input.values)
1323  in_shape = array_ops.identity(sp_input.dense_shape)
1324
1325  if new_shape is None:
1326    dim_low_bound = math_ops.reduce_max(in_indices, axis=0)
1327    output_shape_tensor = math_ops.maximum(
1328        array_ops.constant(0, dtype=dtypes.int64),
1329        math_ops.add(dim_low_bound, array_ops.ones_like(in_shape)))
1330  else:
1331    output_shape_tensor = ops.convert_to_tensor(new_shape)
1332    output_shape_tensor.get_shape().assert_has_rank(1)
1333    output_shape_tensor = math_ops.cast(output_shape_tensor, dtypes.int64)
1334    # For cases when shape is known during graph construction, this catches the
1335    # error before the sparse_tensor.SparseTensor catches it.
1336    output_shape_tensor.get_shape()[0].merge_with(in_shape.get_shape()[0])
1337
1338    output_shape_tensor_const = tensor_util.constant_value(output_shape_tensor)
1339    # For cases where all shapes are known during graph construction
1340    if (output_shape_tensor_const is not None and
1341        sp_input.get_shape().is_fully_defined()):
1342      in_shape_const = np.array(sp_input.get_shape().as_list())
1343      if not np.all(in_shape_const <= output_shape_tensor_const):
1344        raise ValueError(
1345            "Requested new_shape should have dimension sizes >= sp_input.shape."
1346            "  Found new_shape (%s), sp_input.shape (%s)." %
1347            (in_shape_const, output_shape_tensor_const))
1348      output_shape_tensor = output_shape_tensor_const
1349    else:
1350      # For cases where shape is not known during graph construction.
1351      output_shape_tensor = control_flow_ops.with_dependencies([
1352          check_ops.assert_equal(
1353              array_ops.shape(in_shape), array_ops.shape(output_shape_tensor))
1354      ], output_shape_tensor)
1355      output_shape_tensor = control_flow_ops.with_dependencies(
1356          [check_ops.assert_less_equal(in_shape, output_shape_tensor)],
1357          output_shape_tensor)
1358
1359  return sparse_tensor.SparseTensor(in_indices, in_values, output_shape_tensor)
1360
1361
1362@tf_export("sparse_fill_empty_rows")
1363def sparse_fill_empty_rows(sp_input, default_value, name=None):
1364  """Fills empty rows in the input 2-D `SparseTensor` with a default value.
1365
1366  This op adds entries with the specified `default_value` at index
1367  `[row, 0]` for any row in the input that does not already have a value.
1368
1369  For example, suppose `sp_input` has shape `[5, 6]` and non-empty values:
1370
1371      [0, 1]: a
1372      [0, 3]: b
1373      [2, 0]: c
1374      [3, 1]: d
1375
1376  Rows 1 and 4 are empty, so the output will be of shape `[5, 6]` with values:
1377
1378      [0, 1]: a
1379      [0, 3]: b
1380      [1, 0]: default_value
1381      [2, 0]: c
1382      [3, 1]: d
1383      [4, 0]: default_value
1384
1385  Note that the input may have empty columns at the end, with no effect on
1386  this op.
1387
1388  The output `SparseTensor` will be in row-major order and will have the
1389  same shape as the input.
1390
1391  This op also returns an indicator vector such that
1392
1393      empty_row_indicator[i] = True iff row i was an empty row.
1394
1395  Args:
1396    sp_input: A `SparseTensor` with shape `[N, M]`.
1397    default_value: The value to fill for empty rows, with the same type as
1398      `sp_input.`
1399    name: A name prefix for the returned tensors (optional)
1400
1401  Returns:
1402    sp_ordered_output: A `SparseTensor` with shape `[N, M]`, and with all empty
1403      rows filled in with `default_value`.
1404    empty_row_indicator: A bool vector of length `N` indicating whether each
1405      input row was empty.
1406
1407  Raises:
1408    TypeError: If `sp_input` is not a `SparseTensor`.
1409  """
1410  sp_input = _convert_to_sparse_tensor(sp_input)
1411  with ops.name_scope(name, "SparseFillEmptyRows", [sp_input]):
1412    default_value = ops.convert_to_tensor(
1413        default_value, dtype=sp_input.values.dtype)
1414    (output_indices, output_values, empty_row_indicator,
1415     unused_reverse_index_map) = gen_sparse_ops._sparse_fill_empty_rows(
1416         indices=sp_input.indices,
1417         values=sp_input.values,
1418         dense_shape=sp_input.dense_shape,
1419         default_value=default_value)
1420    return (sparse_tensor.SparseTensor(
1421        indices=output_indices,
1422        values=output_values,
1423        dense_shape=sp_input.dense_shape), empty_row_indicator)
1424
1425
1426@tf_export("serialize_sparse")
1427def serialize_sparse(sp_input, name=None, out_type=dtypes.string):
1428  """Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object.
1429
1430  Args:
1431    sp_input: The input `SparseTensor`.
1432    name: A name prefix for the returned tensors (optional).
1433    out_type: The `dtype` to use for serialization.
1434
1435  Returns:
1436    A 3-vector (1-D `Tensor`), with each column representing the serialized
1437    `SparseTensor`'s indices, values, and shape (respectively).
1438
1439  Raises:
1440    TypeError: If `sp_input` is not a `SparseTensor`.
1441  """
1442  sp_input = _convert_to_sparse_tensor(sp_input)
1443
1444  return gen_sparse_ops._serialize_sparse(
1445      sp_input.indices,
1446      sp_input.values,
1447      sp_input.dense_shape,
1448      name=name,
1449      out_type=out_type)
1450
1451
1452@tf_export("serialize_many_sparse")
1453def serialize_many_sparse(sp_input, name=None, out_type=dtypes.string):
1454  """Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`.
1455
1456  The `SparseTensor` must have rank `R` greater than 1, and the first dimension
1457  is treated as the minibatch dimension.  Elements of the `SparseTensor`
1458  must be sorted in increasing order of this first dimension.  The serialized
1459  `SparseTensor` objects going into each row of the output `Tensor` will have
1460  rank `R-1`.
1461
1462  The minibatch size `N` is extracted from `sparse_shape[0]`.
1463
1464  Args:
1465    sp_input: The input rank `R` `SparseTensor`.
1466    name: A name prefix for the returned tensors (optional).
1467    out_type: The `dtype` to use for serialization.
1468
1469  Returns:
1470    A matrix (2-D `Tensor`) with `N` rows and `3` columns. Each column
1471    represents serialized `SparseTensor`'s indices, values, and shape
1472    (respectively).
1473
1474  Raises:
1475    TypeError: If `sp_input` is not a `SparseTensor`.
1476  """
1477  sp_input = _convert_to_sparse_tensor(sp_input)
1478
1479  return gen_sparse_ops._serialize_many_sparse(
1480      sp_input.indices,
1481      sp_input.values,
1482      sp_input.dense_shape,
1483      name=name,
1484      out_type=out_type)
1485
1486
1487def deserialize_sparse(serialized_sparse, dtype, rank=None, name=None):
1488  """Deserialize `SparseTensor` objects.
1489
1490  The input `serialized_sparse` must have the shape `[?, ?, ..., ?, 3]` where
1491  the last dimension stores serialized `SparseTensor` objects and the other N
1492  dimensions (N >= 0) correspond to a batch. The ranks of the original
1493  `SparseTensor` objects must all match. When the final `SparseTensor` is
1494  created, its rank is the rank of the incoming `SparseTensor` objects plus N;
1495  the sparse tensors have been concatenated along new dimensions, one for each
1496  batch.
1497
1498  The output `SparseTensor` object's shape values for the original dimensions
1499  are the max across the input `SparseTensor` objects' shape values for the
1500  corresponding dimensions. The new dimensions match the size of the batch.
1501
1502  The input `SparseTensor` objects' indices are assumed ordered in
1503  standard lexicographic order.  If this is not the case, after this
1504  step run `SparseReorder` to restore index ordering.
1505
1506  For example, if the serialized input is a `[2 x 3]` matrix representing two
1507  original `SparseTensor` objects:
1508
1509      index = [ 0]
1510              [10]
1511              [20]
1512      values = [1, 2, 3]
1513      shape = [50]
1514
1515  and
1516
1517      index = [ 2]
1518              [10]
1519      values = [4, 5]
1520      shape = [30]
1521
1522  then the final deserialized `SparseTensor` will be:
1523
1524      index = [0  0]
1525              [0 10]
1526              [0 20]
1527              [1  2]
1528              [1 10]
1529      values = [1, 2, 3, 4, 5]
1530      shape = [2 50]
1531
1532  Args:
1533    serialized_sparse: The serialized `SparseTensor` objects.
1534      The last dimension must have 3 columns.
1535    dtype: The `dtype` of the serialized `SparseTensor` objects.
1536    rank: (optional) Python int, the rank of the `SparseTensor` objects.
1537    name: A name prefix for the returned tensors (optional).
1538
1539  Returns:
1540    A `SparseTensor` representing the deserialized `SparseTensor` objects.
1541
1542  """
1543  output_indices, output_values, output_shape = (
1544      gen_sparse_ops._deserialize_sparse(serialized_sparse, dtype, name=name))
1545
1546  # Feed rank data back in, if available
1547  output_indices.set_shape([None, rank])
1548  output_shape.set_shape([rank])
1549
1550  return sparse_tensor.SparseTensor(output_indices, output_values, output_shape)
1551
1552
1553@tf_export("deserialize_many_sparse")
1554def deserialize_many_sparse(serialized_sparse, dtype, rank=None, name=None):
1555  """Deserialize and concatenate `SparseTensors` from a serialized minibatch.
1556
1557  The input `serialized_sparse` must be a string matrix of shape `[N x 3]` where
1558  `N` is the minibatch size and the rows correspond to packed outputs of
1559  `serialize_sparse`.  The ranks of the original `SparseTensor` objects
1560  must all match.  When the final `SparseTensor` is created, it has rank one
1561  higher than the ranks of the incoming `SparseTensor` objects (they have been
1562  concatenated along a new row dimension).
1563
1564  The output `SparseTensor` object's shape values for all dimensions but the
1565  first are the max across the input `SparseTensor` objects' shape values
1566  for the corresponding dimensions.  Its first shape value is `N`, the minibatch
1567  size.
1568
1569  The input `SparseTensor` objects' indices are assumed ordered in
1570  standard lexicographic order.  If this is not the case, after this
1571  step run `sparse_reorder` to restore index ordering.
1572
1573  For example, if the serialized input is a `[2, 3]` matrix representing two
1574  original `SparseTensor` objects:
1575
1576      index = [ 0]
1577              [10]
1578              [20]
1579      values = [1, 2, 3]
1580      shape = [50]
1581
1582  and
1583
1584      index = [ 2]
1585              [10]
1586      values = [4, 5]
1587      shape = [30]
1588
1589  then the final deserialized `SparseTensor` will be:
1590
1591      index = [0  0]
1592              [0 10]
1593              [0 20]
1594              [1  2]
1595              [1 10]
1596      values = [1, 2, 3, 4, 5]
1597      shape = [2 50]
1598
1599  Args:
1600    serialized_sparse: 2-D `Tensor` of type `string` of shape `[N, 3]`.
1601      The serialized and packed `SparseTensor` objects.
1602    dtype: The `dtype` of the serialized `SparseTensor` objects.
1603    rank: (optional) Python int, the rank of the `SparseTensor` objects.
1604    name: A name prefix for the returned tensors (optional)
1605
1606  Returns:
1607    A `SparseTensor` representing the deserialized `SparseTensor`s,
1608    concatenated along the `SparseTensor`s' first dimension.
1609
1610    All of the serialized `SparseTensor`s must have had the same rank and type.
1611  """
1612  output_indices, output_values, output_shape = (
1613      gen_sparse_ops._deserialize_many_sparse(
1614          serialized_sparse, dtype, name=name))
1615
1616  # Feed rank data back in, if available
1617  output_indices.set_shape([None, rank])
1618  output_shape.set_shape([rank])
1619
1620  return sparse_tensor.SparseTensor(output_indices, output_values, output_shape)
1621
1622
1623@tf_export("sparse_tensor_dense_matmul")
1624def sparse_tensor_dense_matmul(sp_a,
1625                               b,
1626                               adjoint_a=False,
1627                               adjoint_b=False,
1628                               name=None):
1629  # pylint: disable=line-too-long
1630  """Multiply SparseTensor (of rank 2) "A" by dense matrix "B".
1631
1632  No validity checking is performed on the indices of `A`.  However, the
1633  following input format is recommended for optimal behavior:
1634
1635  * If `adjoint_a == false`: `A` should be sorted in lexicographically
1636    increasing order.  Use `sparse_reorder` if you're not sure.
1637  * If `adjoint_a == true`: `A` should be sorted in order of increasing
1638    dimension 1 (i.e., "column major" order instead of "row major" order).
1639
1640  Using `tf.nn.embedding_lookup_sparse` for sparse multiplication:
1641
1642  It's not obvious but you can consider `embedding_lookup_sparse` as another
1643  sparse and dense multiplication. In some situations, you may prefer to use
1644  `embedding_lookup_sparse` even though you're not dealing with embeddings.
1645
1646  There are two questions to ask in the decision process: Do you need gradients
1647  computed as sparse too? Is your sparse data represented as two
1648  `SparseTensor`s: ids and values? There is more explanation about data format
1649  below. If you answer any of these questions as yes, consider using
1650  `tf.nn.embedding_lookup_sparse`.
1651
1652  Following explains differences between the expected SparseTensors:
1653  For example if dense form of your sparse data has shape `[3, 5]` and values:
1654
1655      [[  a      ]
1656       [b       c]
1657       [    d    ]]
1658
1659
1660  `SparseTensor` format expected by `sparse_tensor_dense_matmul`:
1661   `sp_a` (indices, values):
1662
1663      [0, 1]: a
1664      [1, 0]: b
1665      [1, 4]: c
1666      [2, 2]: d
1667
1668  `SparseTensor` format expected by `embedding_lookup_sparse`:
1669   `sp_ids`                 `sp_weights`
1670
1671      [0, 0]: 1                [0, 0]: a
1672      [1, 0]: 0                [1, 0]: b
1673      [1, 1]: 4                [1, 1]: c
1674      [2, 0]: 2                [2, 0]: d
1675
1676
1677  Deciding when to use `sparse_tensor_dense_matmul` vs.
1678  `matmul`(a_is_sparse=True):
1679
1680  There are a number of questions to ask in the decision process, including:
1681
1682  * Will the SparseTensor `A` fit in memory if densified?
1683  * Is the column count of the product large (>> 1)?
1684  * Is the density of `A` larger than approximately 15%?
1685
1686  If the answer to several of these questions is yes, consider
1687  converting the `SparseTensor` to a dense one and using `tf.matmul` with
1688  `a_is_sparse=True`.
1689
1690  This operation tends to perform well when `A` is more sparse, if the column
1691  size of the product is small (e.g. matrix-vector multiplication), if
1692  `sp_a.dense_shape` takes on large values.
1693
1694  Below is a rough speed comparison between `sparse_tensor_dense_matmul`,
1695  labeled 'sparse', and `matmul`(a_is_sparse=True), labeled 'dense'.  For
1696  purposes of the comparison, the time spent converting from a `SparseTensor` to
1697  a dense `Tensor` is not included, so it is overly conservative with respect to
1698  the time ratio.
1699
1700  Benchmark system:
1701  CPU: Intel Ivybridge with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:12MB
1702  GPU: NVidia Tesla k40c
1703
1704  Compiled with:
1705  `-c opt --config=cuda --copt=-mavx`
1706
1707  ```
1708  tensorflow/python/sparse_tensor_dense_matmul_op_test --benchmarks
1709  A sparse [m, k] with % nonzero values between 1% and 80%
1710  B dense [k, n]
1711
1712  % nnz  n   gpu   m     k     dt(dense)     dt(sparse)   dt(sparse)/dt(dense)
1713  0.01   1   True  100   100   0.000221166   0.00010154   0.459112
1714  0.01   1   True  100   1000  0.00033858    0.000109275  0.322745
1715  0.01   1   True  1000  100   0.000310557   9.85661e-05  0.317385
1716  0.01   1   True  1000  1000  0.0008721     0.000100875  0.115669
1717  0.01   1   False 100   100   0.000208085   0.000107603  0.51711
1718  0.01   1   False 100   1000  0.000327112   9.51118e-05  0.290762
1719  0.01   1   False 1000  100   0.000308222   0.00010345   0.335635
1720  0.01   1   False 1000  1000  0.000865721   0.000101397  0.117124
1721  0.01   10  True  100   100   0.000218522   0.000105537  0.482958
1722  0.01   10  True  100   1000  0.000340882   0.000111641  0.327506
1723  0.01   10  True  1000  100   0.000315472   0.000117376  0.372064
1724  0.01   10  True  1000  1000  0.000905493   0.000123263  0.136128
1725  0.01   10  False 100   100   0.000221529   9.82571e-05  0.44354
1726  0.01   10  False 100   1000  0.000330552   0.000112615  0.340687
1727  0.01   10  False 1000  100   0.000341277   0.000114097  0.334324
1728  0.01   10  False 1000  1000  0.000819944   0.000120982  0.147549
1729  0.01   25  True  100   100   0.000207806   0.000105977  0.509981
1730  0.01   25  True  100   1000  0.000322879   0.00012921   0.400181
1731  0.01   25  True  1000  100   0.00038262    0.00014158   0.370035
1732  0.01   25  True  1000  1000  0.000865438   0.000202083  0.233504
1733  0.01   25  False 100   100   0.000209401   0.000104696  0.499979
1734  0.01   25  False 100   1000  0.000321161   0.000130737  0.407076
1735  0.01   25  False 1000  100   0.000377012   0.000136801  0.362856
1736  0.01   25  False 1000  1000  0.000861125   0.00020272   0.235413
1737  0.2    1   True  100   100   0.000206952   9.69219e-05  0.46833
1738  0.2    1   True  100   1000  0.000348674   0.000147475  0.422959
1739  0.2    1   True  1000  100   0.000336908   0.00010122   0.300439
1740  0.2    1   True  1000  1000  0.001022      0.000203274  0.198898
1741  0.2    1   False 100   100   0.000207532   9.5412e-05   0.459746
1742  0.2    1   False 100   1000  0.000356127   0.000146824  0.41228
1743  0.2    1   False 1000  100   0.000322664   0.000100918  0.312764
1744  0.2    1   False 1000  1000  0.000998987   0.000203442  0.203648
1745  0.2    10  True  100   100   0.000211692   0.000109903  0.519165
1746  0.2    10  True  100   1000  0.000372819   0.000164321  0.440753
1747  0.2    10  True  1000  100   0.000338651   0.000144806  0.427596
1748  0.2    10  True  1000  1000  0.00108312    0.000758876  0.70064
1749  0.2    10  False 100   100   0.000215727   0.000110502  0.512231
1750  0.2    10  False 100   1000  0.000375419   0.0001613    0.429653
1751  0.2    10  False 1000  100   0.000336999   0.000145628  0.432132
1752  0.2    10  False 1000  1000  0.00110502    0.000762043  0.689618
1753  0.2    25  True  100   100   0.000218705   0.000129913  0.594009
1754  0.2    25  True  100   1000  0.000394794   0.00029428   0.745402
1755  0.2    25  True  1000  100   0.000404483   0.0002693    0.665788
1756  0.2    25  True  1000  1000  0.0012002     0.00194494   1.62052
1757  0.2    25  False 100   100   0.000221494   0.0001306    0.589632
1758  0.2    25  False 100   1000  0.000396436   0.000297204  0.74969
1759  0.2    25  False 1000  100   0.000409346   0.000270068  0.659754
1760  0.2    25  False 1000  1000  0.00121051    0.00193737   1.60046
1761  0.5    1   True  100   100   0.000214981   9.82111e-05  0.456836
1762  0.5    1   True  100   1000  0.000415328   0.000223073  0.537101
1763  0.5    1   True  1000  100   0.000358324   0.00011269   0.314492
1764  0.5    1   True  1000  1000  0.00137612    0.000437401  0.317851
1765  0.5    1   False 100   100   0.000224196   0.000101423  0.452386
1766  0.5    1   False 100   1000  0.000400987   0.000223286  0.556841
1767  0.5    1   False 1000  100   0.000368825   0.00011224   0.304318
1768  0.5    1   False 1000  1000  0.00136036    0.000429369  0.31563
1769  0.5    10  True  100   100   0.000222125   0.000112308  0.505608
1770  0.5    10  True  100   1000  0.000461088   0.00032357   0.701753
1771  0.5    10  True  1000  100   0.000394624   0.000225497  0.571422
1772  0.5    10  True  1000  1000  0.00158027    0.00190898   1.20801
1773  0.5    10  False 100   100   0.000232083   0.000114978  0.495418
1774  0.5    10  False 100   1000  0.000454574   0.000324632  0.714146
1775  0.5    10  False 1000  100   0.000379097   0.000227768  0.600817
1776  0.5    10  False 1000  1000  0.00160292    0.00190168   1.18638
1777  0.5    25  True  100   100   0.00023429    0.000151703  0.647501
1778  0.5    25  True  100   1000  0.000497462   0.000598873  1.20386
1779  0.5    25  True  1000  100   0.000460778   0.000557038  1.20891
1780  0.5    25  True  1000  1000  0.00170036    0.00467336   2.74845
1781  0.5    25  False 100   100   0.000228981   0.000155334  0.678371
1782  0.5    25  False 100   1000  0.000496139   0.000620789  1.25124
1783  0.5    25  False 1000  100   0.00045473    0.000551528  1.21287
1784  0.5    25  False 1000  1000  0.00171793    0.00467152   2.71927
1785  0.8    1   True  100   100   0.000222037   0.000105301  0.47425
1786  0.8    1   True  100   1000  0.000410804   0.000329327  0.801664
1787  0.8    1   True  1000  100   0.000349735   0.000131225  0.375212
1788  0.8    1   True  1000  1000  0.00139219    0.000677065  0.48633
1789  0.8    1   False 100   100   0.000214079   0.000107486  0.502085
1790  0.8    1   False 100   1000  0.000413746   0.000323244  0.781261
1791  0.8    1   False 1000  100   0.000348983   0.000131983  0.378193
1792  0.8    1   False 1000  1000  0.00136296    0.000685325  0.50282
1793  0.8    10  True  100   100   0.000229159   0.00011825   0.516017
1794  0.8    10  True  100   1000  0.000498845   0.000532618  1.0677
1795  0.8    10  True  1000  100   0.000383126   0.00029935   0.781336
1796  0.8    10  True  1000  1000  0.00162866    0.00307312   1.88689
1797  0.8    10  False 100   100   0.000230783   0.000124958  0.541452
1798  0.8    10  False 100   1000  0.000493393   0.000550654  1.11606
1799  0.8    10  False 1000  100   0.000377167   0.000298581  0.791642
1800  0.8    10  False 1000  1000  0.00165795    0.00305103   1.84024
1801  0.8    25  True  100   100   0.000233496   0.000175241  0.75051
1802  0.8    25  True  100   1000  0.00055654    0.00102658   1.84458
1803  0.8    25  True  1000  100   0.000463814   0.000783267  1.68875
1804  0.8    25  True  1000  1000  0.00186905    0.00755344   4.04132
1805  0.8    25  False 100   100   0.000240243   0.000175047  0.728625
1806  0.8    25  False 100   1000  0.000578102   0.00104499   1.80763
1807  0.8    25  False 1000  100   0.000485113   0.000776849  1.60138
1808  0.8    25  False 1000  1000  0.00211448    0.00752736   3.55992
1809  ```
1810
1811  Args:
1812    sp_a: SparseTensor A, of rank 2.
1813    b: A dense Matrix with the same dtype as sp_a.
1814    adjoint_a: Use the adjoint of A in the matrix multiply.  If A is complex,
1815      this is transpose(conj(A)).  Otherwise it's transpose(A).
1816    adjoint_b: Use the adjoint of B in the matrix multiply.  If B is complex,
1817      this is transpose(conj(B)).  Otherwise it's transpose(B).
1818    name: A name prefix for the returned tensors (optional)
1819
1820  Returns:
1821    A dense matrix (pseudo-code in dense np.matrix notation):
1822      `A = A.H if adjoint_a else A`
1823      `B = B.H if adjoint_b else B`
1824      `return A*B`
1825  """
1826  # pylint: enable=line-too-long
1827  sp_a = _convert_to_sparse_tensor(sp_a)
1828  with ops.name_scope(name, "SparseTensorDenseMatMul",
1829                      [sp_a.indices, sp_a.values, b]) as name:
1830    b = ops.convert_to_tensor(b, name="b")
1831    return gen_sparse_ops._sparse_tensor_dense_mat_mul(
1832        a_indices=sp_a.indices,
1833        a_values=sp_a.values,
1834        a_shape=sp_a.dense_shape,
1835        b=b,
1836        adjoint_a=adjoint_a,
1837        adjoint_b=adjoint_b)
1838
1839
1840@tf_export("sparse_softmax")
1841def sparse_softmax(sp_input, name=None):
1842  """Applies softmax to a batched N-D `SparseTensor`.
1843
1844  The inputs represent an N-D SparseTensor with logical shape `[..., B, C]`
1845  (where `N >= 2`), and with indices sorted in the canonical lexicographic
1846  order.
1847
1848  This op is equivalent to applying the normal `tf.nn.softmax()` to each
1849  innermost logical submatrix with shape `[B, C]`, but with the catch that *the
1850  implicitly zero elements do not participate*.  Specifically, the algorithm is
1851  equivalent to:
1852
1853    (1) Applies `tf.nn.softmax()` to a densified view of each innermost
1854        submatrix with shape `[B, C]`, along the size-C dimension;
1855    (2) Masks out the original implicitly-zero locations;
1856    (3) Renormalizes the remaining elements.
1857
1858  Hence, the `SparseTensor` result has exactly the same non-zero indices and
1859  shape.
1860
1861  Example:
1862
1863  ```python
1864  # First batch:
1865  # [?   e.]
1866  # [1.  ? ]
1867  # Second batch:
1868  # [e   ? ]
1869  # [e   e ]
1870  shape = [2, 2, 2]  # 3-D SparseTensor
1871  values = np.asarray([[[0., np.e], [1., 0.]], [[np.e, 0.], [np.e, np.e]]])
1872  indices = np.vstack(np.where(values)).astype(np.int64).T
1873
1874  result = tf.sparse_softmax(tf.SparseTensor(indices, values, shape))
1875  # ...returning a 3-D SparseTensor, equivalent to:
1876  # [?   1.]     [1    ?]
1877  # [1.  ? ] and [.5  .5]
1878  # where ? means implicitly zero.
1879  ```
1880
1881  Args:
1882    sp_input: N-D `SparseTensor`, where `N >= 2`.
1883    name: optional name of the operation.
1884  Returns:
1885    output: N-D `SparseTensor` representing the results.
1886  """
1887  with ops.name_scope(name, "SparseSoftmax",
1888                      [sp_input.indices, sp_input.values]) as name:
1889    out_vals = gen_sparse_ops.sparse_softmax(sp_input.indices, sp_input.values,
1890                                             sp_input.dense_shape)
1891    return sparse_tensor.SparseTensor(sp_input.indices, out_vals,
1892                                      sp_input.dense_shape)
1893
1894
1895@tf_export("sparse_maximum")
1896def sparse_maximum(sp_a, sp_b, name=None):
1897  """Returns the element-wise max of two SparseTensors.
1898
1899  Assumes the two SparseTensors have the same shape, i.e., no broadcasting.
1900  Example:
1901
1902  ```python
1903  sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7])
1904  sp_one = sparse_tensor.SparseTensor([[1]], [1], [7])
1905  res = tf.sparse_maximum(sp_zero, sp_one).eval()
1906  # "res" should be equal to SparseTensor([[0], [1]], [0, 1], [7]).
1907  ```
1908
1909  Args:
1910    sp_a: a `SparseTensor` operand whose dtype is real, and indices
1911      lexicographically ordered.
1912    sp_b: the other `SparseTensor` operand with the same requirements (and the
1913      same shape).
1914    name: optional name of the operation.
1915  Returns:
1916    output: the output SparseTensor.
1917  """
1918  with ops.name_scope(
1919      name, "SparseSparseMaximum",
1920      [sp_a.indices, sp_a.values, sp_b.indices, sp_b.values]) as name:
1921    out_indices, out_values = gen_sparse_ops.sparse_sparse_maximum(
1922        sp_a.indices,
1923        sp_a.values,
1924        sp_a.dense_shape,
1925        sp_b.indices,
1926        sp_b.values,
1927        sp_b.dense_shape,
1928        name=name)
1929  return sparse_tensor.SparseTensor(out_indices, out_values, sp_a.dense_shape)
1930
1931
1932@tf_export("sparse_minimum")
1933def sparse_minimum(sp_a, sp_b, name=None):
1934  """Returns the element-wise min of two SparseTensors.
1935
1936  Assumes the two SparseTensors have the same shape, i.e., no broadcasting.
1937  Example:
1938
1939  ```python
1940  sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7])
1941  sp_one = sparse_tensor.SparseTensor([[1]], [1], [7])
1942  res = tf.sparse_minimum(sp_zero, sp_one).eval()
1943  # "res" should be equal to SparseTensor([[0], [1]], [0, 0], [7]).
1944  ```
1945
1946  Args:
1947    sp_a: a `SparseTensor` operand whose dtype is real, and indices
1948      lexicographically ordered.
1949    sp_b: the other `SparseTensor` operand with the same requirements (and the
1950      same shape).
1951    name: optional name of the operation.
1952  Returns:
1953    output: the output SparseTensor.
1954  """
1955  with ops.name_scope(
1956      name, "SparseSparseMinimum",
1957      [sp_a.indices, sp_a.values, sp_b.indices, sp_b.values]) as name:
1958    out_indices, out_values = gen_sparse_ops.sparse_sparse_minimum(
1959        sp_a.indices,
1960        sp_a.values,
1961        sp_a.dense_shape,
1962        sp_b.indices,
1963        sp_b.values,
1964        sp_b.dense_shape,
1965        name=name)
1966  return sparse_tensor.SparseTensor(out_indices, out_values, sp_a.dense_shape)
1967
1968
1969@tf_export("sparse_transpose")
1970def sparse_transpose(sp_input, perm=None, name=None):
1971  """Transposes a `SparseTensor`
1972
1973  The returned tensor's dimension i will correspond to the input dimension
1974  `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is
1975  the rank of the input tensor. Hence by default, this operation performs a
1976  regular matrix transpose on 2-D input Tensors.
1977
1978  For example, if `sp_input` has shape `[4, 5]` and `indices` / `values`:
1979
1980      [0, 3]: b
1981      [0, 1]: a
1982      [3, 1]: d
1983      [2, 0]: c
1984
1985  then the output will be a `SparseTensor` of shape `[5, 4]` and
1986  `indices` / `values`:
1987
1988      [0, 2]: c
1989      [1, 0]: a
1990      [1, 3]: d
1991      [3, 0]: b
1992
1993  Args:
1994    sp_input: The input `SparseTensor`.
1995    perm: A permutation of the dimensions of `sp_input`.
1996    name: A name prefix for the returned tensors (optional)
1997  Returns:
1998    A transposed `SparseTensor`.
1999
2000  Raises:
2001    TypeError: If `sp_input` is not a `SparseTensor`.
2002  """
2003  with ops.name_scope(name, "SparseTranspose", [sp_input]) as name:
2004    if perm is None:
2005      rank = array_ops.rank(sp_input)
2006      perm = (rank - 1) - math_ops.range(0, rank, 1)
2007    indices = sp_input.indices
2008    transposed_indices = array_ops.transpose(
2009        array_ops.gather(array_ops.transpose(indices), perm))
2010
2011    perm_ = tensor_util.constant_value(ops.convert_to_tensor(perm))
2012    if perm_ is not None and sp_input.get_shape().is_fully_defined():
2013      old_shape_ = sp_input.get_shape().as_list()
2014      transposed_dense_shape = list(old_shape_)  # Copy.
2015      for i, p in enumerate(perm_):
2016        transposed_dense_shape[i] = old_shape_[p]
2017    else:
2018      dense_shape = sp_input.dense_shape
2019      transposed_dense_shape = array_ops.gather(dense_shape, perm)
2020    transposed_st = sparse_tensor.SparseTensor(
2021        transposed_indices, sp_input.values, transposed_dense_shape)
2022    transposed_st = sparse_reorder(transposed_st)
2023    return transposed_st
2024
2025
2026def _add_sparse_to_tensors_map(sp_input,
2027                               container=None,
2028                               shared_name=None,
2029                               name=None):
2030  """Add a `SparseTensor` to a `SparseTensorsMap` and return its handle.
2031
2032  Args:
2033    sp_input: The input `SparseTensor`.
2034    container: The container for the underlying `SparseTensorsMap` (optional).
2035    shared_name: The shared name for the underlying `SparseTensorsMap`
2036      (optional, defaults to the name of the newly created op).
2037    name: A name prefix for the returned tensors (optional).
2038
2039  Returns:
2040    A string 1-vector (1D `Tensor`), with the single element representing the
2041    a unique handle to a `SparseTensor` stored by the `SparseTensorMap`
2042    underlying this op.
2043
2044  Raises:
2045    TypeError: If `sp_input` is not a `SparseTensor`.
2046  """
2047  sp_input = _convert_to_sparse_tensor(sp_input)
2048
2049  return gen_sparse_ops._add_sparse_to_tensors_map(
2050      sp_input.indices,
2051      sp_input.values,
2052      sp_input.dense_shape,
2053      container=container,
2054      shared_name=shared_name,
2055      name=name)
2056
2057
2058def _add_many_sparse_to_tensors_map(sp_input,
2059                                    container=None,
2060                                    shared_name=None,
2061                                    name=None):
2062  """Add a minibatch `SparseTensor` to a `SparseTensorsMap`, return `N` handles.
2063
2064  The `SparseTensor` must have rank `R` greater than 1, and the first dimension
2065  is treated as the minibatch dimension.  Elements of the `SparseTensor`
2066  must be sorted in increasing order of this first dimension.  The serialized
2067  `SparseTensor` objects going into each row of the output `Tensor` will have
2068  rank `R-1`.
2069
2070  The minibatch size `N` is extracted from `sparse_shape[0]`.
2071
2072  Args:
2073    sp_input: The input rank `R` `SparseTensor`.
2074    container: The container for the underlying `SparseTensorsMap` (optional).
2075    shared_name: The shared name for the underlying `SparseTensorsMap`
2076      (optional, defaults to the name of the newly created op).
2077    name: A name prefix for the returned tensors (optional).
2078
2079  Returns:
2080    A string matrix (2-D `Tensor`) with `N` rows and `1` column.
2081    Each row represents a unique handle to a `SparseTensor` stored by
2082    the `SparseTensorMap` underlying this op.
2083
2084  Raises:
2085    TypeError: If `sp_input` is not a `SparseTensor`.
2086  """
2087  sp_input = _convert_to_sparse_tensor(sp_input)
2088
2089  return gen_sparse_ops._add_many_sparse_to_tensors_map(
2090      sp_input.indices,
2091      sp_input.values,
2092      sp_input.dense_shape,
2093      container=container,
2094      shared_name=shared_name,
2095      name=name)
2096
2097
2098def _take_many_sparse_from_tensors_map(sparse_map_op,
2099                                       sparse_handles,
2100                                       rank=None,
2101                                       name=None):
2102  """Read `SparseTensors` from a `SparseTensorsMap` and concatenate them.
2103
2104  The input `sparse_handles` must be a string matrix of shape `[N, 1]` where
2105  `N` is the minibatch size and the rows correspond to packed outputs of
2106  `add_sparse_to_tensors_map`.  The ranks of the original `SparseTensor` objects
2107  must all match.  When the final `SparseTensor` is created, it has rank one
2108  higher than the ranks of the incoming `SparseTensor` objects (they have been
2109  concatenated along a new row dimension).
2110
2111  The output `SparseTensor` object's shape values for all dimensions but the
2112  first are the max across the input `SparseTensor` objects' shape values
2113  for the corresponding dimensions.  Its first shape value is `N`, the minibatch
2114  size.
2115
2116  The input `SparseTensor` objects' indices are assumed ordered in
2117  standard lexicographic order.  If this is not the case, after this
2118  step run `sparse_reorder` to restore index ordering.
2119
2120  For example, if the serialized input is a `[2, 3]` matrix representing two
2121  original `SparseTensor` objects:
2122
2123      index = [ 0]
2124              [10]
2125              [20]
2126      values = [1, 2, 3]
2127      shape = [50]
2128
2129  and
2130
2131      index = [ 2]
2132              [10]
2133      values = [4, 5]
2134      shape = [30]
2135
2136  then the final deserialized `SparseTensor` will be:
2137
2138      index = [0  0]
2139              [0 10]
2140              [0 20]
2141              [1  2]
2142              [1 10]
2143      values = [1, 2, 3, 4, 5]
2144      shape = [2 50]
2145
2146  Args:
2147    sparse_map_op: The `Operation` that created the original handles.
2148      Usually this is, e.g., `add_sparse_to_tensors_map(...).op`.
2149    sparse_handles: 2-D `Tensor` of type `string` of shape `[N, 1]`.
2150      The serialized and packed `SparseTensor` objects.
2151    rank: (optional) Python int, the rank of the `SparseTensor` objects.
2152    name: A name prefix for the returned tensors (optional)
2153
2154  Returns:
2155    A `SparseTensor` representing the deserialized `SparseTensor`s,
2156    concatenated along the `SparseTensor`s' first dimension.
2157
2158    All of the serialized `SparseTensor`s must have had the same rank and type.
2159  """
2160  if not isinstance(sparse_map_op, ops.Operation):
2161    raise TypeError("sparse_map_op be an Operation")
2162  if sparse_map_op.type not in ("AddSparseToTensorsMap",
2163                                "AddManySparseToTensorsMap"):
2164    raise TypeError(
2165        "sparse_map_op must be one of AddSparseToTensorsMap or "
2166        "AddSparseToTensorsMap. Instead, found `%s`." % sparse_map_op.type)
2167  with ops.colocate_with(sparse_map_op):
2168    shared_name = sparse_map_op.get_attr("shared_name") or sparse_map_op.name
2169    output_indices, output_values, output_shape = (
2170        gen_sparse_ops._take_many_sparse_from_tensors_map(
2171            sparse_handles,
2172            dtype=sparse_map_op.get_attr("T"),
2173            container=sparse_map_op.get_attr("container"),
2174            shared_name=shared_name,
2175            name=name))
2176
2177  # Feed rank data back in, if available
2178  output_indices.set_shape([None, rank])
2179  output_shape.set_shape([rank])
2180
2181  return sparse_tensor.SparseTensor(output_indices, output_values, output_shape)
2182