U
    <c%                     @   s   d dl Z d dlm  mZ d dlZd dlmZm	Z	 ddl
mZmZ dZdd Zdd	 Zdd
dZdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )    N)ListOptional   )set_grad_sample_if_exists unpack_expanded_weight_or_tensor    c                 C   s2   | t jkr|S | t jkr|S | t jks*t|S d S N)FZconv1dZconv2dZconv3dAssertionError)funcZ	conv1dOptZ	conv2dOptZ	conv3dOpt r   O/tmp/pip-unpacked-wheel-gikjz4vx/torch/nn/utils/_expanded_weights/conv_utils.pyconv_picker   s    

r   c                 C   sN   |d t |t |   }|t |t |  d  }dd t| |D }t||S )Nc                 S   s   i | ]\}}||qS r   r   ).0nameargr   r   r   
<dictcomp>   s      z(conv_args_and_kwargs.<locals>.<dictcomp>)lenzipconv_normalizer)Zkwarg_namesZexpanded_args_and_kwargsargskwargsr   r   r   conv_args_and_kwargs   s    r   c                 C   s   | |f|||||dfS )N)biasstridepaddingdilationgroupsr   )inputweightr   r   r   r   r   r   r   r   r      s    r   c                 C   s*   |dkr|S t | |||}t||S d S )Nvalid)int_padding_for_string_paddingr	   pad)r   padding_styler   r   kernel_sizer   r   r   r   conv_input_for_string_padding    s    r%   c                    s|    fdd}|dkrNg }t t| dddddD ]}|t|||| 7 }q.|S |dkrht| dd	d
d S td| dd S )Nc                    s   t  tr |  S  S r   )
isinstancetuple)ir   r   r   get_dilation)   s    z4int_padding_for_string_padding.<locals>.get_dilationsamer   r      r          )r   zgot padding type of z, only accept 'same' or 'valid')ranger   conv_padding_for_sameRuntimeError)r   r#   r   r$   r*   r   r(   r   r)   r   r!   (   s    r!   c                 C   s$   | |d  }|d }|| }||fS )Nr   r,   r   )r   r$   Z	total_padZleft_padZ	right_padr   r   r   r1   8   s    r1   c              
      s   	f
dd}fdd}dd }j j	|j|j|jjf\g tdtdd	d
D ]}	|  qzj	 g }|d  |d  |j
}jrg }	tddd}
t|
D ]H}jd|  }|	|| | | |  |  d  |   qtj }ttjtjtj}||d t|	}j
rtt|D ],}t|d| || d jd|  }qv|| n
|d  |d gd  }tj | tjfdd t|S )Nc              
      sF    t k r(dkr(tj	 S tj		S d S )Nr   )	THRESHOLDconv_group_weight_grad_sampler   conv_unfold_weight_grad_sample)r   

batch_sizectxr   r   grad_outputr   r$   r   r   weight_shaper   r   weight_grad_sampleA   s        z)conv_backward.<locals>.weight_grad_samplec                    s,   t | tr$t | f| | f| | | fS | S d S r   )r&   intr   )param)r   r   r   expandH   s    
zconv_backward.<locals>.expandc                    sR   |r<t | d|| t fddtt d ddD }|S tdd |D S d S )Nr+   c                 3   s"   | ]} |  |d    V  qdS )r   Nr   )r   r(   Zall_paddingr   r   	<genexpr>R   s     z<conv_backward.<locals>.calc_total_padding.<locals>.<genexpr>r   r-   c                 s   s   | ]}d | V  qdS )r,   Nr   )r   r"   r   r   r   r@   U   s     )r!   r'   r0   r   )r   Zwas_samer   r   r$   total_paddingr   r?   r   calc_total_paddingN   s
    &z)conv_backward.<locals>.calc_total_paddingr,      r.      r   r/   c                    s     j  jd d d jddS )Nr,   r-   )Zdim)r-   )reshapeshapesum)_)r9   r   r   <lambda>|       zconv_backward.<locals>.<lambda>)r   rG   r   r   r   r   r0   r   appendr7   Zwas_same_paddingZinput_required_gradZorig_input_shaper   r	   Zconv_transpose1dZconv_transpose2dZconv_transpose3dr'   r   torchnarrowr   r   )r   r8   r9   r;   r>   rC   r(   resultsrB   Zoutput_padding
