
    AVhY/             	          d Z ddlZddlZddlmZ ddlmZ ddlmZ ddlmZ ddlm	Z	 ddlm
Z dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl ddlmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z" ddl#m$Z$ ddl#m%Z% d Z&d  Z'd! Z( e%d"      dd#       Z) e%d$      dd%       Z* e%d&      dejV                  dfd'       Z, e%d(d)g*       ejZ                  d)       ej\                  dd+d,      	 	 	 	 dd.                     Z/ e%d(g *      dd/       Z0e/j                   jc                  d0d1      jc                  d2d1      e0_          e%d3d4g*       ejZ                  d4       ej\                  dd5d6      dd7                     Z2 e%d3g *      dd8       Z3 e%d9      dd:       Z4e4Z5 e%d;      dd<       Z6e6Z7d=Z8d> Z9	 	 	 	 dd?Z:d@ Z; e%dAdAdBg*       ejZ                  dB      ddC              Z< e%dDdDdEg*       ejZ                  dE      ejz                  ddF                     Z> G dG dH      Z? e%dIdJg*       ejZ                  dJ       ej\                  ddKdL       e?       dddddfdM                     Z@ e%dIg *      	 	 	 	 ddN       ZA e%dOdOdPg*       ejZ                  dP      ddQ              ZB e%dRg*      ejz                   ej                  ddS      	 	 	 ddT                     ZD e%dUg *      	 ddV       ZE e%dUdWg*       ejZ                  dW       ej\                  ddXdY       ej\                  ddZd[      	 	 dd\                            ZF e%d]d^g*       ejZ                  d^       ej\                  ddXdY      	 	 	 	 dd_                     ZG e%d`g *      	 dda       ZH e%d`dbg*       ejZ                  db       ej\                  ddXdY       ej\                  ddZd[      	 	 ddc                            ZI e%dddeg*       ejZ                  de       ej\                  ddXdY      	 	 	 	 ddf                     ZJ e%dgdgdhg*       ejZ                  dh      	 	 	 ddi              ZK e%djdjdkg*       ejZ                  dk      ddl              ZL e%dmdng*       ej                  ddo      	 	 ddp              ZM	 	 ddqZN e%drdrdsg*       ejZ                  ds      dt               ZO e%dududvg*       ejZ                  dv      ddw              ZP e%dxdxdyg*       ejZ                  dy      ddz              ZQ e%d{d|g*      ejz                   ejZ                  d|      dej                  fd}                     ZS e%d{g *      ejz                  ej                  dfd~              ZT e%ddg*      ejz                   ejZ                  d      dej                  fd                     ZU e%dg *      ejz                  ej                  dfd              ZVddZW e%dddg*      ejz                   ejZ                  d      dd                     ZX e%dg d*       ejZ                  d      	 	 	 dd              ZY e%dddg*       ejZ                  d      dd              ZZ e%dddg*       ejZ                  d      dd              Z[ e%dddg*       ejZ                  d      dd              Z\ e%dddg*       ejZ                  d      dd              Z] e%dg *      ejz                  d               Z^ ej                  ej                        dddej                  ddd-fde	j                  fd       Z` e%d      ejz                  	 	 	 	 	 	 dd              ZcddZdd Zed Zf	 	 	 ddZg	 	 	 ddZh	 	 ddZi G d dej                        Zkej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  g	ZueuD ]  Zv ekev      j                  ev        y)zdSparse Tensor Representation.

See also `tf.sparse.SparseTensor`.

API docstring: tensorflow.sparse
    N)composite_tensor)constant_op)dtypes)ops)sparse_tensor)tensor)tensor_conversion)tensor_shape)tensor_util)	array_ops)array_ops_stack)bincount_ops)	check_ops)control_flow_ops)gen_count_ops)gen_math_ops)gen_sparse_ops)math_ops)special_math_ops)*)compat)deprecation)dispatch)nest)
tf_inspect)collections_abc)get_canonical_name_for_symbol)	tf_exportc                     t        | t        j                        rt        j                  j	                  |       S t        | t        j                        st        d      | S )a  Convert `sp_input` to `SparseTensor` and return it.

  Args:
    sp_input: `SparseTensor` or `SparseTensorValue`.

  Returns:
    `sp_input` converted to `SparseTensor`.

  Raises:
    ValueError: if `sp_input` is neither `SparseTensor` nor `SparseTensorValue`.
  zInput must be a SparseTensor.)
isinstancer   SparseTensorValueSparseTensor
from_value	TypeError)sp_inputs    P/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/sparse_ops.py_convert_to_sparse_tensorr'   =   sL     -99:%%00::	Hm88	9
3
44	/    c                     t        | t              r| D cg c]  }t        |       c}S t        | t              r	d | D        S t	        d      c c}w )aS  Convert `sp_inputs` to `SparseTensor` objects and return them.

  Args:
    sp_inputs: `list` or `tuple` of `SparseTensor` or `SparseTensorValue`
      objects.

  Returns:
    `sp_inputs` converted to `SparseTensor` objects.

  Raises:
    ValueError: if any item in `sp_inputs` is neither `SparseTensor` nor
      `SparseTensorValue`.
  c              3   2   K   | ]  }t        |        y wN)r'   ).0r%   s     r&   	<genexpr>z-_convert_to_sparse_tensors.<locals>.<genexpr>a   s     JH%h/Js   zInputs must be a list or tuple.)r    listr'   tupler$   )	sp_inputsr%   s     r&   _convert_to_sparse_tensorsr1   P   sL     	4 @IJH%h/JJ	5!J	JJ344 Ks   Ac                 p   t        | t        j                        r&t        j                  | |t
        j                        S t        | t        j                        st        dj                  |            | j                  t
        j                  k(  r| S t        j                  | t
        j                        S )Nnamedtypez{} must be an integer value)r    r   integral_typesr   convert_to_tensorr   int64
tensor_libTensorr$   formatr5   r   cast)valuer4   s     r&   _make_int64_tensorr>   e   s|    v,,-  TFF	E:,,	-
188>
??
[[FLL L	ufll	++r(   zsparse.from_densec           	         t        j                  |d      5  t        j                  |       } t        j                  t        j                  | t        j                  |                   }t        j                  | |      }t        j                  | t        j                        }t        j                  |||      cddd       S # 1 sw Y   yxY w)a  Converts a dense tensor into a sparse tensor.

  Only elements not equal to zero will be present in the result. The resulting
  `SparseTensor` has the same dtype and shape as the input.

  >>> sp = tf.sparse.from_dense([0, 0, 3, 0, 1])
  >>> sp.shape.as_list()
  [5]
  >>> sp.values.numpy()
  array([3, 1], dtype=int32)
  >>> sp.indices.numpy()
  array([[2],
         [4]])

  Args:
    tensor: A dense `Tensor` to be converted to a `SparseTensor`.
    name: Optional name for the op.

  Returns:
    The `SparseTensor`.
  dense_to_sparse)out_typeN)r   
name_scoper7   r   where_v2r   	not_equal
zeros_like	gather_ndshaper   r8   r   r"   )r   r4   indicesvaluesrG   s        r&   
from_denserJ   o   s    . ~~d-. >""6*F  69#7#7#?@BG  1FOOFV\\:E%%gvu=> > >s   B#CCzsparse.expand_dimsc                    | j                   j                         d   }|"t        j                  | j                         d   }|dn|}t	        j
                  |d| g      5  t        |t        j                        r't	        j                  |dt        j                        }n%t        |t        j                        st        d      t        j                  |dk\  |||z   d	z         }t        j                  | j                         d   }t        j"                  |d	gt        j$                  
      }t        j&                  | j                   ddgd|g      }t        j&                  | j                   d|gddg      }t        j(                  |||gd	      }t        j&                  | j                   dg|g      }	t        j&                  | j                   |gdg      }
t	        j                  d	gdt        j$                        }t        j(                  |	||
gd      }t+        j,                  || j.                  |      cddd       S # 1 sw Y   yxY w)a  Returns a tensor with an length 1 axis inserted at index `axis`.

  Given a tensor `input`, this operation inserts a dimension of length 1 at the
  dimension index `axis` of `input`'s shape. The dimension index follows python
  indexing rules: It's zero-based, a negative index it is counted backward
  from the end.

  This operation is useful to:

  * Add an outer "batch" dimension to a single element.
  * Align axes for broadcasting.
  * To add an inner vector length axis to a tensor of scalars.

  For example:

  If you have a sparse tensor with shape `[height, width, depth]`:

  >>> sp = tf.sparse.SparseTensor(indices=[[3,4,1]], values=[7,],
  ...                             dense_shape=[10,10,3])

  You can add an outer `batch` axis by passing `axis=0`:

  >>> tf.sparse.expand_dims(sp, axis=0).shape.as_list()
  [1, 10, 10, 3]

  The new axis location matches Python `list.insert(axis, 1)`:

  >>> tf.sparse.expand_dims(sp, axis=1).shape.as_list()
  [10, 1, 10, 3]

  Following standard python indexing rules, a negative `axis` counts from the
  end so `axis=-1` adds an inner most dimension:

  >>> tf.sparse.expand_dims(sp, axis=-1).shape.as_list()
  [10, 10, 3, 1]

  Note: Unlike `tf.expand_dims` this function includes a default value for the
  `axis`: `-1`. So if `axis is not specified, an inner dimension is added.

  >>> sp.shape.as_list()
  [10, 10, 3]
  >>> tf.sparse.expand_dims(sp).shape.as_list()
  [10, 10, 3, 1]

  This operation requires that `axis` is a valid index for `input.shape`,
  following python indexing rules:

  ```
  -1-tf.rank(input) <= axis <= tf.rank(input)
  ```

  This operation is related to:

  * `tf.expand_dims`, which provides this functionality for dense tensors.
  * `tf.squeeze`, which removes dimensions of size 1, from dense tensors.
  * `tf.sparse.reshape`, which provides more flexible reshaping capability.

  Args:
    sp_input: A `SparseTensor`.
    axis: 0-D (scalar). Specifies the dimension index at which to expand the
      shape of `input`. Must be in the range `[-rank(sp_input) - 1,
      rank(sp_input)]`. Defaults to `-1`.
    name: The name of the output `SparseTensor`.

  Returns:
    A `SparseTensor` with the same data as `sp_input`, but its shape has an
    additional dimension of size 1 added.
  r   Nexpand_dimsdefault_namerI   axisr3   zLaxis must be an integer value in range [-rank(sp_input) - 1, rank(sp_input)]   r5   rP   	new_shaperH   rI   dense_shape)rV   	get_shaper   rG   r   rB   r    r   r6   r7   r   int32r9   r:   r$   rC   rH   zerosr8   sliceconcatr   r"   rI   )r%   rP   r4   rankcolumn_size	new_indexindices_beforeindices_afterrH   shape_beforeshape_afterrT   rG   s                r&   sparse_expand_dimsrc      s   L 
			'	'	)!	,$	\??8//03D|$
~~dzJ D$--.""4fFLLIdj//0 . / / daitd{Q?D //("2"23A6Ka 0EI__X%5%51vDzJNOOH$4$4q$i"bJM	M2<G
 ??8#7#7!tfEL//("6"6EK%%qc6<<PIlI{C!LE %%UD7D D Ds   !GIIz
sparse.eyec                    t        j                  |d| |g      5  t        | d      } || nt        |d      }t        j                  | |      }t        j
                  |t        j                        }t        j                  t        j                  ||gd      t        j                  ||      | |g	      cddd       S # 1 sw Y   yxY w)
a7  Creates a two-dimensional sparse tensor with ones along the diagonal.

  Args:
    num_rows: Non-negative integer or `int32` scalar `tensor` giving the number
      of rows in the resulting matrix.
    num_columns: Optional non-negative integer or `int32` scalar `tensor` giving
      the number of columns in the resulting matrix. Defaults to `num_rows`.
    dtype: The type of element in the resulting `Tensor`.
    name: A name for this `Op`. Defaults to "eye".

  Returns:
    A `SparseTensor` of shape [num_rows, num_columns] with ones along the
    diagonal.
  eyerN   num_rowsNnum_columnsrR   rQ   rS   rU   )r   rB   r>   r   minimumranger   r8   r   r"   r   stackr   ones)rf   rg   r5   r4   	diag_size
diag_ranges         r&   
sparse_eyern      s    & ~~d+7NO -!(J7H)1(7I]8$K   ;7I	>J%%%%z:&>QG~~iu5{+-- - -s   BCCzsparse.concatsparse_concat)v1z*concat_dim is deprecated, use axis instead
concat_dimFc                     t        j                  d|d|      }||}t        j                  d| d|      } t        | |||      S )a  Concatenates a list of `SparseTensor` along the specified dimension.

  Concatenation is with respect to the dense versions of each sparse input.
  It is assumed that each inputs is a `SparseTensor` whose elements are ordered
  along increasing dimension number.

  If expand_nonconcat_dim is False, all inputs' shapes must match, except for
  the concat dimension. If expand_nonconcat_dim is True, then inputs' shapes are
  allowed to vary among all inputs.

  The `indices`, `values`, and `shapes` lists must have the same length.

  If expand_nonconcat_dim is False, then the output shape is identical to the
  inputs', except along the concat dimension, where it is the sum of the inputs'
  sizes along that dimension.

  If expand_nonconcat_dim is True, then the output shape along the non-concat
  dimensions will be expand to be the largest among all inputs, and it is the
  sum of the inputs sizes along the concat dimension.

  The output elements will be resorted to preserve the sort order along
  increasing dimension number.

  This op runs in `O(M log M)` time, where `M` is the total number of non-empty
  values across all inputs. This is due to the need for an internal sort in
  order to concatenate efficiently across an arbitrary dimension.

  For example, if `axis = 1` and the inputs are

      sp_inputs[0]: shape = [2, 3]
      [0, 2]: "a"
      [1, 0]: "b"
      [1, 1]: "c"

      sp_inputs[1]: shape = [2, 4]
      [0, 1]: "d"
      [0, 2]: "e"

  then the output will be

      shape = [2, 7]
      [0, 2]: "a"
      [0, 4]: "d"
      [0, 5]: "e"
      [1, 0]: "b"
      [1, 1]: "c"

  Graphically this is equivalent to doing

      [    a] concat [  d e  ] = [    a   d e  ]
      [b c  ]        [       ]   [b c          ]

  Another example, if 'axis = 1' and the inputs are

      sp_inputs[0]: shape = [3, 3]
      [0, 2]: "a"
      [1, 0]: "b"
      [2, 1]: "c"

      sp_inputs[1]: shape = [2, 4]
      [0, 1]: "d"
      [0, 2]: "e"

  if expand_nonconcat_dim = False, this will result in an error. But if
  expand_nonconcat_dim = True, this will result in:

      shape = [3, 7]
      [0, 2]: "a"
      [0, 4]: "d"
      [0, 5]: "e"
      [1, 0]: "b"
      [2, 1]: "c"

  Graphically this is equivalent to doing

      [    a] concat [  d e  ] = [    a   d e  ]
      [b    ]        [       ]   [b            ]
      [  c  ]                    [  c          ]


  Args:
    axis: Dimension to concatenate along. Must be in range [-rank, rank),
      where rank is the number of dimensions in each input `SparseTensor`.
    sp_inputs: List of `SparseTensor` to concatenate.
    name: A name prefix for the returned tensors (optional).
    expand_nonconcat_dim: Whether to allow the expansion in the non-concat
      dimensions. Defaulted to False.
    concat_dim: The old (deprecated) name for axis.
    expand_nonconcat_dims: alias for expand_nonconcat_dim

  Returns:
    A `SparseTensor` with the concatenated output.

  Raises:
    TypeError: If `sp_inputs` is not a list of `SparseTensor`.
  expand_nonconcat_dimsexpand_nonconcat_dimrP   rq   )r   deprecated_argument_lookupsparse_concat_v2)rP   r0   r4   rt   rq   rs   s         r&   ro   ro     s[    T %??424 &0		/	/l0:
<$	$	+?	FFr(   c                     t        |      }t        |      dk(  r|d   S |D cg c]  }|j                   }}|D cg c]  }|j                   }}|D cg c]  }|j                   }}|rt        j                  t        j                  |D cg c]  }t        j                  |ddg       c}d      d      }	|D cg c];  }t        j                  |	d    dk(  r|dd  n|  dz     dk(  rg n|	 dz   d  gd      = }}t        j                  ||| |      \  }
}}|D cg c]  }|j                   }}t        d |D              rp|rCg }t        |d   j                        D ]%  |j!                  t#        fd|D                     ' n|d   j%                         }t'         fd|D              | <   nt)        j*                         }t        d |D              r<t-        j.                  |t0        j2                  	      }t5        j6                  |
||      S t5        j6                  |
||      }|j9                  t)        j:                  |             |S c c}w c c}w c c}w c c}w c c}w c c}w )
NrQ   r   rL   r4   c              3   8   K   | ]  }|j                   d u  y wr+   )r\   r,   rG   s     r&   r-   z#sparse_concat_v2.<locals>.<genexpr>  s     :E4	:s   c              3   J   K   | ]  }t        j                  |        y wr+   r
   dimension_at_index)r,   rG   dims     r&   r-   z#sparse_concat_v2.<locals>.<genexpr>  s&      + //s; +    #c              3   J   K   | ]  }t        j                  |        y wr+   r|   )r,   rG   rP   s     r&   r-   z#sparse_concat_v2.<locals>.<genexpr>  s&      $# 	''t4$#r   c              3   <   K   | ]  }|j                           y wr+   )is_fully_definedrz   s     r&   r-   z#sparse_concat_v2.<locals>.<genexpr>  s     <e			!<s   rR   )r1   lenrH   rI   rV   r   
reduce_maxr   r[   reshaper   ro   rG   allri   r\   appendmaxas_listsumr
   unknown_shaper   r7   r   r8   r   r"   	set_shapeTensorShape)rP   r0   rs   r4   r%   indsvalsshapesrG   	max_shape
output_ind
output_valoutput_shapeinpinput_shapesstatic_output_shapeoutputr~   s   `                @r&   rv   rv     s   (3)^qQ<+4	5x(

	5$	5*3	4h(//	4$	41:;XH  ;&;##<BC5Yuq"g.CQ	HIJLI "
 	 	etrz $BCj$T$(3rz 68(3
 		F  ""4vt$G '*j, (11#))1,1:\::|A++, ,#"" +)+ +	,,
 )O335 # $#!$# !# '446<|<<(()</5||=L%%j*lKK
 ''
JMF
\--.ABCMY 
6	4;
 D 2s#   III$I) A I.$I3z4    concat_dim: The old (deprecated) name for axis.
 z:    expand_nonconcat_dims: alias for expand_nonconcat_dim
z
sparse.add
sparse_addz+thresh is deprecated, use threshold insteadthreshc                 T    t        j                  d|d|      }|d}t        | ||      S )a  Adds two tensors, at least one of each is a `SparseTensor`.

  If one `SparseTensor` and one `Tensor` are passed in, returns a `Tensor`.  If
  both arguments are `SparseTensor`s, this returns a `SparseTensor`.  The order
  of arguments does not matter.  Use vanilla `tf.add()` for adding two dense
  `Tensor`s.

  The shapes of the two operands must match: broadcasting is not supported.

  The indices of any input `SparseTensor` are assumed ordered in standard
  lexicographic order.  If this is not the case, before this step run
  `SparseReorder` to restore index ordering.

  If both arguments are sparse, we perform "clipping" as follows.  By default,
  if two values sum to zero at some index, the output `SparseTensor` would still
  include that particular location in its index, storing a zero in the
  corresponding value slot.  To override this, callers can specify `thresh`,
  indicating that if the sum has a magnitude strictly smaller than `thresh`, its
  corresponding value and index would then not be included.  In particular,
  `thresh == 0.0` (default) means everything is kept and actual thresholding
  happens only for a positive value.

  For example, suppose the logical sum of two sparse operands is (densified):

      [       2]
      [.1     0]
      [ 6   -.2]

  Then,

  * `thresh == 0` (the default): all 5 index/value pairs will be returned.
  * `thresh == 0.11`: only .1 and 0 will vanish, and the remaining three
      index/value pairs will be returned.
  * `thresh == 0.21`: .1, 0, and -.2 will vanish.

  Args:
    a: The first operand; `SparseTensor` or `Tensor`.
    b: The second operand; `SparseTensor` or `Tensor`. At least one operand
      must be sparse.
    threshold: An optional 0-D `Tensor` (defaults to `0`). The magnitude
      threshold that determines if an output value/index pair takes space. Its
      dtype should match that of the values if they are real; if the latter are
      complex64/complex128, then the dtype should be float32/float64,
      correspondingly.
    thresh: Deprecated alias for `threshold`.

  Returns:
    A `SparseTensor` or a `Tensor`, representing the sum.

  Raises:
    TypeError: If both `a` and `b` are `Tensor`s.  Use `tf.add()` instead.
  	thresholdr   r   )r   ru   sparse_add_v2)abr   r   s       r&   r   r     s9    r 44[)5=vG)I	q!Y	''r(   c           	         t         j                  t         j                  ft        fd| |fD              st	        d      t        fd| |fD              rGt        |       } t        |      }t        j                  || j                  j                  j                  j                  d      }t        j                  | j                  | j                  | j                   |j                  |j                  |j                   |      \  }}}| j#                         j%                  |j#                                t'        j(                  | j#                         |j#                               }|j+                         r|j-                         }t        j                  |||      S t/        |      r|| }} t        j0                  | j                  | j                  | j                   |      S )a}  Adds two tensors, at least one of each is a `SparseTensor`.

  If one `SparseTensor` and one `Tensor` are passed in, returns a `Tensor`.  If
  both arguments are `SparseTensor`s, this returns a `SparseTensor`.  The order
  of arguments does not matter.  Use vanilla `tf.add()` for adding two dense
  `Tensor`s.

  The shapes of the two operands must match: broadcasting is not supported.

  The indices of any input `SparseTensor` are assumed ordered in standard
  lexicographic order.  If this is not the case, before this step run
  `SparseReorder` to restore index ordering.

  If both arguments are sparse, we perform "clipping" as follows.  By default,
  if two values sum to zero at some index, the output `SparseTensor` would still
  include that particular location in its index, storing a zero in the
  corresponding value slot.  To override this, callers can specify `threshold`,
  indicating that if the sum has a magnitude strictly smaller than `threshold`,
  its corresponding value and index would then not be included.  In particular,
  `threshold == 0.0` (default) means everything is kept and actual thresholding
  happens only for a positive value.

  For example, suppose the logical sum of two sparse operands is (densified):

      [       2]
      [.1     0]
      [ 6   -.2]

  Then,

  * `threshold == 0` (the default): all 5 index/value pairs will be
      returned.
  * `threshold == 0.11`: only .1 and 0 will vanish, and the remaining three
      index/value pairs will be returned.
  * `threshold == 0.21`: .1, 0, and -.2 will vanish.

  Args:
    a: The first operand; `SparseTensor` or `Tensor`.
    b: The second operand; `SparseTensor` or `Tensor`. At least one operand
      must be sparse.
    threshold: A 0-D `Tensor`. The magnitude threshold that determines if an
      output value/index pair takes space. Its dtype should match that of the
      values if they are real; if the latter are complex64/complex128, then the
      dtype should be float32/float64, correspondingly.

  Returns:
    A `SparseTensor` or a `Tensor`, representing the sum.

  Raises:
    TypeError: If both `a` and `b` are `Tensor`s.  Use `tf.add()` instead.
  c              3   6   K   | ]  }t        |        y wr+   r    r,   r   sparse_classess     r&   r-   z sparse_add_v2.<locals>.<genexpr>B  s     ?Z^,?   zGAt least one input should be SparseTensor; do you mean to use tf.add()?c              3   6   K   | ]  }t        |        y wr+   r   r   s     r&   r-   z sparse_add_v2.<locals>.<genexpr>F  s     ;SC	(;r   r   )r5   r4   )r   r"   r!   anyr$   r   r'   r   r7   rI   r5   
