o
    iy                     @   s  d dl Z d dlmZ d dlmZ d dlZd dlmZ eej	d Z
g dZejedfded	ejd
ejdejfddZejeddfded	ejd
ejdeej dejf
ddZdedefddZede
fded	ejd
ejdedeej f
ddZdejdejfddZdS )    N)Path)Optional)	safe_openzhadamards.safetensors)random_hadamard_matrixdeterministic_hadamard_matrixis_pow2cpusizedtypedevicereturnc                 C   s|   | dkrt dtt| }| d| krt dtjdgg||d}t|D ]}tt||ft|| ff}q'|S )a  
    Construct an n-by-n Hadamard matrix, using Sylvester's construction.
    `n` must be a power of 2.

    Adapated from https://github.com/scipy/scipy/blob/v1.15.2/scipy/linalg/_special_matrices.py  # noqa: E501

    :param size: order of the matrix, must be a power of 2
    :param dtype: data type of matrix
    :param device: device to construct matrix on
    :return: hadamard matrix of size `size`
    r   z4Cannot construct deterministic hadamard of size <= 0   z6Cannot construct deterministic hadamard of size != 2^n   r
   r   )	
ValueErrorintmathlog2torchtensorrangevstackhstack)r	   r
   r   r   H_ r   _/home/ubuntu/.local/lib/python3.10/site-packages/compressed_tensors/transform/utils/hadamard.pyr   !   s   &r   genc                 C   s@   t jdd| f||d}|j|d}|d d }t |}t|S )a  
    Produces a randomly generated Hadamard matrix. Differs from
    `deterministic_hadamard_matrix` in that this function supports non powers of 2
    and randomization using a seeded generator

    Adapated from https://github.com/facebookresearch/SpinQuant/blob/main/utils/hadamard_utils.py  # noqa: E501
    Known matrices were retrieved from N. J. A. Sloane's Library of Hadamard Matrices http://www.neilsloane.com/hadamard/  # noqa: E501

    :param size: The dimension of the hamadard matrix
    :param dtype: data type of matrix
    :param device: device to construct matrix on
    :param gen: Optional generator random values
    :return: randomly generated hadamard matrix
    r   r   )lowhighr	   	generatorr
   r   r   )r   randinttodiag_matmul_hadU)r	   r
   r   r   Qr   r   r   r   A   s
   
r   nc                 C   s   | dko| | d @ dkS )zt
    Check if a number is a power of 2

    :param n: number to check
    :return: True iff `n` is a power of 2
    r   r   r   )r'   r   r   r   r   \   s   r   	file_pathc                 C   s   |j dkr
tdn|}t|dt|d<}tdd | D dd}|D ]#}| | d	krHt| | rH|t|j	||d
  W  d   S q%W d   dS 1 sTw   Y  dS )a{  
    Fetch a known hadamard matrix from the given file path. The returned matrix will
    be of of size `k` such that `n / k` is a power of two. Return None if no such
    matrix exists.

    Note: This function reopens the safetensors file every time it is called.
    This is technically inefficient, but a very small runtime cost and simpler
    than forcing callers to manage the file open context

    :param n: size of known hadamard matrix
    :param dtype: data type to move fetched hadamard to
    :param device: device to move fetched hadamard to
    :return: a known hadamard matrix of size `n` if one exists, else None
    metar   pt)	frameworkr   c                 s   s    | ]}t |V  qd S )N)r   ).0keyr   r   r   	<genexpr>|   s    z*_fetch_hadamard_divisor.<locals>.<genexpr>T)reverser   r   N)
typer   r   r   strsortedkeysr   
get_tensorr#   )r'   r
   r   r(   open_devicefiledivisorsdivisorr   r   r   _fetch_hadamard_divisorf   s   
r9   Xc                 C   s  |  d}| j}| j}t|||d}|d u rtd| | d}|  d|d}| }|jd |kr||jd |jd d d|jd }||j}|d d d d dd d f |d d d d dd d f  |d d d d dd d f< |d d d d dd d f |d d d d dd d f  |d d d d dd d f< ||jd |jd d}||}}|jd |ks6|jd |ksJ ~|d|||| }|| jS )Nr   r!   z0Cannot construct random hadamard matrix of size r   r   )	r	   r
   r   r9   r   cloneviewshaper#   )r:   r	   r
   r   hadKKinputoutputr   r   r   r%      s*   

&PP
r%   )r   pathlibr   typingr   r   safetensorsr   __file__parent	REPO_PATH__all__bfloat16r   r   r
   Tensorr   	Generatorr   boolr   r1   r9   r%   r   r   r   r   <module>   s^   	
"

