a
    ijB&                     @  sr  d Z ddlmZ ddlZddlZddlZddlZddlZddlmZm	Z	m
Z
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ZeZed	ZejG d
d dZejG dd dZejd.ddddddddZejd/ddd	dd	dddZd0ddddddZddddddZdddd d!Zedddd"d#d$Zdd%d&d'Z d(d)d*d+d,d-Z!dS )1zCheck util.    )annotationsN)AnyCallableOptionalTypeVar)epy)numpy_utils)type_parsing)typing_Fnc                   @  s8   e Zd ZU dZded< ded< ded< dd	d
dZdS )_ArrayParamzArgument matching an array.zarray_typing.ArrayAliasMetatypeboolis_optionalstrnamenumpy_utils.NpModulexnpc             
   C  sX   z| j jj||ddW S  tyR } z$tj|d| j dd W Y d}~n
d}~0 0 dS )z0Convert the value to array of the correct dtype.none)r   ZcastingInvalid : prefixN)r   Zdtypeasarray	Exceptionr   reraiser   )selfvr   e r    P/home/ghrups/robot-bench/.venv/lib/python3.9/site-packages/etils/enp/checking.pyr   2   s    z_ArrayParam.asarrayN)__name__
__module____qualname____doc____annotations__r   r    r    r    r!   r   *   s
   
r   c                   @  s*   e Zd ZU dZded< ded< ded< dS )	_FnSignatureCachez Cache of the function signature.zinspect.Signaturesigr   has_xnp_kwargszdict[str, _ArrayParam]array_paramsN)r"   r#   r$   r%   r&   r    r    r    r!   r'   :   s   
r'   .strictNoner   zCallable[[_Fn], _Fn])fnr,   returnc                C  s   d S Nr    r.   r,   r    r    r!   check_and_normalize_arraysC   s    r2   c                C  s   d S r0   r    r1   r    r    r!   r2   L   s    Tc                  s8    du rt jtdS d _t   fdd}|S )a  Check and normalize arrays.

  This function:

  * Validate that the dtype/shape input arrays match the typing annotations
  * Normalize np, jnp, tf types to be consistent
  * Add an optional `xnp` argument to convert input arrays to np/jnp/tnp.

  See doc at: https://github.com/google/etils/blob/main/etils/array_types/README.md

  Example:

  ```python
  @enp.check_and_normalize_arrays(strict=False)
  def add(x: FloatArray[...], y: FloatArray[...]) -> y: FloatArray[...]:
    return x + y

  # Inside the function, `np` normalized to `jnp`
  add(np.array(1.), jnp.array(2.)) == jnp.array(3.)

  # strict=False, so `list` accepted and normalized to `xnp`
  add(jnp.array(1.), [1., 2., 3.]) == jnp.array([2., 3., 4.])
  ```

  Args:
    fn: The function to decorate. Arguments will be automatically infered.
    strict: If `False`, `fn` will also accept list, int,... in which case those
      are automatically converted to `xnp`

  Returns:
    fn: The decorated function, with dynamic shape checking
  Nr+   c               
     s  zt |}|dd jd u r*t_j  jr>d|d<  jj| i |} fdd|j D }pvt	|dt
  fdd| D }|j|  jr|jd< W n< ty } z$tj|dj dd	 W Y d }~n
d }~0 0 |ji |jS )
Nr   .c                   s(   i | ] \}}| j v r|d ur||qS r0   )r*   .0kr   )stater    r!   
<dictcomp>   s   zDcheck_and_normalize_arrays.<locals>.decorated_fn.<locals>.<dictcomp>r+   c                   s&   i | ]\}}| j | j|d qS )r   )r*   r   r3   r6   r   r    r!   r7      s   z*@enp.check_and_normalize_arrays error for r   r   )dictpop_array_types_state_parse_signaturer)   r(   bind	argumentsitems_get_xnp_maybe_set_tnp_castingupdater   r   r   r$   argskwargs)rC   rD   Z
bound_args
array_argsr   r1   r8   r!   decorated_fn|   s4    