real_dtype
base_dtyper   r   rH   rV   rW   assert_is_compatible_withr   broadcast_static_shaper   r   r    sparse_tensor_dense_add)r   r   r   r   r   r   static_shaper   s          @r&   r   r     s   j "..0O0OP.	?A?	?
 % & & 	;QF;;!!$A!!$A%%22==KQI 	!!!))QXXq}}"#))QXXq}}"+	- )J
L KKM++AKKM:33AKKM45KKMCL$$&!))+l%%j*lKK !^$a11!))QXX23--D Dr(   zsparse.crossc                     |d}t        j                  |t        j                        }t	        |       \  }}}}t        j                  ||||||      \  }}}	t        j                  |||	      S )a  Generates sparse cross from a list of sparse and dense tensors.

  For example, if the inputs are

      * inputs[0]: SparseTensor with shape = [2, 2]
        [0, 0]: "a"
        [1, 0]: "b"
        [1, 1]: "c"
      * inputs[1]: SparseTensor with shape = [2, 1]
        [0, 0]: "d"
        [1, 0]: "e"
      * inputs[2]: Tensor [["f"], ["g"]]

  then the output will be:

      shape = [2, 2]
      [0, 0]: "a_X_d_X_f"
      [1, 0]: "b_X_e_X_g"
      [1, 1]: "c_X_e_X_g"

  Customized separator "_Y_":

  >>> inp_0 = tf.constant([['a'], ['b']])
  >>> inp_1 = tf.constant([['c'], ['d']])
  >>> output = tf.sparse.cross([inp_0, inp_1], separator='_Y_')
  >>> output.values
  <tf.Tensor: shape=(2,), dtype=string, numpy=array([b'a_Y_c', b'b_Y_d'],
    dtype=object)>


  Args:
    inputs: An iterable of `Tensor` or `SparseTensor`.
    name: Optional name for the op.
    separator: A string added between each string being joined. Defaults to
      '_X_'.

  Returns:
    A `SparseTensor` of type `string`.
  _X_)rH   rI   r   dense_inputssepr4   )	r   r7   r   string_sparse_cross_internal_v2r   sparse_cross_v2r   r"   )
inputsr4   	separatorrH   rI   r   r   indices_out
values_out	shape_outs
             r&   sparse_crossr   `  sy    R I##Iv}}=)*CF*K''66<'5'E'E
($+z9 
	#	#KY	GGr(   zsparse.cross_hashedc                 "    t        | d|||      S )a  Generates hashed sparse cross from a list of sparse and dense tensors.

  For example, if the inputs are

      * inputs[0]: SparseTensor with shape = [2, 2]
        [0, 0]: "a"
        [1, 0]: "b"
        [1, 1]: "c"
      * inputs[1]: SparseTensor with shape = [2, 1]
        [0, 0]: "d"
        [1, 0]: "e"
      * inputs[2]: Tensor [["f"], ["g"]]

  then the output will be:

      shape = [2, 2]
      [0, 0]: FingerprintCat64(
                  Fingerprint64("f"), FingerprintCat64(
                      Fingerprint64("d"), Fingerprint64("a")))
      [1, 0]: FingerprintCat64(
                  Fingerprint64("g"), FingerprintCat64(
                      Fingerprint64("e"), Fingerprint64("b")))
      [1, 1]: FingerprintCat64(
                  Fingerprint64("g"), FingerprintCat64(
                      Fingerprint64("e"), Fingerprint64("c")))

  Args:
    inputs: An iterable of `Tensor` or `SparseTensor`.
    num_buckets: An `int` that is `>= 0`.
      output = hashed_value%num_buckets if num_buckets > 0 else hashed_value.
    hash_key: Integer hash_key that will be used by the `FingerprintCat64`
      function. If not given, will use a default key.
    name: Optional name for the op.

  Returns:
    A `SparseTensor` of type `int64`.
  T)r   hashed_outputnum_bucketshash_keyr4   )_sparse_cross_internal)r   r   r   r4   s       r&   sparse_cross_hashedr     s!    N 
 
 r(   l   /{c                    t        | t        t        f      st        d      t	        d | D              st        d      | D cg c]  }t        |t
        j                        s|! }}| D cg c]  }t        |t
        j                        r|! }}|D cg c]  }|j                   }}|D cg c]  }|j                   }}|D cg c]  }|j                   }}t        t        |            D ]M  }||   j                  t        j                  k7  s$t        j                   ||   t        j"                        ||<   O t        t        |            D ]M  }||   j                  t        j                  k7  s$t        j                   ||   t        j"                        ||<   O ||||fS c c}w c c}w c c}w c c}w c c}w )z#See gen_sparse_ops.sparse_cross_v2.Inputs must be a listc              3      K   | ]:  }t        |t        j                        xs t        |t        j                         < y wr+   r    r   r"   r9   r:   r,   is     r&   r-   z,_sparse_cross_internal_v2.<locals>.<genexpr>  F        
]'') M,6q*:K:K,LM   A Az*All inputs must be Tensor or SparseTensor.)r    r/   r.   r$   r   r   r"   rH   rI   rV   ri   r   r5   r   r   r   r<   r8   )r   r   sparse_inputsr   r%   rH   rI   r   s           r&   r   r     s   	FUDM	*
+
,,	   
 @
AA:a)C)CDa-  z!]-G-GHa,  /<<(X<'<,9:HOO:&:1>?XH  ?&?V 9aay&--'--q	6<<8fQi9 \"# EaA- l1ov||Dl1oE 
&&,	.. =:?s*   F,#F,-F1F1F60F;	G c                    t        | t        t        f      st        d      t	        d | D              st        d      | D cg c]  }t        |t
        j                        s|! }}| D cg c]  }t        |t
        j                        r|! }}|D cg c]  }|j                   }	}|D cg c]  }|j                   }
}|D cg c]  }|j                   }}|rt        j                  nt        j                  }t        j                  }t        t        |
            D ]]  }|
|   j                  t        j                  k7  s$t!        j"                  |
|   t        j                        |
|<   t        j                  }_ t        t        |            D ]]  }||   j                  t        j                  k7  s$t!        j"                  ||   t        j                        ||<   t        j                  }_ t%        j&                  |	|
|||||xs t(        |||
      \  }}}t        j                  |||      S c c}w c c}w c c}w c c}w c c}w )z See gen_sparse_ops.sparse_cross.r   c              3      K   | ]:  }t        |t        j                        xs t        |t        j                         < y wr+   r   r   s     r&   r-   z)_sparse_cross_internal.<locals>.<genexpr>  r   r   z All inputs must be SparseTensors)
rH   rI   r   r   r   r   r   rA   internal_typer4   )r    r/   r.   r$   r   r   r"   rH   rI   rV   r   r8   r   ri   r   r5   r   r<   r   r   _DEFAULT_HASH_KEY)r   r   r   r   r4   r   r   r   r%   rH   rI   r   rA   r   r   r   r   s                    r&   r   r     s    
FUDM	*
+
,,	   
 6
77 :a)C)CDa-  z!]-G-GHa,  /<<(X<'<,9:HOO:&:1>?XH  ?&?*V\\(---V #aay&--'--q	6<<8fQillm# \"# #aA- l1ov||Dl1ollm#
 (6'B'B!,,!
($+z9 
	#	#KY	GGE =:?s*   H:#H:-H?H?I0I		Ic                     t        j                  | j                  | j                  | j                  |      }t        j                  | j                  || j                        S )a  Adds up a SparseTensor and a dense Tensor, using these special rules:

  (1) Broadcasts the dense side to have the same shape as the sparse side, if
      eligible;
  (2) Then, only the dense values pointed to by the indices of the SparseTensor
      participate in the cwise addition.

  By the rules, the result is a logical SparseTensor with exactly the same
  indices and shape, but possibly with different non-zero values.  The output of
  this Op is the resultant non-zero values.

  Args:
    sp_t: the SparseTensor operand.
    dense_t: the dense Tensor operand; must have the same dtype and a
      broadcast-compatible shape as `sp_t`.

  Returns:
    output: the SparseTensor output.
  )r   sparse_dense_cwise_addrH   rI   rV   r   r"   )sp_tdense_tresults      r&   r   r     sK    ( 00t{{151A1A7L&		#	#DLL&$:J:J	KKr(   zsparse.reordersparse_reorderc                    t        |       } t        j                  | j                  | j                  | j
                  |      \  }}| j                         j                         r5| j                         j                         }t        j                  |||      S t        j                  | j
                        }t        j                  |||      }|j                  | j                         |S )a  Reorders a `SparseTensor` into the canonical, row-major ordering.

  Note that by convention, all sparse ops preserve the canonical ordering
  along increasing dimension number. The only time ordering can be violated
  is during manual manipulation of the indices and values to add entries.

  Reordering does not affect the shape of the `SparseTensor`.

  For example, if `sp_input` has shape `[4, 5]` and `indices` / `values`:

      [0, 3]: b
      [0, 1]: a
      [3, 1]: d
      [2, 0]: c

  then the output will be a `SparseTensor` of shape `[4, 5]` and
  `indices` / `values`:

      [0, 1]: a
      [0, 3]: b
      [2, 0]: c
      [3, 1]: d

  Args:
    sp_input: The input `SparseTensor`.
    name: A name prefix for the returned tensors (optional)

  Returns:
    A `SparseTensor` with the same shape and non-empty values, but in
    canonical ordering.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  rx   )r'   r   r   rH   rI   rV   rW   r   r   r   r"   r   identityr   rG   )r%   r4   reordered_indreordered_valrV   	sp_outputs         r&   r   r   5  s    J 'x0( ##


HOOX-A-AN - **,$$&..0K%%m]KPP$$X%9%9:K**=-+68I 'r(   zsparse.reshapesparse_reshapec                    t        |       } t        j                  |t        j                        }t        j                  |d| g      5 }t        j                  | j                  | j                  ||      \  }}t        j                  |      }|j                  |j                         nd}|K| j                  j!                         r0t        j"                  |      }|%t%        d |D              }|dkD  rt'        d|z        t)        |      }t+        j,                  | j                  j                               }	t%        d |D              }
|
dk(  rGd	|vrC|j/                  d      }|d| ||dz   d z   }t1        |	t+        j,                  |      z        ||<   |
d	k(  s	|
dk(  rTd	|vrPt+        j,                  |      }||	k7  rt'        d
|	||fz        t3        j4                  |t        j                        }t7        j8                  |t;        j<                  | j>                        |      cddd       S # 1 sw Y   yxY w)a  Reshapes a `SparseTensor` to represent values in a new dense shape.

  This operation has the same semantics as `reshape` on the represented dense
  tensor.  The indices of non-empty values in `sp_input` are recomputed based
  on the new dense shape, and a new `SparseTensor` is returned containing the
  new indices and new shape.  The order of non-empty values in `sp_input` is
  unchanged.

  If one component of `shape` is the special value -1, the size of that
  dimension is computed so that the total dense size remains constant.  At
  most one component of `shape` can be -1.  The number of dense elements
  implied by `shape` must be the same as the number of dense elements
  originally represented by `sp_input`.

  For example, if `sp_input` has shape `[2, 3, 6]` and `indices` / `values`:

      [0, 0, 0]: a
      [0, 0, 1]: b
      [0, 1, 0]: c
      [1, 0, 0]: d
      [1, 2, 3]: e

  and `shape` is `[9, -1]`, then the output will be a `SparseTensor` of
  shape `[9, 4]` and `indices` / `values`:

      [0, 0]: a
      [0, 1]: b
      [1, 2]: c
      [4, 2]: d
      [8, 1]: e

  Args:
    sp_input: The input `SparseTensor`.
    shape: A 1-D (vector) int64 `Tensor` specifying the new dense shape of the
      represented `SparseTensor`.
    name: A name prefix for the returned tensors (optional)

  Returns:
    A `SparseTensor` with the same non-empty values but with indices calculated
    by the new dense shape.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
    ValueError:  If argument `shape` requests a `SparseTensor` with a different
      number of elements than `sp_input`.
    ValueError:  If `shape` has more than one inferred (== -1) dimension.
  rR   SparseReshaperx   Nc              3   &   K   | ]	  }|d k(    yw)rL   N )r,   ds     r&   r-   z!sparse_reshape.<locals>.<genexpr>  s     !Ga!r'!Gs   rQ   z5At most one dimension can be inferred (-1). Found: %sc              3   $   K   | ]  }|d u  
 y wr+   r   )r,   r~   s     r&   r-   z!sparse_reshape.<locals>.<genexpr>  s     DtDs   r   zCCannot reshape a tensor with %d elements to shape %s (%d elements).) r'   r   r<   r   r8   r   rB   r   r   rH   rV   r   constant_value_as_shapendimsr   rG   r   constant_valuer   
ValueErrorr.   npprodindexintr   constantr   r"   r   r   rI   )r%   rG   r4   reshaped_indreshaped_shapereshaped_shape_constshape_const_by_usernum_implied_by_useroriginal_reshaped_shapein_shape_sizenum_impliedimplied_idxnon_implied_idxreshaped_sizes                 r&   r   r   l  sF   f 'x0(
--V\\
2%
~~dOhZ8 26D#1#@#@(..D$B L. '>>uE*>*D*D*P$$&  	(NN++- (66u=		(!!G3F!GG"E#$% % !%%9 :gghnn4467mD/CDDk
 
	a';;-33D9#L[1#K!O$456 	 -0RWW_55-7[)		kQ.';; 45M)5}EFG G %-- 6 %%l&/&8&8&I&46a26 26 26s   	G%H88Ic                       e Zd Zd Zy)KeywordRequiredc                      y)NzKeywordRequired()r   )selfs    r&   __repr__zKeywordRequired.__repr__  s    r(   N)__name__
__module____qualname__r   r   r(   r&   r   r     s    r(   r   zsparse.splitsparse_splitz)split_dim is deprecated, use axis instead	split_dimc           	         t        | t              st        d      |t        d      |t        d      |t        d      t        j                  d|d|      }t        |      }t        j                  ||j                  |j                  |j                  ||      \  }}}g }	t        d|      D ]1  }
|	j                  t        j                  ||
   ||
   ||
                3 |	S )	a  Split a `SparseTensor` into `num_split` tensors along `axis`.

  If the `sp_input.dense_shape[axis]` is not an integer multiple of `num_split`
  each slice starting from 0:`shape[axis] % num_split` gets extra one
  dimension. For example, if `axis = 1` and `num_split = 2` and the
  input is:

      input_tensor = shape = [2, 7]
      [    a   d e  ]
      [b c          ]

  Graphically the output tensors are:

      output_tensor[0] =
      [    a   ]
      [b c     ]

      output_tensor[1] =
      [ d e  ]
      [      ]

  Args:
    keyword_required: Python 2 standin for * (temporary for argument reorder)
    sp_input: The `SparseTensor` to split.
    num_split: A Python integer. The number of ways to split.
    axis: A 0-D `int32` `Tensor`. The dimension along which to split. Must be in
      range [-rank, rank), where rank is the number of dimensions in the input
      `SparseTensor`.
    name: A name for the operation (optional).
    split_dim: Deprecated old name for axis.

  Returns:
    `num_split` `SparseTensor` objects resulting from splitting `value`.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
    ValueError: If the deprecated `split_dim` and `axis` are both non None.
  z1Keyword arguments are required for this function.zsp_input is requiredznum_split is requiredzaxis is requiredrP   r   rx   r   )r    r   r   r   ru   r'   r   r   rH   rI   rV   ri   r   r   r"   )keyword_requiredr%   	num_splitrP   r4   r   output_indsoutput_valsoutput_shapessparse_tensorsr   s              r&   r   r     s   ` 