input_dimsZ	input_dimZweight_Ztranspose_funcoutr   r6   r   conv_backward?   s>    	(

8
*
rR   c	              
      s   j d }	j d }
t| fdd fdd fdd}| ||	dj d }td|}||	|d|t|
| t}td	|	 }|	gt
| }||}|S )
Nr   r   c                      s:   t jddd fd d fdd fdd fdS )NrA   r   r   )r$   r   r   r   )r	   unfoldZ	unsqueezer   r   r   r$   r   r   r   r   rJ      s
   



z0conv_unfold_weight_grad_sample.<locals>.<lambda>c                      s   t j dS )N)r   r   r   )r	   rS   r   rT   r   r   rJ      rK   c                      s   t  S r   )unfold3dr   rT   r   r   rJ      rK   r-   znoq,npq->nopzngrg...->ngr...)rG   r   rF   rM   Zeinsumviewr<   npprod
contiguouslist)r   r9   r:   r$   r   r   r   r   r   nZin_channelsZunfold_funcr;   rG   r   rT   r   r5      s.    



r5   c              	   C   s   | j d }|j d }	| dd}
|j|j d |j d  df|j dd   }||
|d ||||d}t|ddd}td|D ]}||d|| }qz|j|||	f|j dd   }|dd}|S )Nr   r   r,   )r   r   r   r   rD   r.   rE   )rG   	transposerV   r   r0   rN   Zmovedim)r   r9   r:   r   r   r   r7   r   IOZinput_Zgrad_output_r;   rP   r(   r   r   r   r4      s    

,r4   c              
   C   s   t | jdkrtd| j |dkr6td| d| j\}}}}}t| |d |d |d |d |d |d f} | jd|d |d d	} | jd
|d |d d	} | jd|d |d d	} | ddd
ddddd} | |d|t	
| dd} | S )a  
    Extracts sliding local blocks from an batched input tensor.
    :class:`torch.nn.Unfold` only supports 4D inputs (batched image-like tensors).
    This method implements the same action for 5D inputs
    Args:
        tensor: An input tensor of shape ``(B, C, D, H, W)``.
        kernel_size: the size of the sliding blocks
        padding: implicit zero padding to be added on both sides of input
        stride: the stride of the sliding blocks in the input spatial dimensions
        dilation: the spacing between the kernel points.
    Returns:
        A tensor of shape ``(B, C * np.product(kernel_size), L)``, where L - output spatial dimensions.
        See :class:`torch.nn.Unfold` for more details
    Example:
        >>> B, C, D, H, W = 3, 4, 5, 6, 7
        >>> tensor = torch.arange(1, B*C*D*H*W + 1.).view(B, C, D, H, W)
        >>> # xdoctest: +SKIP
        >>> unfold3d(tensor, kernel_size=2, padding=0, stride=1).shape
        torch.Size([3, 32, 120])
    rE   z6Input tensor must be of the shape [B, C, D, H, W]. Got)r   r   r   z	dilation=z not supported.r,   r   r   )Z	dimensionsizesteprD   r.   r/      r-   )r   rG   
ValueErrorNotImplementedErrorr	   r"   rS   ZpermuterF   rW   rX   r\   )Ztensorr$   r   r   r   r7   ZchannelsrI   r   r   r   rU      s(    
 & rU   )Nr   r   r   r   )rM   Ztorch.nn.functionalnnZ
functionalr	   ZnumpyrW   typingr   r   Zexpanded_weights_utilsr   r   r3   r   r   r   r%   r!   r1   rR   r5   r4   rU   r   r   r   r   <module>   s   	
@"