z0check_and_normalize_arrays.<locals>.decorated_fn)	functoolspartialr2   r;   wraps)r.   r,   rF   r    r1   r!   r2   U   s    "6zdict[str, Any]r   )rE   r,   r/   c                C  s~   t t}|  D ]b\}}z|tjj||d | W q tyr } z"t	j
|d| dd W Y d}~qd}~0 0 qt|S )z*Extract the xnp module common to the args.r+   r   z: Expected xnp.ndarray: r   N)collectionsdefaultdictlistr?   r   lazyZget_xnpappendr   r   r   
_infer_xnp)rE   r,   xnpsr5   r   r   r    r    r!   r@      s    
.r@   z%dict[numpy_utils.NpModule, list[str]])rP   r/   c                 C  sP   t | th }t|dkr:dd |  D } td|  |sBtS |\}|S dS )zExtract the `xnp` module.   c                 S  s   i | ]\}}|j |qS r    )r"   r3   r    r    r!   r7          z_infer_xnp.<locals>.<dictcomp>zConflicting numpy types: N)setnplenr?   
ValueError)rP   Znon_np_xnpsr   r    r    r!   rO      s    rO   )r   r/   c                 C  sT   t jjr| t jjurdS t jjsPddlm} | s>|d t	
d}t| dS )a  If TF numpy mode is not set, make sure `tnp.asarray(1.)` is `tf.float32`.

  If user uses TF without numpy mode, it will create casting issues (for
  example: `tf.float64 + tf.float32` will raise an error).
  To limit the errors encountered, we set `tnp.asarray(1.)` to `tf.float32`
  instead of `tf.float64`.

  If numpy mode is already activated, then no need to do anything, as
  `tf.float64 + tf.float32` will support auto-casting, like Jax and Numpy.

  Args:
    xnp: numpy module.
  Nr   )	np_dtypesTz
        WARNING: Using array types for TF but without numpy mode enabled. It
        is recommended to activate numpy mode as:

        import tensorflow.experimental.numpy as tnp
        tnp.experimental_enable_numpy_behavior(prefer_float32=True)
    )r   rM   Zhas_tfZtnpZis_tnp_enabledZtensorflow.python.ops.numpy_opsrW   Zis_prefer_float32Zset_prefer_float32r   dedentprint)r   rW   msgr    r    r!   rA      s    
rA   )r/   c              
   C  s   zt | }W nB tyP } z*tj|d| j d| j d W Y d}~n
d}~0 0 t| }i }|j	
 D ]"\}}t||}|durj|||< qj|std| j d| dt|d|j	v |d	S )
zParse the function signature.z%Could not infer typing annotation of z defined in r   Nz)Could not detect any array type hints in z with signature .r   )r(   r)   r*   )r
   get_type_hintsr   r   r   r$   r#   inspect	signature
parametersr?   _get_array_paramrV   r'   )r.   hintsr   r(   r*   r   paramZarray_paramr    r    r!   r<     s4    




r<   zinspect.Parameterzdict[str, _TypeForm]zOptional[_ArrayParam])rb   ra   r/   c           	        s   | j |vrdS |  ddd fdd}t }d|v }dd |D }d	d |D }|d
}|d}|r|r|d|dkr|d|rdS |\}| jtjjtjjhv r|dt	||dS )z#Parse the type & hint of the array.Nr   r   )rZ   r/   c                   s   t d|  d d  dS )Nz2`enp.check_and_normalize_arrays` does not support z6. Please open an issue if you need this feature. For `r   `)NotImplementedError)rZ   hintr   r    r!   make_err2  s    z"_get_array_param.<locals>.make_errc                 S  s   g | ]}|d ur|qS r0   r    )r4   tr    r    r!   
<listcomp>;  rR   z$_get_array_param.<locals>.<listcomp>c                 S  s   g | ]}t |tjqS r    )
isinstancearray_typingZArrayAliasMeta)r4   lr    r    r!   ri   >  rR   TFzUnion of array and non-arrayrQ   zUnion of arraysz*args, **kwargs)r   r   r   )
r   r	   Zget_leaf_typescountkindr]   	ParameterVAR_POSITIONALVAR_KEYWORDr   )	rb   ra   rg   Z
leaf_typesr   Z	are_arrayZcount_arrayZcount_non_arrayZ
array_typer    re   r!   r`   '  s8    


r`   ).).)N)"r%   
__future__r   rJ   dataclassesrG   r]   r
   r   r   r   r   Zetilsr   Z	etils.enpr   r	   Zetils.enp.array_typesrk   numpyrT   Z	_TypeFormr   	dataclassr   r'   overloadr2   r@   rO   	lru_cacherA   r<   r`   r    r    r    r!   <module>   sF   	  a(%