$o	6
H
II
+
,,
,
--	\
'
((		/	/k09
;$&x0( !!




//



 *+{M .I 6a"";q>;q>#0#3	566 
r(   c                 "    t        | |||d      S )aH  Split a `SparseTensor` into `num_split` tensors along `axis`.

  If the `sp_input.dense_shape[axis]` is not an integer multiple of `num_split`
  each slice starting from 0:`shape[axis] % num_split` gets extra one
  dimension. For example:

  >>> indices = [[0, 2], [0, 4], [0, 5], [1, 0], [1, 1]]
  >>> values = [1, 2, 3, 4, 5]
  >>> t = tf.sparse.SparseTensor(indices=indices, values=values,
  ...                            dense_shape=[2, 7])
  >>> tf.sparse.to_dense(t)
  <tf.Tensor: shape=(2, 7), dtype=int32, numpy=
  array([[0, 0, 1, 0, 2, 3, 0],
         [4, 5, 0, 0, 0, 0, 0]], dtype=int32)>

  >>> output = tf.sparse.split(sp_input=t, num_split=2, axis=1)
  >>> tf.sparse.to_dense(output[0])
  <tf.Tensor: shape=(2, 4), dtype=int32, numpy=
  array([[0, 0, 1, 0],
         [4, 5, 0, 0]], dtype=int32)>
  >>> tf.sparse.to_dense(output[1])
  <tf.Tensor: shape=(2, 3), dtype=int32, numpy=
  array([[2, 3, 0],
         [0, 0, 0]], dtype=int32)>

  >>> output = tf.sparse.split(sp_input=t, num_split=2, axis=0)
  >>> tf.sparse.to_dense(output[0])
  <tf.Tensor: shape=(1, 7), dtype=int32, numpy=array([[0, 0, 1, 0, 2, 3, 0]],
  dtype=int32)>
  >>> tf.sparse.to_dense(output[1])
  <tf.Tensor: shape=(1, 7), dtype=int32, numpy=array([[4, 5, 0, 0, 0, 0, 0]],
  dtype=int32)>

  >>> output = tf.sparse.split(sp_input=t, num_split=2, axis=-1)
  >>> tf.sparse.to_dense(output[0])
  <tf.Tensor: shape=(2, 4), dtype=int32, numpy=
  array([[0, 0, 1, 0],
         [4, 5, 0, 0]], dtype=int32)>
  >>> tf.sparse.to_dense(output[1])
  <tf.Tensor: shape=(2, 3), dtype=int32, numpy=
  array([[2, 3, 0],
         [0, 0, 0]], dtype=int32)>

  Args:
    sp_input: The `SparseTensor` to split.
    num_split: A Python integer. The number of ways to split.
    axis: A 0-D `int32` `Tensor`. The dimension along which to split. Must be in
      range [-rank, rank), where rank is the number of dimensions in the input
      `SparseTensor`.
    name: A name for the operation (optional).

  Returns:
    `num_split` `SparseTensor` objects resulting from splitting `value`.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  N)r%   r  rP   r4   r   )r   )r%   r  rP   r4   s       r&   sparse_split_v2r  +  s     | 
x ) $	
& &r(   zsparse.slicesparse_slicec           	         t        |       } t        j                  |t        j                        }t        j                  |t        j                        }t        j
                  |d| g      5 }t        j                  | j                  | j                  | j                  |||      \  }}}t        j                  |||      cddd       S # 1 sw Y   yxY w)a  Slice a `SparseTensor` based on the `start` and `size`.

  For example, if the input is

      input_tensor = shape = [2, 7]
      [    a   d e  ]
      [b c          ]

  Graphically the output tensors are:

      sparse.slice([0, 0], [2, 4]) = shape = [2, 4]
      [    a  ]
      [b c    ]

      sparse.slice([0, 4], [2, 3]) = shape = [2, 3]
      [ d e  ]
      [      ]

  Args:
    sp_input: The `SparseTensor` to split.
    start: 1-D. tensor represents the start of the slice.
    size: 1-D. tensor represents the size of the slice.
    name: A name for the operation (optional).

  Returns:
    A `SparseTensor` objects resulting from splicing.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  SparseSlicerx   N)r'   r   r7   r   r8   rB   r   r  rH   rI   rV   r   r"   )r%   startsizer4   output_indicesoutput_valuesr   s          r&   r  r  p  s    B 'x0(


v||
4%			tV\\	2$
~~dMH:6 
4$2@2M2M3/NM< %%nm&24
4 
4 
4s   ,AC

Csparse_to_densezGCreate a `tf.sparse.SparseTensor` and use `tf.sparse.to_dense` instead.c                 8    t        j                  | |||||      S )a  Converts a sparse representation into a dense tensor.

  Builds an array `dense` with shape `output_shape` such that

  ```python
  # If sparse_indices is scalar
  dense[i] = (i == sparse_indices ? sparse_values : default_value)

  # If sparse_indices is a vector, then for each i
  dense[sparse_indices[i]] = sparse_values[i]

  # If sparse_indices is an n by d matrix, then for each i in [0, n)
  dense[sparse_indices[i][0], ..., sparse_indices[i][d-1]] = sparse_values[i]
  ```

  All other values in `dense` are set to `default_value`.  If `sparse_values`
  is a scalar, all sparse indices are set to this single value.

  Indices should be sorted in lexicographic order, and indices must not
  contain any repeats. If `validate_indices` is True, these properties
  are checked during execution.

  Args:
    sparse_indices: A 0-D, 1-D, or 2-D `Tensor` of type `int32` or `int64`.
      `sparse_indices[i]` contains the complete index where `sparse_values[i]`
      will be placed.
    output_shape: A 1-D `Tensor` of the same type as `sparse_indices`.  Shape
      of the dense output tensor.
    sparse_values: A 0-D or 1-D `Tensor`.  Values corresponding to each row of
      `sparse_indices`, or a scalar value to be used for all sparse indices.
    default_value: A 0-D `Tensor` of the same type as `sparse_values`.  Value
      to set for indices not specified in `sparse_indices`.  Defaults to zero.
    validate_indices: A boolean value.  If True, indices are checked to make
      sure they are sorted in lexicographic order and that there are no repeats.
    name: A name for the operation (optional).

  Returns:
    Dense `Tensor` of shape `output_shape`.  Has the same type as
    `sparse_values`.
  default_valuevalidate_indicesr4   )r   r  )sparse_indicesr   sparse_valuesr  r  r4   s         r&   r  r    s*    f 
	'	'!'
 r(   zsparse.reduce_maxc           	      x   |d}|rht        j                  | j                  | j                  | j                  t        j                  | |      ||      \  }}}t        j                  |||      S t        j                  | j                  | j                  | j                  t        j                  | |      ||      S )a
  Computes `tf.sparse.maximum` of elements across dimensions of a SparseTensor.

  This is the reduction operation for the elementwise `tf.sparse.maximum` op.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_max()`.  In particular, this Op also returns a dense `Tensor`
  if `output_is_sparse` is `False`, or a `SparseTensor` if `output_is_sparse`
  is `True`.

  Note: A gradient is not defined for this function, so it can't be used
  in training models that need gradient descent.

  Reduces `sp_input` along the dimensions given in `axis`.  Unless
  `keepdims` is true, the rank of the tensor is reduced by 1 for each entry in
  `axis`. If `keepdims` is true, the reduced dimensions are retained
  with length 1.

  If `axis` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  similar to the indexing rules in Python.

  The values not defined in `sp_input` don't participate in the reduce max,
  as opposed to be implicitly assumed 0 -- hence it can return negative values
  for sparse `axis`. But, in case there are no values in
  `axis`, it will reduce to 0. See second example below.

  For example:

    # 'x' represents [[1, ?, 2]
    #                 [?, 3, ?]]
    # where ? is implicitly-zero.

    >>> x = tf.sparse.SparseTensor([[0, 0], [0, 2], [1, 1]], [1, 2, 3], [2, 3])
    >>> tf.sparse.reduce_max(x)
    <tf.Tensor: shape=(), dtype=int32, numpy=3>
    >>> tf.sparse.reduce_max(x, 0)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 3, 2], dtype=int32)>
    >>> tf.sparse.reduce_max(x, 1)
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 3], dtype=int32)>
    >>> tf.sparse.reduce_max(x, 1, keepdims=True)
    <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
    array([[2],
           [3]], dtype=int32)>
    >>> tf.sparse.reduce_max(x, [0, 1])
    <tf.Tensor: shape=(), dtype=int32, numpy=3>

    # 'y' represents [[-7, ?]
    #                 [ 4, 3]
    #                 [ ?, ?]

    >>> y = tf.sparse.SparseTensor([[0, 0,], [1, 0], [1, 1]], [-7, 4, 3],
    ... [3, 2])
    >>> tf.sparse.reduce_max(y, 1)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([-7,  4,  0], dtype=int32)>

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    output_is_sparse: If true, returns a `SparseTensor` instead of a dense
      `Tensor` (the default).
    name: A name for the operation (optional).

  Returns:
    The reduced Tensor or the reduced SparseTensor if `output_is_sparse` is
    True.
  Frx   )
r   sparse_reduce_max_sparserH   rI   rV   r   _ReductionDimsr   r"   sparse_reduce_maxr%   rP   keepdimsoutput_is_sparser4   r   r   r   s           r&   sparse_reduce_max_v2r    s    N H//OO  ##Hd3	 )J
L %%j*lKK		)	)ooh-
 r(   r  z-keep_dims is deprecated, use keepdims instead	keep_dimsz.reduction_axes is deprecated, use axis insteadreduction_axesc           	          t        j                  d|d|      }t        j                  d|d|      }|d}t        j                  | j                  | j
                  | j                  t        j                  | |      |      S )a.
  Computes `tf.sparse.maximum` of elements across dimensions of a SparseTensor.

  This is the reduction operation for the elementwise `tf.sparse.maximum` op.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_max()`.  In particular, this Op also returns a dense `Tensor`
  instead of a sparse one.

  Note: A gradient is not defined for this function, so it can't be used
  in training models that need gradient descent.

  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
  `keepdims` is true, the rank of the tensor is reduced by 1 for each entry in
  `reduction_axes`. If `keepdims` is true, the reduced dimensions are retained
  with length 1.

  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  similar to the indexing rules in Python.

  The values not defined in `sp_input` don't participate in the reduce max,
  as opposed to be implicitly assumed 0 -- hence it can return negative values
  for sparse `reduction_axes`. But, in case there are no values in
  `reduction_axes`, it will reduce to 0. See second example below.

  For example:

    # 'x' represents [[1, ?, 2]
    #                 [?, 3, ?]]
    # where ? is implicitly-zero.

    >>> x = tf.sparse.SparseTensor([[0, 0], [0, 2], [1, 1]], [1, 2, 3], [2, 3])
    >>> tf.sparse.reduce_max(x)
    <tf.Tensor: shape=(), dtype=int32, numpy=3>
    >>> tf.sparse.reduce_max(x, 0)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 3, 2], dtype=int32)>
    >>> tf.sparse.reduce_max(x, 1)
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 3], dtype=int32)>
    >>> tf.sparse.reduce_max(x, 1, keepdims=True)
    <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
    array([[2],
           [3]], dtype=int32)>
    >>> tf.sparse.reduce_max(x, [0, 1])
    <tf.Tensor: shape=(), dtype=int32, numpy=3>

    # 'y' represents [[-7, ?]
    #                 [ 4, 3]
    #                 [ ?, ?]

    >>> y = tf.sparse.SparseTensor([[0, 0,], [1, 0], [1, 1]], [-7, 4, 3],
    ... [3, 2])
    >>> tf.sparse.reduce_max(y, 1)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([-7,  4,  0], dtype=int32)>

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    reduction_axes: Deprecated name of `axis`.
    keep_dims:  Deprecated alias for `keepdims`.

  Returns:
    The reduced Tensor.
  r  r  rP   r  F)	r   ru   r   r  rH   rI   rV   r   r  r%   rP   r  r  r  s        r&   r  r  =  s    T 33J4?L(		/	/>N0>
@$H		)	))=)=h-x
9 9r(   zsparse.reduce_max_sparser  c           	      6   t        j                  d|d|      }t        j                  d|d|      }|d}t        j                  | j                  | j
                  | j                  t        j                  | |      |      \  }}}t        j                  |||      S )a  Computes the max of elements across dimensions of a SparseTensor.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_max()`.  In contrast to SparseReduceSum, this Op returns a
  SparseTensor.

  Note: A gradient is not defined for this function, so it can't be used
  in training models that need gradient descent.

  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
  `keepdims` is true, the rank of the tensor is reduced by 1 for each entry in
  `reduction_axes`. If `keepdims` is true, the reduced dimensions are retained
  with length 1.

  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  which are interpreted according to the indexing rules in Python.

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    reduction_axes: Deprecated name of axis.
    keep_dims: Deprecated alias for `keepdims`.

  Returns:
    The reduced SparseTensor.
  r  r  rP   r  F)r   ru   r   r  rH   rI   rV   r   r  r   r"   r%   rP   r  r  r  r   r   r   s           r&   r  r        L 33J4?L(		/	/>N0>
@$H --


HOOX-A-A

!
!(D
18= '*j,
 
	#	#J
L	IIr(   zsparse.reduce_sumc           	      x   |d}|rht        j                  | j                  | j                  | j                  t        j                  | |      ||      \  }}}t        j                  |||      S t        j                  | j                  | j                  | j                  t        j                  | |      ||      S )a  Computes `tf.sparse.add` of elements across dimensions of a SparseTensor.

  This is the reduction operation for the elementwise `tf.sparse.add` op.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_sum()`.  In particular, this Op also returns a dense `Tensor`
  if `output_is_sparse` is `False`, or a `SparseTensor` if `output_is_sparse`
  is `True`.

  Note: if `output_is_sparse` is True, a gradient is not defined for this
  function, so it can't be used in training models that need gradient descent.

  Reduces `sp_input` along the dimensions given in `axis`.  Unless `keepdims` is
  true, the rank of the tensor is reduced by 1 for each entry in `axis`. If
  `keepdims` is true, the reduced dimensions are retained with length 1.

  If `axis` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  similar to the indexing rules in Python.

  For example:

    # 'x' represents [[1, ?, 1]
    #                 [?, 1, ?]]
    # where ? is implicitly-zero.

    >>> x = tf.sparse.SparseTensor([[0, 0], [0, 2], [1, 1]], [1, 1, 1], [2, 3])
    >>> tf.sparse.reduce_sum(x)
    <tf.Tensor: shape=(), dtype=int32, numpy=3>
    >>> tf.sparse.reduce_sum(x, 0)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 1, 1], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, 1)  # Can also use -1 as the axis
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 1], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, 1, keepdims=True)
    <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
    array([[2],
           [1]], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, [0, 1])
    <tf.Tensor: shape=(), dtype=int32, numpy=3>

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    output_is_sparse: If true, returns a `SparseTensor` instead of a dense
      `Tensor` (the default).
    name: A name for the operation (optional).

  Returns:
    The reduced Tensor or the reduced SparseTensor if `output_is_sparse` is
    True.
  Frx   )
