o
    i e?"                     @   s   d Z ddlm  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 ejZejZed	d
g dG dd dejZdS )z*Keras hashed crossing preprocessing layer.    N)backend)
base_layer)base_preprocessing_layer)preprocessing_utils)layer_utils)keras_exportzkeras.layers.HashedCrossingz6keras.layers.experimental.preprocessing.HashedCrossing)v1c                       sV   e Zd ZdZd fdd	Zdd Zdd	 Zd
d Z fddZdd Z	dd Z
  ZS )HashedCrossingav  A preprocessing layer which crosses features using the "hashing trick".

    This layer performs crosses of categorical features using the "hashing
    trick". Conceptually, the transformation can be thought of as:
    `hash(concatenate(features)) % num_bins`.

    This layer currently only performs crosses of scalar inputs and batches of
    scalar inputs. Valid input shapes are `(batch_size, 1)`, `(batch_size,)` and
    `()`.

    For an overview and full list of preprocessing layers, see the preprocessing
    [guide](https://www.tensorflow.org/guide/keras/preprocessing_layers).

    Args:
        num_bins: Number of hash bins.
        output_mode: Specification for the output of the layer. Values can be
            `"int"`, or `"one_hot"` configuring the layer as follows:
            - `"int"`: Return the integer bin indices directly.
            - `"one_hot"`: Encodes each individual element in the input into an
                array the same size as `num_bins`, containing a 1 at the input's
                bin index. Defaults to `"int"`.
        sparse: Boolean. Only applicable to `"one_hot"` mode. If `True`,
            returns a `SparseTensor` instead of a dense `Tensor`.
            Defaults to `False`.
        **kwargs: Keyword arguments to construct a layer.

    Examples:

    **Crossing two scalar features.**

    >>> layer = tf.keras.layers.HashedCrossing(
    ...     num_bins=5)
    >>> feat1 = tf.constant(['A', 'B', 'A', 'B', 'A'])
    >>> feat2 = tf.constant([101, 101, 101, 102, 102])
    >>> layer((feat1, feat2))
    <tf.Tensor: shape=(5,), dtype=int64, numpy=array([1, 4, 1, 1, 3])>

    **Crossing and one-hotting two scalar features.**

    >>> layer = tf.keras.layers.HashedCrossing(
    ...     num_bins=5, output_mode='one_hot')
    >>> feat1 = tf.constant(['A', 'B', 'A', 'B', 'A'])
    >>> feat2 = tf.constant([101, 101, 101, 102, 102])
    >>> layer((feat1, feat2))
    <tf.Tensor: shape=(5, 5), dtype=float32, numpy=
      array([[0., 1., 0., 0., 0.],
             [0., 0., 0., 0., 1.],
             [0., 1., 0., 0., 0.],
             [0., 1., 0., 0., 0.],
             [0., 0., 0., 1., 0.]], dtype=float32)>
    intFc                    s   d|vs
|d d u r|t krtjnt |d< t jdi | tj	d
d |t kr?t| jjs?|d }td| tj|t tf| jjdd || _|| _|| _d S )Ndtyper	   TzMWhen `output_mode='int'`, `dtype` should be an integer type. Received: dtype=output_mode)allowable_strings
layer_namearg_name )INTtfint64r   floatxsuper__init__r   keras_kpl_gaugeget_cellsetas_dtypecompute_dtype
is_integer
ValueErrorr   validate_string_argONE_HOT	__class____name__num_binsr   sparse)selfr"   r   r#   kwargsinput_dtyper    r   ]/var/www/myenv/lib/python3.10/site-packages/keras/src/layers/preprocessing/hashed_crossing.pyr   [   s2   
zHashedCrossing.__init__c                 C   s   |  | dd |D }| | |d jj}|dk r"dd |D }|dk r-dd |D }tj|| j}tj|}|dkrHt	|ddg}n|dkrTt	|dg}n
|dkr^t	|g }t
j|| j| j| j| jd	S )
Nc                 S   s   g | ]}t |qS r   )utilsensure_tensor.0xr   r   r(   
<listcomp>       z'HashedCrossing.call.<locals>.<listcomp>r      c                 S      g | ]}t |d qS r)   expand_dimsr+   r   r   r(   r.             c                 S   r1   r2   r4   r+   r   r   r(   r.      r6   r3   )r   depthr#   r   )_check_at_least_two_inputs_check_input_shape_and_typeshaperankr   r#   cross_hashedr"   to_densereshaper)   encode_categorical_inputsr   r   )r$   inputsr<   outputsr   r   r(   call~   s.   

zHashedCrossing.callc                 C   s   |  | t|d S )Nr   )r9   r)   $compute_shape_for_encode_categorical)r$   input_shapesr   r   r(   compute_output_shape   s   
z#HashedCrossing.compute_output_shapec                 C   sP   dd |D }|  |}| jstdd |D r tj|| jdS tj|| jdS )Nc                 S   s   g | ]}|j  qS r   r;   as_listr+   r   r   r(   r.      r/   z;HashedCrossing.compute_output_signature.<locals>.<listcomp>c                 s   s    | ]	}t |tjV  qd S N)
isinstancer   SparseTensorSpecr+   r   r   r(   	<genexpr>   s    
z:HashedCrossing.compute_output_signature.<locals>.<genexpr>)r;   r   )rF   r#   anyr   rK   r   
TensorSpec)r$   input_specsrE   output_shaper   r   r(   compute_output_signature   s   
z'HashedCrossing.compute_output_signaturec                    s&   t   }|| j| j| jd |S )N)r"   r   r#   )r   
get_configupdater"   r   r#   )r$   configr'   r   r(   rR      s   
zHashedCrossing.get_configc                 C   s:   t |ttfstd| t|dk rtd| d S )NzQ`HashedCrossing` should be called on a list or tuple of inputs. Received: inputs=r0   zK`HashedCrossing` should be called on at least two inputs. Received: inputs=)rJ   listtupler   len)r$   rA   r   r   r(   r9      s   z)HashedCrossing._check_at_least_two_inputsc                    s   |d j   t }|dks|dkr  d dkr td| t fdd|dd  D s6td| td	d |D rFtd
| tdd |D sVtd| d S )Nr   r0   r3   r7   zjAll `HashedCrossing` inputs should have shape `[]`, `[batch_size]` or `[batch_size, 1]`. Received: inputs=c                 3   s    | ]
}|j   kV  qd S rI   rG   r+   first_shaper   r(   rL      s    z=HashedCrossing._check_input_shape_and_type.<locals>.<genexpr>zFAll `HashedCrossing` inputs should have equal shape. Received: inputs=c                 s   s"    | ]}t |tjtjfV  qd S rI   )rJ   r   RaggedTensorSparseTensorr+   r   r   r(   rL      s    
zFAll `HashedCrossing` inputs should be dense tensors. Received: inputs=c                 s   s$    | ]}|j jp|j tjkV  qd S rI   )r   r   r   stringr+   r   r   r(   rL      s   " zUAll `HashedCrossing` inputs should have an integer or string dtype. Received: inputs=)r;   rH   rW   r   allrM   )r$   rA   r<   r   rX   r(   r:      s:   z*HashedCrossing._check_input_shape_and_type)r
   F)r!   
__module____qualname____doc__r   rC   rF   rQ   rR   r9   r:   __classcell__r   r   r'   r(   r	   !   s    4#&r	   )r`   tensorflow.compat.v2compatv2r   	keras.srcr   keras.src.enginer   r   keras.src.layers.preprocessingr   r)   keras.src.utilsr    tensorflow.python.util.tf_exportr   r   r   Layerr	   r   r   r   r(   <module>   s    