o
    2h                     @   s~   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 edG dd	 d	Zd
d Zdd Zdd ZdS )    N)backend)keras_export)global_state)	jax_utils)	auto_namezkeras.random.SeedGeneratorc                   @   s8   e Zd ZdZdddZdddZdd	 Zed
d ZdS )SeedGeneratoraR  Generates variable seeds upon each call to a function generating
    random numbers.

    In Keras, all random number generators (such as
    `keras.random.normal()`) are stateless, meaning that if you pass an
    integer seed to them (such as `seed=42`), they will return the same
    values for repeated calls. To get different values for each
    call, a `SeedGenerator` providing the state of the random generator
    has to be used.

    Note that all the random number generators have a default seed of None,
    which implies that an internal global SeedGenerator is used.
    If you need to decouple the RNG from the global state you can provide
    a local `StateGenerator` with either a deterministic or random initial
    state.

    Remark concerning the JAX backen: Note that the use of a local
    `StateGenerator` as seed argument is required for JIT compilation of
    RNG with the JAX backend, because the use of global state is not
    supported.

    Example:

    ```python
    seed_gen = keras.random.SeedGenerator(seed=42)
    values = keras.random.normal(shape=(2, 3), seed=seed_gen)
    new_values = keras.random.normal(shape=(2, 3), seed=seed_gen)
    ```

    Usage in a layer:

    ```python
    class Dropout(keras.Layer):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.seed_generator = keras.random.SeedGenerator(1337)

        def call(self, x, training=False):
            if training:
                return keras.random.dropout(
                    x, rate=0.5, seed=self.seed_generator
                )
            return x
    ```
    Nc              	      s   |d u r
t jj}|_|dd }|rtd| |d ur$|_nt_ _ d u r1t  t	 t
s=td   fdd}jjjd jj|dj dd	d
d_W d    d S 1 siw   Y  d S )Nr   z Unrecognized keyword arguments: z3Argument `seed` must be an integer. Received: seed=c                     s    | dd }jj dg|dS )Ndtyper   r   )getr   convert_to_tensor)argskwargsr   seedself Z/var/www/html/chatgem/venv/lib/python3.10/site-packages/keras/src/random/seed_generator.pyseed_initializerR   s   z0SeedGenerator.__init__.<locals>.seed_initializer)caller)   Fnoneseed_generator_state)shaper   	trainableaggregationname)r   	__class____name__r   pop
ValueErrorr   _initial_seedmake_default_seed
isinstanceint
name_scopeVariablerandom_seed_dtypestate)r   r   r   r   custom_backendr   r   r   r   __init__<   s6   

"zSeedGenerator.__init__Tc                 C   sh   | j }|jd }|r&| jjtddg|jd}| j | jj	|| |S | j |d d d  |S )N   r   r	   i  iO= )
r'   valuer   r   nparrayr   assignnumpyadd)r   ordered
seed_statenew_seed_value	incrementr   r   r   next`   s   
zSeedGenerator.nextc                 C   s
   d| j iS )Nr   )r    )r   r   r   r   
get_configo   s   
zSeedGenerator.get_configc                 C   s   | di |S )Nr   r   )clsconfigr   r   r   from_configr   s   zSeedGenerator.from_config)NN)T)	r   
__module____qualname____doc__r)   r5   r6   classmethodr9   r   r   r   r   r      s    
.
$r   c                  C   s8   t  rtdtd} | d u rt } td|  | S )Na  [JAX RNG] When tracing a JAX function, you should only use seeded random ops, e.g. you should create a `SeedGenerator` instance, attach it to your layer/model, and pass the instance as the `seed` argument when calling random ops. Unseeded random ops would get incorrectly traced by JAX and would become constant after tracing. Example:

```
# Make sure to set the seed generator as a layer attribute
self.seed_generator = keras.random.SeedGenerator(seed=1337)
...
out = keras.random.normal(shape=(1,), seed=self.seed_generator)
```global_seed_generator)r   is_in_jax_tracing_scoper   r   get_global_attributer   set_global_attribute)genr   r   r   r>   w   s   
r>   c                   C   s   t dtdS )Nr*   g    eA)python_randomrandintr#   r   r   r   r   r!      s   r!   c                 C   sv   ddl m} ddl m} t| tr|  S t| tr#|| dg| dS | d u r.t jddS td|  dt	|  d	)
Nr   )r   )r&   r	   F)r1   z\Argument `seed` must be either an integer or an instance of `SeedGenerator`. Received: seed=z
 (of type ))
keras.src.backendr   r&   r"   r   r5   r#   r>   r   type)r   r   r&   r   r   r   	draw_seed   s   

rH   )randomrC   r/   r,   	keras.srcr   keras.src.api_exportr   keras.src.backend.commonr   keras.src.utilsr   keras.src.utils.namingr   r   r>   r!   rH   r   r   r   r   <module>   s    j