r   sparse_reduce_sum_sparserH   rI   rV   r   r  r   r"   sparse_reduce_sumr  s           r&   sparse_reduce_sum_v2r(    s    p H//OO  ##Hd3	 )J
L %%j*lKK		)	)ooh-
 r(   r'  c           	          t        j                  d|d|      }t        j                  d|d|      }|d}t        j                  | j                  | j
                  | j                  t        j                  | |      |      S )a}  Computes `tf.sparse.add` of elements across dimensions of a SparseTensor.

  This is the reduction operation for the elementwise `tf.sparse.add` op.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_sum()`.  In particular, this Op also returns a dense `Tensor`
  instead of a sparse one.

  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
  `keepdims` is true, the rank of the tensor is reduced by 1 for each entry in
  `reduction_axes`. If `keepdims` is true, the reduced dimensions are retained
  with length 1.

  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  similar to the indexing rules in Python.

  For example:

    # 'x' represents [[1, ?, 1]
    #                 [?, 1, ?]]
    # where ? is implicitly-zero.

    >>> x = tf.sparse.SparseTensor([[0, 0], [0, 2], [1, 1]], [1, 1, 1], [2, 3])
    >>> tf.sparse.reduce_sum(x)
    <tf.Tensor: shape=(), dtype=int32, numpy=3>
    >>> tf.sparse.reduce_sum(x, 0)
    <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 1, 1], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, 1)  # Can also use -1 as the axis
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([2, 1], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, 1, keepdims=True)
    <tf.Tensor: shape=(2, 1), dtype=int32, numpy=
    array([[2],
           [1]], dtype=int32)>
    >>> tf.sparse.reduce_sum(x, [0, 1])
    <tf.Tensor: shape=(), dtype=int32, numpy=3>

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    reduction_axes: Deprecated name of `axis`.
    keep_dims: Deprecated alias for `keepdims`.

  Returns:
    The reduced Tensor.
  r  r  rP   r  F)	r   ru   r   r'  rH   rI   rV   r   r  r!  s        r&   r'  r'    s    r 33J4?L(		/	/>N0>
@$H		)	))=)=h-x
9 9r(   zsparse.reduce_sum_sparser&  c           	      6   t        j                  d|d|      }t        j                  d|d|      }|d}t        j                  | j                  | j
                  | j                  t        j                  | |      |      \  }}}t        j                  |||      S )a  Computes the sum of elements across dimensions of a SparseTensor.

  This Op takes a SparseTensor and is the sparse counterpart to
  `tf.reduce_sum()`.  In contrast to SparseReduceSum, this Op returns a
  SparseTensor.

  Note: A gradient is not defined for this function, so it can't be used
  in training models that need gradient descent.

  Reduces `sp_input` along the dimensions given in `reduction_axes`.  Unless
  `keepdims` is true, the rank of the tensor is reduced by 1 for each entry in
  `reduction_axes`. If `keepdims` is true, the reduced dimensions are retained
  with length 1.

  If `reduction_axes` has no entries, all dimensions are reduced, and a tensor
  with a single element is returned.  Additionally, the axes can be negative,
  which are interpreted according to the indexing rules in Python.

  Args:
    sp_input: The SparseTensor to reduce. Should have numeric type.
    axis: The dimensions to reduce; list or scalar. If `None` (the
      default), reduces all dimensions.
    keepdims: If true, retain reduced dimensions with length 1.
    reduction_axes: Deprecated name of axis.
    keep_dims: Deprecated alias for `keepdims`.

  Returns:
    The reduced SparseTensor.
  r  r  rP   r  F)r   ru   r   r&  rH   rI   rV   r   r  r   r"   r#  s           r&   r&  r&  \  r$  r(   zsparse.to_densesparse_tensor_to_densec                     t        |       } |!t        j                  g | j                        }t	        j
                  | j                  | j                  | j                  |||      S )a  Converts a `SparseTensor` into a dense tensor.

  For this sparse tensor with three non-empty values:

  >>> sp_input = tf.sparse.SparseTensor(
  ...   dense_shape=[3, 5],
  ...   values=[7, 8, 9],
  ...   indices =[[0, 1],
  ...             [0, 3],
  ...             [2, 0]])

  The output will be a dense `[3, 5]` tensor with values:

  >>> tf.sparse.to_dense(sp_input).numpy()
  array([[0, 7, 0, 8, 0],
         [0, 0, 0, 0, 0],
         [9, 0, 0, 0, 0]], dtype=int32)

  Note: Indices must be without repeats.  This is only tested if
  `validate_indices` is `True`.

  Args:
    sp_input: The input `SparseTensor`.
    default_value: Scalar value to set for indices not specified in
      `sp_input`.  Defaults to zero.
    validate_indices: A boolean value.  If `True`, indices are checked to make
      sure they are sorted in lexicographic order and that there are no repeats.
    name: A name prefix for the returned tensors (optional).

  Returns:
    A dense tensor with shape `sp_input.dense_shape` and values specified by
    the non-empty values in `sp_input`. Indices not in `sp_input` are assigned
    `default_value`.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  rR   r  )	r'   r   rY   r5   r   r  rH   rV   rI   )r%   r  r  r4   s       r&   r+  r+    s^    V 'x0(OOBhnn=M		'	'oo!'
 r(   zsparse.to_indicatorsparse_to_indicatorc                    t        |       } t        j                  |d| g      5 }t        j                  | j
                        d   }t        j                  t        j                  |d      d      }t        j                  | j
                  || j                        }t        | |||      }t        |dd|      cddd       S # 1 sw Y   yxY w)a  Converts a `SparseTensor` of ids into a dense bool indicator tensor.

  The last dimension of `sp_input.indices` is discarded and replaced with
  the values of `sp_input`.  If `sp_input.dense_shape = [D0, D1, ..., Dn, K]`,
  then `output.shape = [D0, D1, ..., Dn, vocab_size]`, where

      output[d_0, d_1, ..., d_n, sp_input[d_0, d_1, ..., d_n, k]] = True

  and False elsewhere in `output`.

  For example, if `sp_input.dense_shape = [2, 3, 4]` with non-empty values:

      [0, 0, 0]: 0
      [0, 1, 0]: 10
      [1, 0, 3]: 103
      [1, 1, 1]: 150
      [1, 1, 2]: 149
      [1, 1, 3]: 150
      [1, 2, 1]: 121

  and `vocab_size = 200`, then the output will be a `[2, 3, 200]` dense bool
  tensor with False everywhere except at positions

      (0, 0, 0), (0, 1, 10), (1, 0, 103), (1, 1, 149), (1, 1, 150),
      (1, 2, 121).

  Note that repeats are allowed in the input SparseTensor.
  This op is useful for converting `SparseTensor`s into dense formats for
  compatibility with ops that expect dense tensors.

  The input `SparseTensor` must be in row-major order.

  Args:
    sp_input: A `SparseTensor` with `values` property of type `int32` or
      `int64`.
    vocab_size: A scalar int64 Tensor (or Python int) containing the new size
      of the last dimension, `all(0 <= sp_input.values < vocab_size)`.
    name: A name prefix for the returned tensors (optional)

  Returns:
    A dense bool indicator tensor representing the indices with specified value.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  SparseToIndicatorr   TFr  N)r'   r   rB   r   rG   rH   fillrM   r   r"   rV   sparse_merge_implr+  )r%   
vocab_sizer4   num_entries
new_values	sp_valuessp_news          r&   r-  r-    s    b 'x0(
~~d/(< H//("2"23A6K	 5 5k1 EtLJ**8+;+;Z+3+?+?AI xJEF "ee$HH H Hs   BCCzsparse.mergesparse_mergez%No similar op available at this time.c                      t        | ||||      S )a  Combines a batch of feature ids and values into a single `SparseTensor`.

  The most common use case for this function occurs when feature ids and
  their corresponding values are stored in `Example` protos on disk.
  `parse_example` will return a batch of ids and a batch of values, and this
  function joins them into a single logical `SparseTensor` for use in
  functions such as `sparse_tensor_dense_matmul`, `sparse_to_dense`, etc.

  The `SparseTensor` returned by this function has the following properties:

    - `indices` is equivalent to `sp_ids.indices` with the last
      dimension discarded and replaced with `sp_ids.values`.
    - `values` is simply `sp_values.values`.
    - If `sp_ids.dense_shape = [D0, D1, ..., Dn, K]`, then
      `output.shape = [D0, D1, ..., Dn, vocab_size]`.

  For example, consider the following feature vectors:

  ```python
    vector1 = [-3, 0, 0, 0, 0, 0]
    vector2 = [ 0, 1, 0, 4, 1, 0]
    vector3 = [ 5, 0, 0, 9, 0, 0]
  ```

  These might be stored sparsely in the following Example protos by storing
  only the feature ids (column number if the vectors are treated as a matrix)
  of the non-zero elements and the corresponding values:

  ```python
    examples = [Example(features={
                    "ids": Feature(int64_list=Int64List(value=[0])),
                    "values": Feature(float_list=FloatList(value=[-3]))}),
                Example(features={
                    "ids": Feature(int64_list=Int64List(value=[1, 4, 3])),
                    "values": Feature(float_list=FloatList(value=[1, 1, 4]))}),
                Example(features={
                    "ids": Feature(int64_list=Int64List(value=[0, 3])),
                    "values": Feature(float_list=FloatList(value=[5, 9]))})]
  ```

  The result of calling parse_example on these examples will produce a
  dictionary with entries for "ids" and "values". Passing those two objects
  to this function along with vocab_size=6, will produce a `SparseTensor` that
  sparsely represents all three instances. Namely, the `indices` property will
  contain the coordinates of the non-zero entries in the feature matrix (the
  first dimension is the row number in the matrix, i.e., the index within the
  batch, and the second dimension is the column number, i.e., the feature id);
  `values` will contain the actual values. `shape` will be the shape of the
  original matrix, i.e., (3, 6). For our example above, the output will be
  equal to:

  ```python
    SparseTensor(indices=[[0, 0], [1, 1], [1, 3], [1, 4], [2, 0], [2, 3]],
                 values=[-3, 1, 4, 1, 5, 9],
                 dense_shape=[3, 6])
  ```

  This method generalizes to higher-dimensions by simply providing a list for
  both the sp_ids as well as the vocab_size.
  In this case the resulting `SparseTensor` has the following properties:
    - `indices` is equivalent to `sp_ids[0].indices` with the last
      dimension discarded and concatenated with
      `sp_ids[0].values, sp_ids[1].values, ...`.
    - `values` is simply `sp_values.values`.
    - If `sp_ids.dense_shape = [D0, D1, ..., Dn, K]`, then
      `output.shape = [D0, D1, ..., Dn] + vocab_size`.

  Args:
    sp_ids: A single `SparseTensor` with `values` property of type `int32`
      or `int64` or a Python list of such `SparseTensor`s or a list thereof.
    sp_values: A `SparseTensor` of any type.
    vocab_size: A scalar `int64` Tensor (or Python int) containing the new size
      of the last dimension, `all(0 <= sp_ids.values < vocab_size)`.
      Or a list thereof with `all(0 <= sp_ids[i].values < vocab_size[i])` for
      all `i`.
    name: A name prefix for the returned tensors (optional)
    already_sorted: A boolean to specify whether the per-batch values in
     `sp_values` are already sorted. If so skip sorting, False by default
     (optional).

  Returns:
    A `SparseTensor` compactly representing a batch of feature ids and values,
    useful for passing to functions that expect such a `SparseTensor`.

  Raises:
    TypeError: If `sp_values` is not a `SparseTensor`. Or if `sp_ids` is neither
      a `SparseTensor` nor a list thereof. Or if `vocab_size` is not a
      `Tensor` or a Python int and `sp_ids` is a `SparseTensor`. Or if
      `vocab_size` is not a or list thereof and `sp_ids` is a list.
    ValueError: If `sp_ids` and `vocab_size` are lists of different lengths.
  )r1  )sp_idsr5  r2  r4   already_sorteds        r&   r7  r7  
  s    ~ 
69j$	OOr(   c                 8   t        | t        j                        st        | t        j                        rR| g} t        |t        j
                        s1t        |t        j                        st        dt        |      z        |g}nt        | t        j                        st        dt        |       z        t        |t        j                        st        dt        |      z        |D ]N  }t        |t        j
                        rt        |t        j                        r9t        dt        |      z         t        |       t        |      k7  rt        d      t        j                  |d| |g      5  | D cg c]  }t!        |       } }t!        |      }g }| D ]j  }|j"                  }|j$                  t&        j(                  k7  r$t+        j,                  |t&        j(                        }|t/        j0                  |d      gz  }l |D 	cg c]&  }	t+        j,                  |	t&        j(                        ( }}	| d   j2                  d	d	d	d
f   }
t/        j4                  |
g|z   d      }|j"                  }t/        j4                  | d   j6                  d	d
 |gd      }t        j                  |||      }|r|cd	d	d	       S t9        |      }t        j                  |j2                  |j"                  |      cd	d	d	       S c c}w c c}	w # 1 sw Y   y	xY w)zGInternal implementation for sparse_merge to avoid deprecation warnings.z5vocab_size has to be a Tensor or Python int. Found %sz9sp_ids has to be a SparseTensor or list thereof. Found %sz?vocab_size has to be a list of Tensors or Python ints. Found %sz1sp_ids and vocab_size have to have equal lengths.SparseMergerQ   rS   r   NrL   )r    r   r!   r"   r9   r:   numbersIntegralr$   typer   Iterabler   r   r   rB   r'   rI   r5   r   r8   r   r<   r   rM   rH   r[   rV   r   )r9  r5  r2  r4   r:  r~   
sp_ids_dimidsids_dimxindices_columns_to_preservenew_indicesr4  rT   r   sorted_results                   r&   r1  r1  l  s    778Jm((=*XFz:#4#45z7#3#34M:&' ( (Jfo667 !#'<0 1 1j/":":; !#'
#34 5 5 
z  "%/W5E5E%FMI 	 	[C
O#
H
II
~~dMFI+>? @FLM
'
3MFM))4I
C 6
!!g			V\\	)--6	i##G!455c	6 ;EEQ(--6<<0EJE #))"3"3AssF";""$?#@3#FJK!!J  &)"7"7"<j!I1MI''ZKF+@ @, #6*M%%}33Y@/@ @M F@ @s2   7L<LBL+L;BL5L
LLzsparse.retainsparse_retainc                    t        |       } t        j                  |      }|j                         }|j	                  d       | j
                  j                         j                  J| j
                  j                         j                  d   j                  t        j                  |d             t        j                  t        j                  |      dg      }t        j                  | j                  |      }t        j                  | j
                  |      }t        j                   ||t        j"                  | j$                              S )a  Retains specified non-empty values within a `SparseTensor`.

  For example, if `sp_input` has shape `[4, 5]` and 4 non-empty string values:

      [0, 1]: a
      [0, 3]: b
      [2, 0]: c
      [3, 1]: d

  and `to_retain = [True, False, False, True]`, then the output will
  be a `SparseTensor` of shape `[4, 5]` with 2 non-empty values:

      [0, 1]: a
      [3, 1]: d

  Args:
    sp_input: The input `SparseTensor` with `N` non-empty elements.
    to_retain: A bool vector of length `N` with `M` true values.

  Returns:
    A `SparseTensor` with the same shape as the input and `M` non-empty
    elements corresponding to the true positions in `to_retain`.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  rQ   r   rL   )r'   r   r7   rW   assert_has_rankrI   dimsr   r
   r}   r   r   rC   gatherrH   r   r"   r   rV   )r%   	to_retainretain_shape
where_truerF  r4  s         r&   rH  rH    s   : 'x0(##I.) $$&,q!__ %%1OO$$Q'AA''a8:   !3!3I!>E*  !1!1:>+<*		#	#K$-$6$6x7K7K$L
N Nr(   zsparse.reset_shapesparse_reset_shapec           	         t        |       } t        j                  | j                        }t        j                  | j                        }t        j                  | j
                        }|yt        j                  |d      }t        j                  t        j                  dt        j                        t        j                  |t        j                  |                  }nt        j                  |      }|j!                         j#                  d       t        j$                  |t        j                        }|j!                         j&                  G|j!                         j(                  d   j+                  |j!                         j(                  d          t-        j.                  |      }||| j!                         j1                         r^t3        j4                  | j!                         j7                               }t3        j8                  ||k        st;        d|d|d      |}n|t=        j>                  tA        jB                  t        jD                  |      t        jD                  |            g|      }t=        j>                  tA        jF                  ||      g|      }tI        jJ                  |||      S )a	  Resets the shape of a `SparseTensor` with indices and values unchanged.

  If `new_shape` is None, returns a copy of `sp_input` with its shape reset
  to the tight bounding box of `sp_input`. This will be a shape consisting of
  all zeros if sp_input has no values.

  If `new_shape` is provided, then it must be larger or equal in all dimensions
  compared to the shape of `sp_input`. When this condition is met, the returned
  SparseTensor will have its shape reset to `new_shape` and its indices and
  values unchanged from that of `sp_input.`

  For example:

    Consider a `sp_input` with shape [2, 3, 5]:

      [0, 0, 1]: a
      [0, 1, 0]: b
      [0, 2, 2]: c
      [1, 0, 3]: d

    - It is an error to set `new_shape` as [3, 7] since this represents a
      rank-2 tensor while `sp_input` is rank-3. This is either a ValueError
      during graph construction (if both shapes are known) or an OpError during
      run time.

    - Setting `new_shape` as [2, 3, 6] will be fine as this shape is larger or
      equal in every dimension compared to the original shape [2, 3, 5].

    - On the other hand, setting new_shape as [2, 3, 4] is also an error: The
      third dimension is smaller than the original shape [2, 3, 5] (and an
      `InvalidArgumentError` will be raised).

    - If `new_shape` is None, the returned SparseTensor will have a shape
      [2, 3, 4], which is the tight bounding box of `sp_input`.

  Args:
    sp_input: The input `SparseTensor`.
    new_shape: None or a vector representing the new shape for the returned
      `SparseTensor`.

  Returns:
    A `SparseTensor` indices and values unchanged from `sp_input`. Its shape is
      `new_shape` if that is set. Otherwise it is the tight bounding box of
       `sp_input`

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
    ValueError: If `new_shape` represents a tensor with a different rank from
      that of `sp_input` (if shapes are known when graph is constructed).
    ValueError:  If `new_shape` is determined during graph build to have
      dimension sizes that are too small.
    OpError:
      - If `new_shape` has dimension sizes that are too small.
      - If shapes are not known during graph construction time, and during run
        time it is found out that the ranks do not match.
  r   rS   rR   rQ   zURequested new_shape should have dimension sizes >= sp_input.shape.  Found new_shape (z), sp_input.shape (z).)&r'   r   r   rH   rI   rV   r   r   maximumr   r   r8   add	ones_liker   r7   rW   rJ  r<   r\   rK  r   r   r   r   r   arrayr   r   r   r   with_dependenciesr   assert_equalrG   assert_less_equalr   r"   )	r%   rT   
in_indices	in_valuesin_shapedim_low_boundoutput_shape_tensoroutput_shape_tensor_constin_shape_consts	            r&   rP  rP    s@   x 'x0(!!("2"23*  1) 4 45(''
;M"**1FLL1]I$7$7$ABD //	:!!#33A6"--(;V\\J $$&++7##%**1-GG




#
#A
&( !, : :;N O!---/xx 2 2 4 < < >?nVVN&??@ 689 	9 6 ->>

 
 ooh'9L)MO@ 
 ->>&&x1DE
F
 
	#	#J	;N	OOr(   zsparse.fill_empty_rowssparse_fill_empty_rowsc                    t        |       } t        j                  |d| g      5  t        j                  || j                  j
                        }t        j                  | j                  | j                  | j                  |      \  }}}}t        j                  ||| j                        |fcddd       S # 1 sw Y   yxY w)af  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`.
  SparseFillEmptyRowsrR   )rH   rI   rV   r  rU   N)r'   r   rB   r7   rI   r5   r   r`  rH   rV   r   r"   )r%   r  r4   r  r  empty_row_indicatorunused_reverse_index_maps          r&   r`  r`  =  s    f 'x0(
~~d1H:> @))X__224M "0!F!F!!))$	"&^]$7
 &&((* ,?@@ @ @s   BB99Czio.serialize_sparseserialize_sparsec                     t        | ||      S )a  Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object.

  Args:
    sp_input: The input `SparseTensor`.
    name: A name prefix for the returned tensors (optional).
    out_type: The `dtype` to use for serialization.

  Returns:
    A 3-vector (1-D `Tensor`), with each column representing the serialized
    `SparseTensor`'s indices, values, and shape (respectively).

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  )serialize_sparse_v2r%   r4   rA   s      r&   re  re    s    $ 
Xx	66r(   c                     t        |       } t        j                  | j                  | j                  | j
                  ||      S )a  Serialize a `SparseTensor` into a 3-vector (1-D `Tensor`) object.

  Args:
    sp_input: The input `SparseTensor`.
    out_type: The `dtype` to use for serialization.
    name: A name prefix for the returned tensors (optional).

  Returns:
    A 3-vector (1-D `Tensor`), with each column representing the serialized
    `SparseTensor`'s indices, values, and shape (respectively).

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  r4   rA   )r'   r   re  rH   rI   rV   r%   rA   r4   s      r&   rg  rg    s@    " 'x0(		(	(oo
 r(   zio.serialize_many_sparseserialize_many_sparsec                     t        | ||      S )a`  Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`.

  The `SparseTensor` must have rank `R` greater than 1, and the first dimension
  is treated as the minibatch dimension.  Elements of the `SparseTensor`
  must be sorted in increasing order of this first dimension.  The serialized
  `SparseTensor` objects going into each row of the output `Tensor` will have
  rank `R-1`.

  The minibatch size `N` is extracted from `sparse_shape[0]`.

  Args:
    sp_input: The input rank `R` `SparseTensor`.
    name: A name prefix for the returned tensors (optional).
    out_type: The `dtype` to use for serialization.

  Returns:
    A matrix (2-D `Tensor`) with `N` rows and `3` columns. Each column
    represents serialized `SparseTensor`'s indices, values, and shape
    (respectively).

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  )serialize_many_sparse_v2rh  s      r&   rl  rl    s    6 
"(Hd	;;r(   c                     t        |       } t        j                  | j                  | j                  | j
                  ||      S )a`  Serialize `N`-minibatch `SparseTensor` into an `[N, 3]` `Tensor`.

  The `SparseTensor` must have rank `R` greater than 1, and the first dimension
  is treated as the minibatch dimension.  Elements of the `SparseTensor`
  must be sorted in increasing order of this first dimension.  The serialized
  `SparseTensor` objects going into each row of the output `Tensor` will have
  rank `R-1`.

  The minibatch size `N` is extracted from `sparse_shape[0]`.

  Args:
    sp_input: The input rank `R` `SparseTensor`.
    out_type: The `dtype` to use for serialization.
    name: A name prefix for the returned tensors (optional).

  Returns:
    A matrix (2-D `Tensor`) with `N` rows and `3` columns. Each column
    represents serialized `SparseTensor`'s indices, values, and shape
    (respectively).

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  rj  )r'   r   rl  rH   rI   rV   rk  s      r&   rn  rn    s@    4 'x0(		-	-oo
 r(   c                     t        j                  | ||      \  }}}|j                  d|g       |j                  |g       t        j                  |||      S )a9  Deserialize `SparseTensor` objects.

  The input `serialized_sparse` must have the shape `[?, ?, ..., ?, 3]` where
  the last dimension stores serialized `SparseTensor` objects and the other N
  dimensions (N >= 0) correspond to a batch. The ranks of the original
  `SparseTensor` objects must all match. When the final `SparseTensor` is
  created, its rank is the rank of the incoming `SparseTensor` objects plus N;
  the sparse tensors have been concatenated along new dimensions, one for each
  batch.

  The output `SparseTensor` object's shape values for the original dimensions
  are the max across the input `SparseTensor` objects' shape values for the
  corresponding dimensions. The new dimensions match the size of the batch.

  The input `SparseTensor` objects' indices are assumed ordered in
  standard lexicographic order.  If this is not the case, after this
  step run `SparseReorder` to restore index ordering.

  For example, if the serialized input is a `[2 x 3]` matrix representing two
  original `SparseTensor` objects:

      index = [ 0]
              [10]
              [20]
      values = [1, 2, 3]
      shape = [50]

  and

      index = [ 2]
              [10]
      values = [4, 5]
      shape = [30]

  then the final deserialized `SparseTensor` will be:

      index = [0  0]
              [0 10]
              [0 20]
              [1  2]
              [1 10]
      values = [1, 2, 3, 4, 5]
      shape = [2 50]

  Args:
    serialized_sparse: The serialized `SparseTensor` objects.
      The last dimension must have 3 columns.
    dtype: The `dtype` of the serialized `SparseTensor` objects.
    rank: (optional) Python int, the rank of the `SparseTensor` objects.
    name: A name prefix for the returned tensors (optional).

  Returns:
    A `SparseTensor` representing the deserialized `SparseTensor` objects.

  rx   N)r   deserialize_sparser   r   r"   serialized_sparser5   r\   r4   r  r  r   s          r&   rq  rq    s\    r ''(95tL ..- D$<($ 		#	#NM<	PPr(   zio.deserialize_many_sparsedeserialize_many_sparsec                     t        j                  | ||      \  }}}|j                  d|g       |j                  |g       t        j                  |||      S )a  Deserialize and concatenate `SparseTensors` from a serialized minibatch.

  The input `serialized_sparse` must be a string matrix of shape `[N x 3]` where
  `N` is the minibatch size and the rows correspond to packed outputs of
  `serialize_sparse`.  The ranks of the original `SparseTensor` objects
  must all match.  When the final `SparseTensor` is created, it has rank one
  higher than the ranks of the incoming `SparseTensor` objects (they have been
  concatenated along a new row dimension).

  The output `SparseTensor` object's shape values for all dimensions but the
  first are the max across the input `SparseTensor` objects' shape values
  for the corresponding dimensions.  Its first shape value is `N`, the minibatch
  size.

  The input `SparseTensor` objects' indices are assumed ordered in
  standard lexicographic order.  If this is not the case, after this
  step run `sparse.reorder` to restore index ordering.

  For example, if the serialized input is a `[2, 3]` matrix representing two
  original `SparseTensor` objects:

      index = [ 0]
              [10]
              [20]
      values = [1, 2, 3]
      shape = [50]

  and

      index = [ 2]
              [10]
      values = [4, 5]
      shape = [30]

  then the final deserialized `SparseTensor` will be:

      index = [0  0]
              [0 10]
              [0 20]
              [1  2]
              [1 10]
      values = [1, 2, 3, 4, 5]
      shape = [2 50]

  Args:
    serialized_sparse: 2-D `Tensor` of type `string` of shape `[N, 3]`.
      The serialized and packed `SparseTensor` objects.
    dtype: The `dtype` of the serialized `SparseTensor` objects.
    rank: (optional) Python int, the rank of the `SparseTensor` objects.
    name: A name prefix for the returned tensors (optional)

  Returns:
    A `SparseTensor` representing the deserialized `SparseTensor`s,
    concatenated along the `SparseTensor`s' first dimension.

    All of the serialized `SparseTensor`s must have had the same rank and type.
  rx   N)r   rt  r   r   r"   rr  s          r&   rt  rt  4	  s^    @ ,,
U/ ..-
 D$<($ 		#	#NM<	PPr(   sparse.sparse_dense_matmul)rv  zsparse.matmulsparse_tensor_dense_matmulrw  c           	      <   t        |t        j                        st        |t        j                        rJ||k7  r!t	        j
                  t        || ||            S t	        j
                  t        || | |             S t        |       } t        j                  |d| j                  | j                  |g      5 }t        j                  |d      }t        j                  | j                  | j                  | j                  |||      cddd       S # 1 sw Y   yxY w)ai(  Multiply SparseTensor (or dense Matrix) (of rank 2) "A" by dense matrix

  (or SparseTensor) "B". Please note that one and only one of the inputs MUST
  be a SparseTensor and the other MUST be a dense matrix.

  The following input format is recommended (but not required) for optimal
  performance:

  * If `adjoint_a == false`: `A` should be sorted in lexicographically
    increasing order.  Use `sparse.reorder` if you're not sure.
  * If `adjoint_a == true`: `A` should be sorted in order of increasing
    dimension 1 (i.e., "column major" order instead of "row major" order).

  Args:
    sp_a: SparseTensor (or dense Matrix) A, of rank 2.
    b: dense Matrix (or SparseTensor) B, with the same dtype as sp_a.
    adjoint_a: Use the adjoint of A in the matrix multiply.  If A is complex,
      this is transpose(conj(A)).  Otherwise it's transpose(A).
    adjoint_b: Use the adjoint of B in the matrix multiply.  If B is complex,
      this is transpose(conj(B)).  Otherwise it's transpose(B).
    name: A name prefix for the returned tensors (optional)

  Returns:
    A dense matrix (pseudo-code in dense np.matrix notation):
      `A = A.H if adjoint_a else A`
      `B = B.H if adjoint_b else B`
      `return A*B`

  Notes:

  Using `tf.nn.embedding_lookup_sparse` for sparse multiplication:

  It's not obvious but you can consider `embedding_lookup_sparse` as another
  sparse and dense multiplication. In some situations, you may prefer to use
  `embedding_lookup_sparse` even though you're not dealing with embeddings.

  There are two questions to ask in the decision process: Do you need gradients
  computed as sparse too? Is your sparse data represented as two
  `SparseTensor`s: ids and values? There is more explanation about data format
  below. If you answer any of these questions as yes, consider using
  `tf.nn.embedding_lookup_sparse`.

  Following explains differences between the expected SparseTensors:
  For example if dense form of your sparse data has shape `[3, 5]` and values:

      [[  a      ]
       [b       c]
       [    d    ]]


  `SparseTensor` format expected by `sparse_tensor_dense_matmul`:
   `sp_a` (indices, values):

      [0, 1]: a
      [1, 0]: b
      [1, 4]: c
      [2, 2]: d

  `SparseTensor` format expected by `embedding_lookup_sparse`:
   `sp_ids`                 `sp_weights`

      [0, 0]: 1                [0, 0]: a
      [1, 0]: 0                [1, 0]: b
      [1, 1]: 4                [1, 1]: c
      [2, 0]: 2                [2, 0]: d


  Deciding when to use `sparse_tensor_dense_matmul` vs.
  `matmul`(a_is_sparse=True):

  There are a number of questions to ask in the decision process, including:

  * Will the SparseTensor `A` fit in memory if densified?
  * Is the column count of the product large (>> 1)?
  * Is the density of `A` larger than approximately 15%?

  If the answer to several of these questions is yes, consider
  converting the `SparseTensor` to a dense one and using `tf.matmul` with
  `a_is_sparse=True`.

  This operation tends to perform well when `A` is more sparse, if the column
  size of the product is small (e.g. matrix-vector multiplication), if
  `sp_a.dense_shape` takes on large values.

  Below is a rough speed comparison between `sparse_tensor_dense_matmul`,
  labeled 'sparse', and `matmul`(a_is_sparse=True), labeled 'dense'.  For
  purposes of the comparison, the time spent converting from a `SparseTensor` to
  a dense `Tensor` is not included, so it is overly conservative with respect to
  the time ratio.

  Benchmark system:
  CPU: Intel Ivybridge with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:12MB
  GPU: NVidia Tesla k40c

  Compiled with:
  `-c opt --config=cuda --copt=-mavx`

  ```
  tensorflow/python/sparse_tensor_dense_matmul_op_test --benchmarks
  A sparse [m, k] with % nonzero values between 1% and 80%
  B dense [k, n]

  % nnz  n   gpu   m     k     dt(dense)     dt(sparse)   dt(sparse)/dt(dense)
  0.01   1   True  100   100   0.000221166   0.00010154   0.459112
  0.01   1   True  100   1000  0.00033858    0.000109275  0.322745
  0.01   1   True  1000  100   0.000310557   9.85661e-05  0.317385
  0.01   1   True  1000  1000  0.0008721     0.000100875  0.115669
  0.01   1   False 100   100   0.000208085   0.000107603  0.51711
  0.01   1   False 100   1000  0.000327112   9.51118e-05  0.290762
  0.01   1   False 1000  100   0.000308222   0.00010345   0.335635
  0.01   1   False 1000  1000  0.000865721   0.000101397  0.117124
  0.01   10  True  100   100   0.000218522   0.000105537  0.482958
  0.01   10  True  100   1000  0.000340882   0.000111641  0.327506
  0.01   10  True  1000  100   0.000315472   0.000117376  0.372064
  0.01   10  True  1000  1000  0.000905493   0.000123263  0.136128
  0.01   10  False 100   100   0.000221529   9.82571e-05  0.44354
  0.01   10  False 100   1000  0.000330552   0.000112615  0.340687
  0.01   10  False 1000  100   0.000341277   0.000114097  0.334324
  0.01   10  False 1000  1000  0.000819944   0.000120982  0.147549
  0.01   25  True  100   100   0.000207806   0.000105977  0.509981
  0.01   25  True  100   1000  0.000322879   0.00012921   0.400181
  0.01   25  True  1000  100   0.00038262    0.00014158   0.370035
  0.01   25  True  1000  1000  0.000865438   0.000202083  0.233504
  0.01   25  False 100   100   0.000209401   0.000104696  0.499979
  0.01   25  False 100   1000  0.000321161   0.000130737  0.407076
  0.01   25  False 1000  100   0.000377012   0.000136801  0.362856
  0.01   25  False 1000  1000  0.000861125   0.00020272   0.235413
  0.2    1   True  100   100   0.000206952   9.69219e-05  0.46833
  0.2    1   True  100   1000  0.000348674   0.000147475  0.422959
  0.2    1   True  1000  100   0.000336908   0.00010122   0.300439
  0.2    1   True  1000  1000  0.001022      0.000203274  0.198898
  0.2    1   False 100   100   0.000207532   9.5412e-05   0.459746
  0.2    1   False 100   1000  0.000356127   0.000146824  0.41228
  0.2    1   False 1000  100   0.000322664   0.000100918  0.312764
  0.2    1   False 1000  1000  0.000998987   0.000203442  0.203648
  0.2    10  True  100   100   0.000211692   0.000109903  0.519165
  0.2    10  True  100   1000  0.000372819   0.000164321  0.440753
  0.2    10  True  1000  100   0.000338651   0.000144806  0.427596
  0.2    10  True  1000  1000  0.00108312    0.000758876  0.70064
  0.2    10  False 100   100   0.000215727   0.000110502  0.512231
  0.2    10  False 100   1000  0.000375419   0.0001613    0.429653
  0.2    10  False 1000  100   0.000336999   0.000145628  0.432132
  0.2    10  False 1000  1000  0.00110502    0.000762043  0.689618
  0.2    25  True  100   100   0.000218705   0.000129913  0.594009
  0.2    25  True  100   1000  0.000394794   0.00029428   0.745402
  0.2    25  True  1000  100   0.000404483   0.0002693    0.665788
  0.2    25  True  1000  1000  0.0012002     0.00194494   1.62052
  0.2    25  False 100   100   0.000221494   0.0001306    0.589632
  0.2    25  False 100   1000  0.000396436   0.000297204  0.74969
  0.2    25  False 1000  100   0.000409346   0.000270068  0.659754
  0.2    25  False 1000  1000  0.00121051    0.00193737   1.60046
  0.5    1   True  100   100   0.000214981   9.82111e-05  0.456836
  0.5    1   True  100   1000  0.000415328   0.000223073  0.537101
  0.5    1   True  1000  100   0.000358324   0.00011269   0.314492
  0.5    1   True  1000  1000  0.00137612    0.000437401  0.317851
  0.5    1   False 100   100   0.000224196   0.000101423  0.452386
  0.5    1   False 100   1000  0.000400987   0.000223286  0.556841
  0.5    1   False 1000  100   0.000368825   0.00011224   0.304318
  0.5    1   False 1000  1000  0.00136036    0.000429369  0.31563
  0.5    10  True  100   100   0.000222125   0.000112308  0.505608
  0.5    10  True  100   1000  0.000461088   0.00032357   0.701753
  0.5    10  True  1000  100   0.000394624   0.000225497  0.571422
  0.5    10  True  1000  1000  0.00158027    0.00190898   1.20801
  0.5    10  False 100   100   0.000232083   0.000114978  0.495418
  0.5    10  False 100   1000  0.000454574   0.000324632  0.714146
  0.5    10  False 1000  100   0.000379097   0.000227768  0.600817
  0.5    10  False 1000  1000  0.00160292    0.00190168   1.18638
  0.5    25  True  100   100   0.00023429    0.000151703  0.647501
  0.5    25  True  100   1000  0.000497462   0.000598873  1.20386
  0.5    25  True  1000  100   0.000460778   0.000557038  1.20891
  0.5    25  True  1000  1000  0.00170036    0.00467336   2.74845
  0.5    25  False 100   100   0.000228981   0.000155334  0.678371
  0.5    25  False 100   1000  0.000496139   0.000620789  1.25124
  0.5    25  False 1000  100   0.00045473    0.000551528  1.21287
  0.5    25  False 1000  1000  0.00171793    0.00467152   2.71927
  0.8    1   True  100   100   0.000222037   0.000105301  0.47425
  0.8    1   True  100   1000  0.000410804   0.000329327  0.801664
  0.8    1   True  1000  100   0.000349735   0.000131225  0.375212
  0.8    1   True  1000  1000  0.00139219    0.000677065  0.48633
  0.8    1   False 100   100   0.000214079   0.000107486  0.502085
  0.8    1   False 100   1000  0.000413746   0.000323244  0.781261
  0.8    1   False 1000  100   0.000348983   0.000131983  0.378193
  0.8    1   False 1000  1000  0.00136296    0.000685325  0.50282
  0.8    10  True  100   100   0.000229159   0.00011825   0.516017
  0.8    10  True  100   1000  0.000498845   0.000532618  1.0677
  0.8    10  True  1000  100   0.000383126   0.00029935   0.781336
  0.8    10  True  1000  1000  0.00162866    0.00307312   1.88689
  0.8    10  False 100   100   0.000230783   0.000124958  0.541452
  0.8    10  False 100   1000  0.000493393   0.000550654  1.11606
  0.8    10  False 1000  100   0.000377167   0.000298581  0.791642
  0.8    10  False 1000  1000  0.00165795    0.00305103   1.84024
  0.8    25  True  100   100   0.000233496   0.000175241  0.75051
  0.8    25  True  100   1000  0.00055654    0.00102658   1.84458
  0.8    25  True  1000  100   0.000463814   0.000783267  1.68875
  0.8    25  True  1000  1000  0.00186905    0.00755344   4.04132
  0.8    25  False 100   100   0.000240243   0.000175047  0.728625
  0.8    25  False 100   1000  0.000578102   0.00104499   1.80763
  0.8    25  False 1000  100   0.000485113   0.000776849  1.60138
  0.8    25  False 1000  1000  0.00211448    0.00752736   3.55992
  ```

  )	adjoint_a	adjoint_bSparseTensorDenseMatMulr   rx   )	a_indicesa_valuesa_shaper   ry  rz  N)r    r   r"   r!   r   	transposerw  r'   r   rB   rH   rI   r7   r   sparse_tensor_dense_mat_mulrV   )sp_ar   ry  rz  r4   s        r&   rw  rw  ~	  s   l =--.=::; I  
$Qi
CE E   
$Yi-IJ J
 %T*D	7t{{A6
8 	;?



,a77LL;;""	 	 	s   8ADDzsparse.softmaxsparse_softmaxc                 H   t        j                  |d| j                  | j                  g      5 }t	        j
                  | j                  | j                  | j                        }t        j                  | j                  || j                        cddd       S # 1 sw Y   yxY w)a  Applies softmax to a batched N-D `SparseTensor`.

  The inputs represent an N-D SparseTensor with logical shape `[..., B, C]`
  (where `N >= 2`), and with indices sorted in the canonical lexicographic
  order.

  This op is equivalent to applying the normal `tf.nn.softmax()` to each
  innermost logical submatrix with shape `[B, C]`, but with the catch that *the
  implicitly zero elements do not participate*.  Specifically, the algorithm is
  equivalent to:

    (1) Applies `tf.nn.softmax()` to a densified view of each innermost
        submatrix with shape `[B, C]`, along the size-C dimension;
    (2) Masks out the original implicitly-zero locations;
    (3) Renormalizes the remaining elements.

  Hence, the `SparseTensor` result has exactly the same non-zero indices and
  shape.

  Example using a 3-D SparseTensor:

    >>> st = tf.sparse.from_dense(
    ...   [[[0., np.e],
    ...     [1., 0.]],
    ...
    ...    [[np.e, 0.],
    ...     [np.e, np.e]]])
    >>> res = tf.sparse.softmax(st)
    >>> res.indices
    <tf.Tensor: shape=(5, 3), dtype=int64, numpy=
    array([[0, 0, 1],
           [0, 1, 0],
           [1, 0, 0],
           [1, 1, 0],
           [1, 1, 1]])>
    >>> res.values
    <tf.Tensor: ... numpy=array([1. , 1. , 1. , 0.5, 0.5], dtype=float32)>
    >>> res.dense_shape
    <tf.Tensor: shape=(3,), dtype=int64, numpy=array([2, 2, 2])>
    >>> tf.sparse.to_dense(res)
    <tf.Tensor: shape=(2, 2, 2), dtype=float32, numpy=
    array([[[0. , 1. ],
            [1. , 0. ]],
           [[1. , 0. ],
            [0.5, 0.5]]], dtype=float32)>

  Args:
    sp_input: N-D `SparseTensor`, where `N >= 2`.
    name: optional name of the operation.
  Returns:
    output: N-D `SparseTensor` representing the results.
  SparseSoftmaxN)	r   rB   rH   rI   r   r  rV   r   r"   )r%   r4   out_valss      r&   r  r  o
  s    n ~~dO''9; <>B,,X-=-=x-5-A-ACH%%h&6&6&.&:&:<	< < <s   A BB!zsparse.maximumsparse_maximumc           
         t        j                  |d| j                  | j                  |j                  |j                  g      5 }t	        j
                  | j                  | j                  | j                  |j                  |j                  |j                  |      \  }}ddd       t        j                  | j                        S # 1 sw Y   *xY w)a  Returns the element-wise max of two SparseTensors.

  Assumes the two SparseTensors have the same shape, i.e., no broadcasting.

  Example:

    >>> sp_zero = tf.sparse.SparseTensor([[0]], [0], [7])
    >>> sp_one = tf.sparse.SparseTensor([[1]], [1], [7])
    >>> res = tf.sparse.maximum(sp_zero, sp_one)
    >>> res.indices
    <tf.Tensor: shape=(2, 1), dtype=int64, numpy=
    array([[0],
           [1]])>
    >>> res.values
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([0, 1], dtype=int32)>
    >>> res.dense_shape
    <tf.Tensor: shape=(1,), dtype=int64, numpy=array([7])>

  The reduction version of this elementwise operation is `tf.sparse.reduce_max`

  Args:
    sp_a: a `SparseTensor` operand whose dtype is real, and indices
      lexicographically ordered.
    sp_b: the other `SparseTensor` operand with the same requirements (and the
      same shape).
    name: optional name of the operation.
  Returns:
    output: the output SparseTensor.
  SparseSparseMaximumrx   N)	r   rB   rH   rI   r   sparse_sparse_maximumrV   r   r"   r  sp_br4   out_indices
out_valuess        r&   r  r  
  s    @ ~~
!||T[[$,,<> 
AE,BBK
 
	#	#KT=M=M	NN
 
   AC		Czsparse.minimumsparse_minimumc           
         t        j                  |d| j                  | j                  |j                  |j                  g      5 }t	        j
                  | j                  | j                  | j                  |j                  |j                  |j                  |      \  }}ddd       t        j                  | j                        S # 1 sw Y   *xY w)av  Returns the element-wise min of two SparseTensors.

  Assumes the two SparseTensors have the same shape, i.e., no broadcasting.

  Example:

    >>> sp_zero = tf.sparse.SparseTensor([[0]], [0], [7])
    >>> sp_one = tf.sparse.SparseTensor([[1]], [1], [7])
    >>> res = tf.sparse.minimum(sp_zero, sp_one)
    >>> res.indices
    <tf.Tensor: shape=(2, 1), dtype=int64, numpy=
    array([[0],
           [1]])>
    >>> res.values
    <tf.Tensor: shape=(2,), dtype=int32, numpy=array([0, 0], dtype=int32)>
    >>> res.dense_shape
    <tf.Tensor: shape=(1,), dtype=int64, numpy=array([7])>

  Args:
    sp_a: a `SparseTensor` operand whose dtype is real, and indices
      lexicographically ordered.
    sp_b: the other `SparseTensor` operand with the same requirements (and the
      same shape).
    name: optional name of the operation.
  Returns:
    output: the output SparseTensor.
  SparseSparseMinimumrx   N)	r   rB   rH   rI   r   sparse_sparse_minimumrV   r   r"   r  s        r&   r  r  
  s    < ~~
!||T[[$,,<> 
AE,BBK
 
	#	#KT=M=M	NN
 
r  zsparse.transposesparse_transposec                    t        j                  |d| g      5 }||| j                  j                  4| j                  j                  }|dz
  t	        j
                  d|d      z
  }n2t        j                  |       }|dz
  t        j                  d|d      z
  }| j                  }t        j                  t        j                  t        j                  |      |            }t        j                  t        j                  |            }|c| j                         j!                         rE| j                         j#                         }t%        |      }t'        |      D ]  \  }	}
||
   ||	<    n"| j(                  }t        j                  ||      }t+        j,                  || j.                  |      }t1        |      }|cddd       S # 1 sw Y   yxY w)a
  Transposes a `SparseTensor`.

  Permutes the dimensions according to the value of `perm`.  This is the sparse
  version of `tf.transpose`.

  The returned tensor's dimension `i` will correspond to the input dimension
  `perm[i]`. If `perm` is not given, it is set to (n-1...0), where n is the rank
  of the input tensor. Hence, by default, this operation performs a regular
  matrix transpose on 2-D input Tensors.

  For example:

  >>> x = tf.SparseTensor(indices=[[0, 1], [0, 3], [2, 3], [3, 1]],
  ...                     values=[1.1, 2.2, 3.3, 4.4],
  ...                     dense_shape=[4, 5])
  >>> print('x =', tf.sparse.to_dense(x))
  x = tf.Tensor(
  [[0.  1.1 0.  2.2 0. ]
  [0.  0.  0.  0.  0. ]
  [0.  0.  0.  3.3 0. ]
  [0.  4.4 0.  0.  0. ]], shape=(4, 5), dtype=float32)

  >>> x_transpose = tf.sparse.transpose(x)
  >>> print('x_transpose =', tf.sparse.to_dense(x_transpose))
  x_transpose = tf.Tensor(
  [[0.  0.  0.  0. ]
  [1.1 0.  0.  4.4]
  [0.  0.  0.  0. ]
  [2.2 0.  3.3 0. ]
  [0.  0.  0.  0. ]], shape=(5, 4), dtype=float32)

  Equivalently, you could call `tf.sparse.transpose(x, perm=[1, 0])`.  The
  `perm` argument is more useful for n-dimensional tensors where n > 2.

  >>> x = tf.SparseTensor(indices=[[0, 0, 1], [0, 0, 3], [1, 2, 3], [1, 3, 1]],
  ...                     values=[1.1, 2.2, 3.3, 4.4],
  ...                     dense_shape=[2, 4, 5])
  >>> print('x =', tf.sparse.to_dense(x))
  x = tf.Tensor(
  [[[0.  1.1 0.  2.2 0. ]
    [0.  0.  0.  0.  0. ]
    [0.  0.  0.  0.  0. ]
    [0.  0.  0.  0.  0. ]]
  [[0.  0.  0.  0.  0. ]
    [0.  0.  0.  0.  0. ]
    [0.  0.  0.  3.3 0. ]
    [0.  4.4 0.  0.  0. ]]], shape=(2, 4, 5), dtype=float32)

  As above, simply calling `tf.sparse.transpose` will default to `perm=[2,1,0]`.

  To take the transpose of a batch of sparse matrices, where 0 is the batch
  dimension, you would set `perm=[0,2,1]`.

  >>> x_transpose = tf.sparse.transpose(x, perm=[0, 2, 1])
  >>> print('x_transpose =', tf.sparse.to_dense(x_transpose))
  x_transpose = tf.Tensor(
  [[[0.  0.  0.  0. ]
    [1.1 0.  0.  0. ]
    [0.  0.  0.  0. ]
    [2.2 0.  0.  0. ]
    [0.  0.  0.  0. ]]
  [[0.  0.  0.  0. ]
    [0.  0.  0.  4.4]
    [0.  0.  0.  0. ]
    [0.  0.  3.3 0. ]
    [0.  0.  0.  0. ]]], shape=(2, 5, 4), dtype=float32)

  Args:
    sp_input: The input `SparseTensor`.
    perm: A permutation vector of the dimensions of `sp_input`.
    name: A name prefix for the returned tensors (optional).

  Returns:
    A transposed `SparseTensor`.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  SparseTransposeNrQ   r   )r   rB   rG   r\   r   aranger   r   ri   rH   r  rL  r   r   r7   rW   r   r   r.   	enumeraterV   r   r"   rI   r   )r%   permr4   r\   rH   transposed_indicesperm_
old_shape_transposed_dense_shaper   prV   transposed_sts                r&   r  r    s   b ~~d-z: d|				(~~""qBIIaq11~~h'qHNN1dA66G",,,,W5t<> &&s'<'<T'BCEX//1BBD%%'//1j#J/E" 2$!Q$.qMq!2 ((k(//TB!..HOO-CEM"=1M1  s   F#GGzsparse.map_valuesc           	      &   g }t        ||      }t        ||      }|st        d      t        j                  t	        |            5  t        j                  |d   j                   | |i ||d   j                        cddd       S # 1 sw Y   yxY w)a>  Applies `op` to the `.values` tensor of one or more `SparseTensor`s.

  Replaces any `SparseTensor` in `args` or `kwargs` with its `values`
  tensor (which contains the non-default values for the SparseTensor),
  and then calls `op`.  Returns a `SparseTensor` that is constructed
  from the input `SparseTensor`s' `indices`, `dense_shape`, and the
  value returned by the `op`.

  If the input arguments contain multiple `SparseTensor`s, then they must have
  equal `indices` and dense shapes.

  Examples:

  >>> s = tf.sparse.from_dense([[1, 2, 0],
  ...                           [0, 4, 0],
  ...                           [1, 0, 0]])
  >>> tf.sparse.to_dense(tf.sparse.map_values(tf.ones_like, s)).numpy()
  array([[1, 1, 0],
         [0, 1, 0],
         [1, 0, 0]], dtype=int32)

  >>> tf.sparse.to_dense(tf.sparse.map_values(tf.multiply, s, s)).numpy()
  array([[ 1,  4,  0],
         [ 0, 16,  0],
         [ 1,  0,  0]], dtype=int32)

  >>> tf.sparse.to_dense(tf.sparse.map_values(tf.add, s, 5)).numpy()
  array([[6, 7, 0],
         [0, 9, 0],
         [6, 0, 0]], dtype=int32)

  Note: even though `tf.add(0, 5) != 0`, implicit zeros
  will remain unchanged. However, if the sparse tensor contains any explicit
  zeros, these will be affected by the mapping!

  Args:
    op: The operation that should be applied to the SparseTensor `values`. `op`
      is typically an element-wise operation (such as math_ops.add), but any
      operation that preserves the shape can be used.
    *args: Arguments for `op`.
    **kwargs: Keyword arguments for `op`.

  Returns:
    A `SparseTensor` whose `indices` and `dense_shape` matches the `indices`
    and `dense_shape` of all input `SparseTensor`s.
  Raises:
    ValueError: If args contains no `SparseTensor`, or if the `indices`
      or `dense_shape`s of the input `SparseTensor`s are not equal.
  z.No SparseTensor in argument list of map_valuesr   N)	_replace_sparse_with_valuesr   r   control_dependencies_assert_sparse_compatibler   r"   rH   rV   )opargskwargssparse_list
inner_argsinner_kwargss         r&   
map_valuesr  t  s    h +*4=*,V[A,	
E
FF
 9+ FG B %%k!n&<&<&(*&E&E&1!n&@&@B	B B Bs   7BBarrc           	      d   |dn|}t        j                  |      5  ||rt        d      | j                  j                  s$t        j                  | t        j                        } |d}|dvrt        d| d      t        j                  |       }|dkD  }	t        j                  t        j                  | j                        d      }
t        j                  |	| j                        |
d	z   z  }|8t        j                  |d
| j                        }t        j                  ||      }|8t        j                  |d| j                        }t        j                   ||      }|dk(  r|t#        | ||      }| j                  } t%        | t&        j(                        rOt#        | ||      }t        j*                  | j,                  | j                  | j.                  |||      cddd       S t1        j2                  | ||      }t        j4                  | |||      cddd       S # 1 sw Y   yxY w)a  Counts the number of occurrences of each value in an integer array.

  Only the values in the SparseTensor's `values` tensor are counted,
  missing zeros are ignored.

  If `minlength` and `maxlength` are not given, returns a vector with length
  `tf.reduce_max(arr) + 1` if `arr` is non-empty, and length 0 otherwise.

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [1, 7], [2, 4], [3, 0],
  ...              [4, 9], [5, 1], [6, 8], [7, 2]],
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[8, 10])
  >>> tf.math.bincount(data)
  <tf.Tensor: ... numpy=array([0, 2, 2, 1, 2, 1], dtype=int32)>

  Vector length = Maximum element in vector `values` is 5. Adding 1, which is 6
                  will be the vector length.

  Each bin value in the output indicates number of occurrences of the particular
  index. Here, index 1 in output has a value 2. This indicates value 1 occurs
  two times in `values`.

  **Bin-counting with weights**

  >>> indices=[[0, 3], [1, 7], [2, 4], [3, 0], [4, 9], [5, 1], [6, 8], [7, 2]]
  >>> data = tf.sparse.SparseTensor(
  ...     indices=indices,
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[8, 10])
  >>> weights = tf.sparse.SparseTensor(
  ...     indices=indices,
  ...     values=[1,5,0,1,0,5,4,5],
  ...     dense_shape=[8, 10])
  >>> tf.math.bincount(data, weights=weights)
  <tf.Tensor: ... numpy=array([0, 6, 0, 1, 9, 5], dtype=int32)>

  When `weights` is specified, bins will be incremented by the corresponding
  weight instead of 1. Here, index 1 in output has a value 6. This is the
  summation of `weights` corresponding to the value in `values` (i.e. for index
  1, the first two data values are 1 so the first two weights, 1 and 5, are
  summed).

  On GPU, `bincount` with weights is only supported when `axis=0` and XLA is
  enabled (typically when a function decorated with
  `@tf.function(jit_compile=True)`).

  **Bin-counting matrix rows independently**

  This example uses `axis=-1` with a 2 dimensional input and returns a
  `Tensor` with bincounting where axis 0 is **not** flattened, i.e. an
  independent bincount for each matrix row.

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [0, 7], [1, 4], [1, 0],
  ...              [1, 9], [2, 1], [2, 8], [2, 2]],
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[3, 10])
  >>> tf.math.bincount(data, axis=-1)
    <tf.Tensor: shape=(3, 6), dtype=int32, numpy=
    array([[0, 2, 0, 0, 0, 0],
           [0, 0, 2, 1, 0, 0],
           [0, 0, 0, 0, 2, 1]], dtype=int32)>

  **Bin-counting with binary_output**

  This example gives binary output instead of counting the occurrence.

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [0, 7], [1, 4], [1, 0],
  ...              [1, 9], [2, 1], [2, 8], [2, 2]],
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[3, 10])
  >>> tf.math.bincount(data, axis=-1, binary_output=True)
    <tf.Tensor: shape=(3, 6), dtype=int32, numpy=
    array([[0, 1, 0, 0, 0, 0],
           [0, 0, 1, 1, 0, 0],
           [0, 0, 0, 0, 1, 1]], dtype=int32)>

  **Missing zeros in SparseTensor**

  Note that missing zeros (implict zeros) in SparseTensor are **NOT** counted.
  This supports cases such as `0` in the values tensor indicates that index/id
  `0`is present and a missing zero indicates that no index/id is present.

  If counting missing zeros is desired, there are workarounds.
  For the `axis=0` case, the number of missing zeros can computed by subtracting
  the number of elements in the SparseTensor's `values` tensor from the
  number of elements in the dense shape, and this difference can be added to the
  first element of the output of `bincount`. For all cases, the SparseTensor
  can be converted to a dense Tensor with `tf.sparse.to_dense` before calling
  `tf.math.bincount`.

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [1, 7], [2, 4], [3, 0],
  ...              [4, 9], [5, 1], [6, 8], [7, 2]],
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[8, 10])
  >>> counts = tf.math.bincount(data, dtype=tf.int64)
  >>> dense_size = tf.math.reduce_prod(data.dense_shape)
  >>> missing_zeros = dense_size - tf.size(data.values, out_type=tf.int64)
  >>> tf.concat([[counts[0] + missing_zeros], counts[1:]], 0)
  <tf.Tensor: ... numpy=array([72, 2, 2, 1, 2, 1])>

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [1, 7], [2, 4], [3, 0],
  ...              [4, 9], [5, 1], [6, 8], [7, 2]],
  ...     values=[1,1,2,3,2,4,4,5],
  ...     dense_shape=[8, 10])
  >>> tf.math.bincount(tf.sparse.to_dense(data), dtype=tf.int64)
  <tf.Tensor: ... numpy=array([72, 2, 2, 1, 2, 1])>


  Args:
    arr: A SparseTensor whose values should be counted.
      These tensors must have a rank of 2 if `axis=-1`.
    weights: If non-None, must be a SparseTensor with the same dense shape and
      same indices as `arr`. For each value in `arr`, the bin will be
      incremented by the corresponding weight instead of 1. If non-None,
      `binary_output` must be False.
    minlength: If given, ensures the output has length at least `minlength`,
      padding with zeros at the end if necessary.
    maxlength: If given, skips values in `arr` that are equal or greater than
      `maxlength`, ensuring that the output has length at most `maxlength`.
    dtype: If `weights` is None, determines the type of the output bins.
    name: A name scope for the associated operations (optional).
    axis: The axis to slice over. Axes at and below `axis` will be flattened
      before bin counting. Currently, only `0`, and `-1` are supported. If None,
      all axes will be flattened (identical to passing `0`). XLA does not
      support `axis=-1`.
    binary_output: If True, this op will output 1 instead of the number of times
      a token appears (equivalent to one_hot + reduce_any instead of one_hot +
      reduce_add). Defaults to False.

  Returns:
    A vector with the same dtype as `weights` or the given `dtype` containing
    the bincount values.

  Raises:
    `InvalidArgumentError` if negative values are provided as an input.

  NbincountXArguments `binary_output` and `weights` are mutually exclusive. Please specify only one.r   r   rL   $Unsupported value for argument axis=(. Only 0 and -1 are currently supported.rL   rQ   	minlengthr3   	maxlength)rH   rI   rV   r  weightsbinary_output)inputr  r  r  )r   rB   r   r5   
is_integerr   r<   r   rX   r   r  rR  r   rI   r7   r   rh   validate_sparse_weightsr    r   r"   sparse_bincountrH   rV   r   validate_dense_weightsdense_bincount)r  r  r  r  r5   r4   rP   r  
total_sizearray_is_nonempty	max_valueoutput_sizes               r&   r  r    s   n |$
~~d 3'} = > > 99MM#v||,c|d7=dV D6 6 7 7 $J"Q   !4!4SZZ!@"EI-- 1399=QOK''
+SYY8i ((K@k''
+SYY8i ((K@kqy		)#w>JJc#}112'We<g))++oo%'K3' 3'\ 33C%Hg((%	'_3' 3' 3's   GH&-/H&&H/zsparse.bincountc           
         t        j                  |d| |g      5  t        | t        j                        st        j                  | d      } |1t        |t        j                        st        j                  |d      }||rt        d      |d}|dvrt        d	| d
      ||nd}||nd}|dk(  ret        | t        j                        r|t        | |      }| j                  } n0|t        j                  |dg      }t        j                  | dg      } t        | t        j                        rKt        | |      }t        j                  | j                   | j                  | j"                  ||||      \  }	}
}n4t%        j&                  | |      }t        j(                  | ||||      \  }	}
}t        j                  |	|
|      cddd       S # 1 sw Y   yxY w)a  Count the number of times an integer value appears in a tensor.

  This op takes an N-dimensional `Tensor`, `RaggedTensor`, or `SparseTensor`,
  and returns an N-dimensional int64 SparseTensor where element
  `[i0...i[axis], j]` contains the number of times the value `j` appears in
  slice `[i0...i[axis], :]` of the input tensor.  Currently, only N=0 and
  N=-1 are supported.

  Args:
    values: A Tensor, RaggedTensor, or SparseTensor whose values should be
      counted. These tensors must have a rank of 2 if `axis=-1`.
    weights: If non-None, must be the same shape as `arr`. If `arr` is a
      SparseTensor, `weights` must be a SparseTensor with the same dense shape
      and same indices as `arr`. For each value in `value`, the bin will be
      incremented by the corresponding weight instead of 1.
    axis: The axis to slice over. Axes at and below `axis` will be flattened
      before bin counting. Currently, only `0`, and `-1` are supported. If None,
      all axes will be flattened (identical to passing `0`).
    minlength: If given, ensures the output has length at least `minlength`,
      padding with zeros at the end if necessary.
    maxlength: If given, skips values in `values` that are equal or greater than
      `maxlength`, ensuring that the output has length at most `maxlength`.
    binary_output: If True, this op will output 1 instead of the number of times
      a token appears (equivalent to one_hot + reduce_any instead of one_hot +
      reduce_add). Defaults to False.
    name: A name for this op.

  Returns:
    A SparseTensor with `output.shape = values.shape[:axis] + [N]`, where `N` is
      * `maxlength` (if set);
      * `minlength` (if set, and `minlength > reduce_max(values)`);
      * `0` (if `values` is empty);
      * `reduce_max(values) + 1` otherwise.

  Raises:
    `InvalidArgumentError` if negative values are provided as an input.

  Examples:

  **Bin-counting every item in individual batches**

  This example takes an input (which could be a Tensor, RaggedTensor, or
  SparseTensor) and returns a SparseTensor where the value of (i,j) is the
  number of times value j appears in batch i.

  >>> data = np.array([[10, 20, 30, 20], [11, 101, 11, 10001]], dtype=np.int64)
  >>> tf.sparse.bincount(data, axis=-1)
  SparseTensor(indices=tf.Tensor(
  [[    0    10]
   [    0    20]
   [    0    30]
   [    1    11]
   [    1   101]
   [    1 10001]], shape=(6, 2), dtype=int64),
   values=tf.Tensor([1 2 1 2 1 1], shape=(6,), dtype=int64),
   dense_shape=tf.Tensor([    2 10002], shape=(2,), dtype=int64))

  This example shows a sparse tensor input. Missing zeros are not counted.

  >>> data = tf.sparse.SparseTensor(
  ...     indices=[[0, 3], [0, 7], [0, 8], [0, 11],
  ...              [1, 9], [1, 11], [1, 18], [1, 27]],
  ...     values=[10, 20, 30, 20, 11, 101, 11, 10001],
  ...     dense_shape=[2, 30])
  >>> tf.sparse.bincount(data, axis=-1)
  SparseTensor(indices=tf.Tensor(
  [[    0    10]
   [    0    20]
   [    0    30]
   [    1    11]
   [    1   101]
   [    1 10001]], shape=(6, 2), dtype=int64),
   values=tf.Tensor([1 2 1 2 1 1], shape=(6,), dtype=int32),
   dense_shape=tf.Tensor([    2 10002], shape=(2,), dtype=int64))

  **Bin-counting with defined output shape**

  This example takes an input (which could be a Tensor, RaggedTensor, or
  SparseTensor) and returns a SparseTensor where the value of (i,j) is the
  number of times value j appears in batch i. However, all values of j
  above 'maxlength' are ignored. The dense_shape of the output sparse tensor
  is set to 'minlength'. Note that, while the input is identical to the
  example above, the value '10001' in batch item 2 is dropped, and the
  dense shape is [2, 500] instead of [2,10002] or [2, 102].

  >>> minlength = maxlength = 500
  >>> data = np.array([[10, 20, 30, 20], [11, 101, 11, 10001]], dtype=np.int64)
  >>> tf.sparse.bincount(
  ...    data, axis=-1, minlength=minlength, maxlength=maxlength)
  SparseTensor(indices=tf.Tensor(
  [[  0  10]
   [  0  20]
   [  0  30]
   [  1  11]
   [  1 101]], shape=(5, 2), dtype=int64),
   values=tf.Tensor([1 2 1 2 1], shape=(5,), dtype=int64),
   dense_shape=tf.Tensor([  2 500], shape=(2,), dtype=int64))

  **Binary bin-counting**

  This example takes an input (which could be a Tensor, RaggedTensor, or
  SparseTensor) and returns a SparseTensor where (i,j) is 1 if the value j
  appears in batch i at least once and is 0 otherwise. Note that, even though
  some values (like 20 in batch 1 and 11 in batch 2) appear more than once,
  the 'values' tensor is all 1s.

  >>> data = np.array([[10, 20, 30, 20], [11, 101, 11, 10001]], dtype=np.int64)
  >>> tf.sparse.bincount(data, binary_output=True, axis=-1)
  SparseTensor(indices=tf.Tensor(
  [[    0    10]
   [    0    20]
   [    0    30]
   [    1    11]
   [    1   101]
   [    1 10001]], shape=(6, 2), dtype=int64),
   values=tf.Tensor([1 1 1 1 1 1], shape=(6,), dtype=int64),
   dense_shape=tf.Tensor([    2 10002], shape=(2,), dtype=int64))

  **Weighted bin-counting**

  This example takes two inputs - a values tensor and a weights tensor. These
  tensors must be identically shaped, and have the same row splits or indices
  in the case of RaggedTensors or SparseTensors. When performing a weighted
  count, the op will output a SparseTensor where the value of (i, j) is the
  sum of the values in the weight tensor's batch i in the locations where
  the values tensor has the value j. In this case, the output dtype is the
  same as the dtype of the weights tensor.

  >>> data = np.array([[10, 20, 30, 20], [11, 101, 11, 10001]], dtype=np.int64)
  >>> weights = [[2, 0.25, 15, 0.5], [2, 17, 3, 0.9]]
  >>> tf.sparse.bincount(data, weights=weights, axis=-1)
  SparseTensor(indices=tf.Tensor(
  [[    0    10]
   [    0    20]
   [    0    30]
   [    1    11]
   [    1   101]
   [    1 10001]], shape=(6, 2), dtype=int64),
   values=tf.Tensor([2. 0.75 15. 5. 17. 0.9], shape=(6,), dtype=float32),
   dense_shape=tf.Tensor([    2 10002], shape=(2,), dtype=int64))

  countrI   rx   Nr  r  r   r  r  r  rL   )r  r  r  )r  r  r  r  )r   rB   r    r   r"   r	   "convert_to_tensor_v2_with_dispatchr   CompositeTensorr   r  rI   r   r   r   sparse_count_sparse_outputrH   rV   r   r  dense_count_sparse_output)rI   r  rP   r  r  r  r4   minlength_valuemaxlength_valuec_indc_valc_shapes               r&   r  r    s   n ~~dGfg%67 8=fm889 CC
x!f
 !1!A!AB#FF)% } = > > |d7=dV D6 6 7 7 $-#8ibO#,#8ibOqy	FM66	7+FG<'%%gt4'""6B40&-445'8g+FF
..
--



##%'eUG 33FGDg+EE
##%'eUG %%eUG<q8= 8= 8=s   F0GGc                    |D|rt        j                  g |      S t        j                  g | j                  j                        S t	        |t
        j                        s$t        d| dt        |      j                         g }|j                  | j                  ur;|j                  t        j                  |j                  | j                  d             |j                  | j                  ur;|j                  t        j                  |j                  | j                  d             |r?t        j                   |      5  t        j"                  |j                        }ddd       |S |j                  }|S # 1 sw Y   |S xY w)z;Validates the passed weight tensor or creates an empty one.NrR   zZArgument `weights` must be a SparseTensor if `values` is a SparseTensor. Received weights=z
 of type: z6'weights' and 'values' must have the same dense shape.messagez2'weights' and 'values' must have the same indices.)r   r   rI   r5   r    r   r"   r   r?  r   rV   r   r   rW  rH   r   r  r   )rI   r  r5   checkss       r&   r  r  W  sW   _%00b(;(;<<	G]77	8
	**1*=!!
"	$% %
 & 2 22
MML	NO
 __FNN*
MMOONNH	J 		!	!&	) 3""7>>2g3
 
. nnG	.3
 
.s    E<<Fc                    g }| d   }| dd D ]x  }|j                  t        j                  |j                  |j                  d             |j                  t        j                  |j                  |j                  d             z |S )zCheck that all of `sparse_tensors` have same `indices` and `dense_shape`.

  Args:
    sparse_tensors: A list of sparse tensors.

  Returns:
    An op to be used as a control dependency.
  r   rQ   NzMismatched shapes!r  zMismatched indices!)r   r   rW  rV   rH   )r  r  firstts       r&   r  r  {  s     &

%!" Fa
MMq}}6J	LM MMMM199.C	EF	F 
-r(   c                 "   t        j                  | d      }g }|D ]Z  }t        |t        j                        r-|j                  |       |j                  |j                         J|j                  |       \ t        j                  | |d      S )a  Replace `SparseTensor`s with their values in `value`

  Each `SparseTensor` in `value` is replaced by its `values` tensor, and
  collects all `SparseTensor`s in `sparse_list`.

  Args:
    value: A structure of `Tensor`s and `SparseTensor`s
    sparse_list: A list. Output parameter that collects all `SparseTensor`s in
      `value`.

  Returns:
    `value` with each SparseTensor replaced by its `.value` attribute.
  F)expand_composites)r   flattenr    r   r"   r   rI   pack_sequence_as)r=   r  	flat_valsnew_valsvs        r&   r  r    sy     ll5E:)( a!]//0ooahhooa 
		uh%	HHr(   c                     t        |       } t        j                  | j                  | j                  | j
                  |||      S )a  Add a `SparseTensor` to a `SparseTensorsMap` and return its handle.

  Args:
    sp_input: The input `SparseTensor`.
    container: The container for the underlying `SparseTensorsMap` (optional).
    shared_name: The shared name for the underlying `SparseTensorsMap`
      (optional, defaults to the name of the newly created op).
    name: A name prefix for the returned tensors (optional).

  Returns:
    A string 1-vector (1D `Tensor`), with the single element representing the
    a unique handle to a `SparseTensor` stored by the `SparseTensorMap`
    underlying this op.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  	containershared_namer4   )r'   r   add_sparse_to_tensors_maprH   rI   rV   r%   r  r  r4   s       r&   _add_sparse_to_tensors_mapr    sC    * 'x0(		1	1oo
 r(   c                     t        |       } t        j                  | j                  | j                  | j
                  |||      S )a   Add a minibatch `SparseTensor` to a `SparseTensorsMap`, return `N` handles.

  The `SparseTensor` must have rank `R` greater than 1, and the first dimension
  is treated as the minibatch dimension.  Elements of the `SparseTensor`
  must be sorted in increasing order of this first dimension.  The serialized
  `SparseTensor` objects going into each row of the output `Tensor` will have
  rank `R-1`.

  The minibatch size `N` is extracted from `sparse_shape[0]`.

  Args:
    sp_input: The input rank `R` `SparseTensor`.
    container: The container for the underlying `SparseTensorsMap` (optional).
    shared_name: The shared name for the underlying `SparseTensorsMap`
      (optional, defaults to the name of the newly created op).
    name: A name prefix for the returned tensors (optional).

  Returns:
    A string matrix (2-D `Tensor`) with `N` rows and `1` column.
    Each row represents a unique handle to a `SparseTensor` stored by
    the `SparseTensorMap` underlying this op.

  Raises:
    TypeError: If `sp_input` is not a `SparseTensor`.
  r  )r'   r   add_many_sparse_to_tensors_maprH   rI   rV   r  s       r&   _add_many_sparse_to_tensors_mapr    sC    : 'x0(		6	6oo
 r(   c                    t        | t        j                        st        d      | j                  dvrt        d| j                  z        t        j
                  |       5  | j                  d      xs | j                  }t        j                  || j                  d      | j                  d      ||      \  }}}ddd       j                  d|g       j                  |g       t        j                  ||      S # 1 sw Y   ExY w)	a  Read `SparseTensors` from a `SparseTensorsMap` and concatenate them.

  The input `sparse_handles` must be a string matrix of shape `[N, 1]` where
  `N` is the minibatch size and the rows correspond to packed outputs of
  `add_sparse_to_tensors_map`.  The ranks of the original `SparseTensor` objects
  must all match.  When the final `SparseTensor` is created, it has rank one
  higher than the ranks of the incoming `SparseTensor` objects (they have been
  concatenated along a new row dimension).

  The output `SparseTensor` object's shape values for all dimensions but the
  first are the max across the input `SparseTensor` objects' shape values
  for the corresponding dimensions.  Its first shape value is `N`, the minibatch
  size.

  The input `SparseTensor` objects' indices are assumed ordered in
  standard lexicographic order.  If this is not the case, after this
  step run `sparse.reorder` to restore index ordering.

  For example, if the serialized input is a `[2, 3]` matrix representing two
  original `SparseTensor` objects:

      index = [ 0]
              [10]
              [20]
      values = [1, 2, 3]
      shape = [50]

  and

      index = [ 2]
              [10]
      values = [4, 5]
      shape = [30]

  then the final deserialized `SparseTensor` will be:

      index = [0  0]
              [0 10]
              [0 20]
              [1  2]
              [1 10]
      values = [1, 2, 3, 4, 5]
      shape = [2 50]

  Args:
    sparse_map_op: The `Operation` that created the original handles.
      Usually this is, e.g., `add_sparse_to_tensors_map(...).op`.
    sparse_handles: 2-D `Tensor` of type `string` of shape `[N, 1]`.
      The serialized and packed `SparseTensor` objects.
    rank: (optional) Python int, the rank of the `SparseTensor` objects.
    name: A name prefix for the returned tensors (optional)

  Returns:
    A `SparseTensor` representing the deserialized `SparseTensor`s,
    concatenated along the `SparseTensor`s' first dimension.

    All of the serialized `SparseTensor`s must have had the same rank and type.
  zsparse_map_op be an Operation)AddSparseToTensorsMapAddManySparseToTensorsMapzasparse_map_op must be one of AddSparseToTensorsMap or AddSparseToTensorsMap. Instead, found `%s`.r  Tr  )r5   r  r  r4   N)r    r   	Operationr$   r?  colocate_withget_attrr4   r   !take_many_sparse_from_tensors_mapr   r   r"   )sparse_map_opsparse_handlesr\   r4   r  r  r  r   s           r&   "_take_many_sparse_from_tensors_mapr    s   | 
M3==	1
3
44  = =
	68E8J8J	KL L ' ((7M=;M;MK88((-#,,[9#	 0NM< D$<($ 		#	#NM<	PP s   !ADD
c                       e Zd ZdZd Zd Zy)_UnaryMapValueDispatcherzHOpDispatcher for unary ops that maps base function across sparse values.c                     || _         t        |      }t        j                  |      d   }|d   | _        |j
                  j                         dz   dj                  | j                  |      z   |_        y )Nr   z

zv    If `{x}` is a `SparseTensor`, returns
    `SparseTensor({x}.indices, tf.{func}({x}.values, ...), {x}.dense_shape)`)rD  func)_original_funcr   r   getfullargspec_x__doc__rstripr;   )r   original_func	func_name	arg_namess       r&   __init__z!_UnaryMapValueDispatcher.__init__J  sp    'D-m<I))-8;IlDG$$&/
$ftwwYf?	@ r(   c                 T   |r|d   |dd  }}n,|j                         }|j                  | j                  d       }t        |t        j
                        rJt	        j
                  |j                   | j                  |j                  g|i ||j                        S | j                  S )Nr   rQ   rU   )copypopr  r    r   r"   rH   r  rI   rV   NOT_SUPPORTED)r   r  r  rD  s       r&   handlez_UnaryMapValueDispatcher.handleU  s    Qaba{{}f
**TWWd
#a!]//0''))$$$QXX???mm% %
 r(   N)r   r   r   r  r  r  r   r(   r&   r  r  G  s    P	A r(   r  r+   )NN)NFNN)FN)r   )r   NN)Fr   NN)NNNN)r   TN)NNFN)NTN)NF)FFN)Nr   NNFN)NNN)xr  r=  numpyr   tensorflow.python.frameworkr   r   r   r   r   r   r9   r	   r
   r   tensorflow.python.opsr   r   r   r   r   r   r   r   r   r   $tensorflow.python.ops.gen_sparse_opstensorflow.python.utilr   r   r   r   r   tensorflow.python.util.compatr    tensorflow.python.util.tf_exportr   r   r'   r1   r>   rJ   rc   float32rn   deprecated_endpointsdeprecated_argsro   rv   replacer   r   r   _sparse_crossr   _sparse_cross_hashedr   r   r   r   r   add_dispatch_supportr   r   r   r  r  
deprecatedr  r  r  r  r(  r'  r&  r+  r-  r7  r1  rH  rP  r`  r   re  rg  rl  rn  rq  rt  rw  r  r  r  r  r  dispatch_for_apir  rX   r"   r  r  r  r  r  r  r  OpDispatcherr  absnegativesignsquaresqrterftanh
bessel_i0e
bessel_i1e
_UNARY_OPSunary_opregisterr   r(   r&   <module>r     s  "   8 3 . + 5 < 9 4 3 + 1 . + 2 / . 0 * 2 3 ) . + ' - 9 J 6&5*, >  >>  fD !fDR <^^- -D 01!!!/2
6F ',!(,mGF 3 2mG` ?r"2 #2j )0088;M	   |\*+!!!,/
7C9(C 0 ,9(x <BPD  PDf >3H 3Hl   !+ "+\ +   /8 */'($( $	0HfL2 !13C DE!!!"232 4 F2j !13C DE!!!"23	e6  4 Fe6R  ~~./!!!.1
5{D"1"3ED 2 0EP >b!!"A& "A&H >~~>?!!!.1-4 2 @-4`  !"	MO #$%)4O  #
4n 2&EI[ '[| "$789!!!"56
9;H
: 5959L9H 7 :L9^ )+EFG!!!"<=
9;H #'&*,0'+	.JH > H.Jb 2&EIK 'K\ "$789!!!"56
9;H
: 5959;9H 7 :;9| )+EFG!!!"<=
9;H #'&*,0'+	.JH > H.Jb "35M!NO!!!":;)-,0 $3 < P3l 46KLN!!!"78;H 9N;H| ~~./EF59 %]P G 0]PF  %*	6@r ?AB!!!/2*N 3 C*NZ 24HIK!!!"67cP 8KcPL  ":;= "!!":;<@ <=<@~ $&89:	!!!"45$(6== 7 6  ;7$  R(	+1==t   )2 )+BCD	!!!"9:)- < ;  E<6 %"-	06D   .D?QD  $&?@B 
!!!";<BQ = B
BQJ '-. "!!">? */).$(	j @.jZ !13C DE!!!"23:< 4 F:<z !13C DE!!!"23)O 4 F)OX !13C DE!!!"23'O 4 F'OT #57I"JK!!!"45g 6 LgT 2&	>B  '>BB <001<< J'-,, J' 2J'Z 	 """'M=  M=`!H*I4 *.+/$(B /304)-%T -1,0SQl x44  > LLMMOOMMLLMM
  8H8$--h78r(   