o
    XiC                     @  s  U d dl mZ g d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
mZ d dlZd dlZd dlZd dlZd dlm  mZ d dlmZ g dZdZdZd	Zeh d
ZedhZeeZdddZ dddZ!dddZ"dddZ#dddZ$G dd  d Z%e% Z&ej'G d!d" d"Z(eej)e*ej) ej+f Z,G d#d$ d$Z-ej.Z/ee(e
ej) ej)df Z0eej1e/e-ge0f Z2ej'G d%d& d&Z3G d'd( d(Z4e4 Z5d(e6d)< e5j7Z7dd-d.Z8	ddd6d7Z9dd9d:Z:dd=d>Z;dd?d@Z<ddAdBZ=dddEdFZ>e7dGddJdKZ?e7dLddMdNZ@e7dOddPdQZAddRdSZBe7dTddUdVZCe7dWddXdYZDe7dZdd[d\ZEe7d]dd^d_ZFe7d`ddadbZGe7dcddddeZHe7dfddgdhZIe7diddjdkZJe7dlddmdnZKe7doddpdqZLe7drdsdtddudvZMe7dwddxdyZNe7dzdd{d|ZOe7d}dd~dZPe7ddddZQdddZRdddZSG dd dejTjUZVdddZWdddZXej'G dd dejTjYZZdeedd ddddZ[dS )    )annotations)basic_constant_propagationfold_constantsFoldConstantsPassFOLDED_FROM_KEYN)AnyCallableIterableSequenceUnion)_tape)ConstantOfShapeQuantizeLinearDequantizeLineari    i   z$pkg.onnxscript.optimizer.folded_from>   MultinomialRandomNormalRandomUniformRandomNormalLikeRandomUniformLike) 	Transposenodeir.Nodereturnboolc                   s,   t jjt jjh t fdd| j D S )Nc                 3  s    | ]}|j  v V  qd S N)type).0attrgraph_types Z/home/ubuntu/.local/lib/python3.10/site-packages/onnxscript/optimizer/_constant_folding.py	<genexpr>D       z&_is_control_flow_op.<locals>.<genexpr>)irAttributeTypeGRAPHGRAPHSany
attributesvaluesr   r!   r   r"   _is_control_flow_opB   s   r-   c                 C  s   | j tv o
t| jS r   )op_type_NON_DETERMINISTIC_OPSutilsis_onnx_domaindomainr,   r!   r!   r"   _is_non_deterministic_opG      r3   r.   strc                 C  s   | j |ko
t| jS r   )r.   r0   r1   r2   )r   r.   r!   r!   r"   _is_onnx_opK   r4   r6   Nonec                 C  s(  t | dsdS t| jdkrdS tt| j \}}t| jdkr$dS | jd }|du s3t|tj	s5dS |j
du r<dS |dv rPtjtj|j
tjd|jd}n7|dv rdtjtj|j
tjd|jd}n#|d	v rxtjtj|j
tjd|jd}n|d
krttj|j
}ndS ||_|j|_|j|_dS )z7Sets const_value of output value of a Constant op node.ConstantN   r   >   value_floatvalue_floats)dtypename>   	value_int
value_ints>   value_stringvalue_stringsvalue)r6   lenr*   nextiteritemsoutputs
isinstancer%   AttrrC   Tensornparrayfloat32r>   int64StringTensorbytes_typingcastTensorProtocolconst_valueshaper<   )r   	attr_name
attr_valueir_valuerU   r!   r!   r"   _process_constant_nodeU   s8   


 rZ   nodesIterable[ir.Node]c                 C  s   | D ]}t | qdS )zPerforms basic constant propagation for a sequence of nodes.

    Just marks the output values of Constant op nodes with their const_value.
    N)rZ   )r[   r   r!   r!   r"   r   ~   s   
r   c                   @  s    e Zd Zddd	ZdddZdS )ReferenceEvaluatorr2   r5   opversionintr   Callable | Nonec                 C  s0   zt jj|||}|jW S  ty   Y d S w r   )onnx	referenceopsload_opeval	Exception)selfr2   r^   r_   op_impl_classr!   r!   r"   get_evaluator   s   z ReferenceEvaluator.get_evaluatorr   c              
   O  sl   t d|| | |||}|d u rd S z||i |W S  ty5 } zt d| W Y d }~d S d }~ww )NzEvaluating %s::%szEvaluation failed: %s)loggerdebugrj   rg   warning)rh   r2   r^   r_   argskwargs	evaluatorer!   r!   r"   evaluate   s   zReferenceEvaluator.evaluateN)r2   r5   r^   r5   r_   r`   r   ra   )r2   r5   r^   r5   r_   r`   r   r   )__name__
__module____qualname__rj   rr   r!   r!   r!   r"   r]      s    
r]   c                   @  s"   e Zd ZU dZded< ded< dS )Replacementz&A replacement for a node in the graph.Sequence[ir.Value]new_outputszSequence[ir.Node]	new_nodesN)rs   rt   ru   __doc____annotations__r!   r!   r!   r"   rv      s   
 rv   c                   @  s@   e Zd Zdd ZedddZdd
dZdddZdddZdS )OptimizerStatec                 C  s   i | _ g | _d S r   )_sym_value_map_initializer_inputsrh   r!   r!   r"   __init__   s   
zOptimizerState.__init__r   dict[ir.Value, SymbolicValue]c                 C     | j S r   r}   r   r!   r!   r"   symbolic_value_map   s   z!OptimizerState.symbolic_value_maprC   ir.Value | NoneSymbolicValue | Nonec                 C  s   |d u rd S | j |S r   )r}   get)rh   rC   r!   r!   r"   get_sym_value   s   zOptimizerState.get_sym_valueir.Value	sym_valueSymbolicValuer7   c                 C  s   || j |< d S r   r   )rh   rC   r   r!   r!   r"   set_sym_value   s   zOptimizerState.set_sym_valueir.Shape | Nonec                 C  sT   t |tjjdd}|d ur|jdkrt| S d S | |}t|tjr(|S d S )N
   
size_limitr9   )	_get_numpy_valuer%   DataTypeINT64ndimShapetolistr   rI   )rh   rC   rU   r   r!   r!   r"   get_shape_value   s   

zOptimizerState.get_shape_valueN)r   r   )rC   r   r   r   )rC   r   r   r   r   r7   )rC   r   r   r   )	rs   rt   ru   r   propertyr   r   r   r   r!   r!   r!   r"   r|      s    

r|   c                   @  s4   e Zd ZU dZded< ded< ded< dddZdS )PartialEvaluatora  A class that represents a partial-evaluator for a particular op.

    It is applicable for a specific version range (min_version, max_version) of the op.
    The min_version and max_version can be None, indicating that there is no version
    constraint in that direction.
    
int | Nonemin_versionmax_versionPartialEvaluatorFunctionfunctionr_   r`   r   r   c                 C  s(   | j du s
|| j ko| jdu p|| jkS )zCReturns True if this evaluator is applicable for the given version.N)r   r   )rh   r_   r!   r!   r"   	valid_for   s   zPartialEvaluator.valid_forN)r_   r`   r   r   )rs   rt   ru   rz   r{   r   r!   r!   r!   r"   r      s   
 r   c                   @  s0   e Zd ZdZdd Zdd	d
Z	ddddZdS )PartialEvaluatorRegistryz8A class that maintains a registry of evaluators for ops.c                 C  s
   i | _ d S r   )op_evaluatorsr   r!   r!   r"   r      s   
z!PartialEvaluatorRegistry.__init__r2   r5   opnamer_   r`   c                   s$   | j ||fg } fdd|D S )Nc                   s   g | ]
}|  r|jqS r!   )r   r   )r   rp   r_   r!   r"   
<listcomp>   s
    
z>PartialEvaluatorRegistry.lookup_evaluators.<locals>.<listcomp>)r   r   )rh   r2   r   r_   evaluator_listr!   r   r"   lookup_evaluators   s   
z*PartialEvaluatorRegistry.lookup_evaluatorsr   Nr   >Callable[[PartialEvaluatorFunction], PartialEvaluatorFunction]c                   s~   ||f| j v r| j ||f  n	g   | j ||f< |d u r!d d nt|tr+||n	t|tr4|\d fdd}|S )Nr   r   r   c                   s     t|  | S r   )appendr   )r   r   r   r   r!   r"   	decorator  s   z4PartialEvaluatorRegistry.register.<locals>.decorator)r   r   r   r   )r   rI   r`   tuple)rh   r   r2   r_   r   r!   r   r"   register   s   

z!PartialEvaluatorRegistry.register)r2   r5   r   r5   r_   r`   )r   N)r   r5   r2   r5   r   r   )rs   rt   ru   rz   r   r   r   r!   r!   r!   r"   r      s    
r   registryshape1ir.Shapeshape2c                 C  s"   t dd | D rdS | j|jkS )Nc                 s  s&    | ]}t |tjo|jd u V  qd S r   rI   r%   SymbolicDimrC   )r   dimr!   r!   r"   r#   !  s   $ z_same_shape.<locals>.<genexpr>F)r)   dims)r   r   r!   r!   r"   _same_shape  s   r   valr   r<   ir.DataType | Noner   r   np.ndarray | Nonec                 C  s   | du rdS | j }|durT|dur|j|krdS |dur#|j|kr#dS z| }|jtjjkr7||j }W n tyI   t	
d| j Y dS w t|tjsRJ |S dS )zReturns the numpy value of a constant value, if available.

    It returns None if the value is not a constant value, or if the value is not of
    the specified element dtype, or if the size of the value exceeds the specified
    size_limit.
    Nz[External data for value '%s' is not available. This may lead to incorrect constant folding.)rU   r<   sizenumpyr%   r   STRINGviewFileNotFoundErrorrk   rm   r>   rI   rL   ndarray)r   r<   r   rU   rM   r!   r!   r"   r   &  s.   	r   bool | Nonec                 C  sB   | d u rd S t | }|d u rd S |jdkr|jtkr|dS d S Nr9   r   )r   r   r<   r   item)r   rC   r!   r!   r"   _get_bool_valueQ  s   
r   indexr`   c                 C     |t | jk r| j| S d S r   )rD   inputsr   r   r!   r!   r"   
_get_input\     
r   c                 C  r   r   )rD   rH   r   r!   r!   r"   _get_outputb  r   r   c                 C  s0   t | |}|d ur|jd ur|jjjS tjjjS r   )r   r   r<   rC   r%   r   	UNDEFINED)r   r   inputr!   r!   r"   _get_input_element_typeh  s   


r   r>   defaultc                 C  s@   || j v r| j | }t|tjsd S |j}t|tr|S d S |S r   )r*   rI   r%   rJ   rC   r`   )r   r>   r   r   attr_valr!   r!   r"   _get_int_attributeo  s   


r   AddstateReturnValuec                   s    fdd}|d}|d}|du s|du rdS t |tr(t |tr(|| }n
t| d| }t d}|durG|t|g dS dS )zPropagate symbolic dim values.c                   sT   t  | }|d u rd S |}|d u st|dkrd S |d }t|tr'|S |jS r   )r   r   rD   rI   r`   rC   )input_indexr   shape_valuer   r   r   r!   r"   get_dim_value  s   

zadd.<locals>.get_dim_valuer   r9   N+)rI   r`   r%   r   r   r   r   )r   r^   r   r   dim0dim1result_dim_valueoutputr!   r   r"   add}  s   


r   Absc                 C  s@   t | d}||}|du rdS tdd |D rdS ||S )zoReplace an Abs node by Identity when applicable.

    Currently, addresses Abs applied to symbolic shapes.
    r   Nc                 s  s"    | ]}t |to|d k V  qdS )r   NrI   r`   r   dr!   r!   r"   r#          zabs.<locals>.<genexpr>)r   r   r)   Identity)r   r^   r   r   input_sym_valuer!   r!   r"   abs  s   


r   Gatherc           	        s   t | d}t | d}|du s|du rdS ||  du rdS t| dd}|dkr+dS t|}|du r5dS |jdkr<dS  fdd|D }t| d}|durW||t| t	dd |D rj|j
td	|d
S dS )z|Replace a Gather node by a constant when applicable.

    Currently, handles the case of Gathering from a shape tensor.
    r   r9   Naxisc                   s   g | ]} | qS r!   r!   r   ir   r!   r"   r         zgather.<locals>.<listcomp>c                 s      | ]}t |tV  qd S r   r   r   r!   r!   r"   r#     r$   zgather.<locals>.<genexpr>r@   r@   )r   r   r   r   r   r   r   r%   r   allr8   
AttrInt64s)	r   r^   r   r   indicesr   indices_numpy_valuegatheredr   r!   r   r"   gather  s,   




r   c                 C  s>   t | d}||}t| d}|dur|dur||| dS )zPropagates symbolic shape value of input 0 to output 0.

    Applies to ops like Reshape/Squeeze/Unsqueeze where the shape of the tensor may change
    but the values in the tensor remain the same.
    r   N)r   r   r   r   )r   r^   r   r   input_shape_valuer   r!   r!   r"   _propagate_shape_value  s   


r   Reshapec                 C  st   t | d}t | d}|du s|du rdS |j}||}|du s$|du r*t| ||S t||r4||S t| ||S )zcReplace a Reshape node by Identity when applicable.

    Also propagate symbolic shape values.
    r   r9   N)r   rV   r   r   r   r   )r   r^   r   r   rV   input_shaper   r!   r!   r"   reshape  s   




r   Squeezec                 C  s   t | ||S )z Propagate symbolic shape values.)r   )r   r^   r   r!   r!   r"   squeeze  s   r   Castc                 C  sn   t | d}t| d}|d u s|d u rd S t| d}t| dd }|d ur5||kr,||S tt||_d S )Nr   to)	r   r   r   r   r   r%   
TensorTyper   r   )r   r^   r   r   r   input_dtypeoutput_dtyper!   r!   r"   rS     s   



rS   CastLikec                 C  sN   | j d }t| d}t| d}|tjjkrd S ||kr ||S |j||dS )Nr   r9   )r   )r   r   r%   r   r   r   r   )r   r^   r   input0source_element_typetarget_element_typer!   r!   r"   	cast_like  s   



r  r   c           	      C  s   | j d }|d u rd S |j}|d u rd S t| dd}t| dd }||| }t| d}|d ur8||t| tdd |D rM|jt	dt
|dS d S )Nr   startendc                 s  r   r   r   r   r!   r!   r"   r#     r$   zshape.<locals>.<genexpr>r@   r   )r   rV   r   r   r   r%   r   r   r8   r   list)	r   r^   r   r   rV   r  r  shape_slicer   r!   r!   r"   rV     s   

rV   Sizec                 C  sZ   t | d}|d u rd S |j}|d u rd S d}|D ]}t|ts" d S ||9 }q|j|dS )Nr   r9   r?   )r   rV   rI   r`   r8   )r   r^   r   r   rV   r   r   r!   r!   r"   r   $  s   


r   Ifc                   s   t | d}t|}|d urz|rdnd}| j|}|d u rd S |jtjjkr(d S t|tj	s0J |
 }t|j}|j  | j}	dd t||	D   fdd}
t|}|| |D ]}|jD ]}|
|j|_qa| j d|j |_q\t||S d S )	Nr   then_branchelse_branchc                 S  s"   i | ]\}}|d ur|j |j qS r   r=   )r   formalactualr!   r!   r"   
<dictcomp>F  s
    zif_op.<locals>.<dictcomp>c                   s     | | S r   )r   r=   	renamingsr!   r"   renameM  s   zif_op.<locals>.rename_)r   r   r*   r   r   r%   r&   r'   rI   rJ   as_graphr  rH   clearzipremover>   rv   )r   r^   r   
cond_inputcondbranch
graph_attrgraphformal_outsactual_outsr  graph_nodessub_nodevr!   r  r"   if_op4  s4   





r"  r   c                 C  s   ~| j d }| jd }|d urN|d urNz
t|j|j|_W n! ty> } ztd| j|j	t
t | W Y d }~nd }~ww |jd u rH|j|_||| d S )Nr   zb[Constant folder] Cannot merge shapes on Identity node '%s' (folded from: %s) because of error: %s)r   rH   _merge_shapesrV   rg   rk   rm   r>   metar   r   setr   r   )r   r^   r   r   r   rq   r!   r!   r"   identity^  s&   


r&  SequenceConstructc                 C  s*   ~| j d }|d ur||t| j d S )Nr   )rH   r   r  r   )r   r^   r   r   r!   r!   r"   sequence_constructu  s
   
r(  Concatc                   s  | j }t|dkr||d S t| dd  du rdS d fd	d
fdd|D }t|t|krV|rEtd|| |j|d iS |rTtd| ||d S dS  dkr\dS fdd|D }tdd |D rpdS t	dd |D }| j
d }|du rdS || dS )z5Replace a Concat node with a single input by Identityr9   r   r   Noperandr   r   r   c                   sF   | d u rdS | j  }d u rdS z	|  }W |dkS  ty"   Y dS w )NFr   )rV   
IndexError)r*  rV   dim_size)r   r!   r"   has_zero_size  s   
zconcat.<locals>.has_zero_sizec                   s   g | ]} |s|qS r!   r!   r   x)r-  r!   r"   r         zconcat.<locals>.<listcomp>z0Concat: removing zero-length operand(s) %s => %sz,Concat: removing all zero-length operands %sc                   s   g | ]}  |qS r!   )r   )r   r   )r   r!   r"   r     s    c                 s      | ]}|d u V  qd S r   r!   )r   rV   r!   r!   r"   r#         zconcat.<locals>.<genexpr>c                 s  s     | ]}|j D ]}|V  qqd S r   )r   )r   rV   r   r!   r!   r"   r#         )r*  r   r   r   )r   rD   r   r   rk   rl   r)  r)   r%   r   rH   r   )r   r^   r   r   
new_inputsshapesconcatenatedr   r!   )r   r-  r   r"   concat~  s:   
r7  Dropout)   Nr   c                   s    fdd} j }t|dks|d du r| S t|d du r$| S t|d }|du r0dS |jdkr7dS | dkr@| S dS )z.Replace a Dropout by Identity when applicable.c                    sR    j d } | }t jdkr|S tdg}| }j||d}||fS )Nr   r9   T)rC   )r   r   rD   rH   r%   tensorr   r   )r   r   true_tensorr   maskr   r^   r!   r"   optimized_dropout  s   


z"dropout.<locals>.optimized_dropout   NFr9   r   )r   rD   r   r   r   r   )r   r^   r   r>  r   ratior!   r=  r"   dropout  s   
rA  Expandc                 C  s   t | jdkr	dS | jd  }du rdS |j }du rdS t| jd  }du r@|| jd }|du s9t||s;dS ||S |jdkrGdS |jt	|
 krU||S dS )z3Replace an Expand node by Identity when applicable.r?  Nr   r9   )rD   r   rV   r   r   r   r   r   r   r   r   )r   r^   r   r   r   expanded_shapeexpanded_sym_shaper!   r!   r"   expand  s    


rE  ConcatFromSequencec                 C  s  | j d }||}|d u stdd |D rd S t| dd}t| dd }|d u r+d S |d urt|tr|dkrKtddd |D  |j|d|iS |d	kr|j	|d
}g }|D ]}	|j
|	||	j dgd}
||
 qYtddd |D  |j|d|iS d S )Nr   c                 s  r1  r   r!   r.  r!   r!   r"   r#     r2  z'concat_from_sequence.<locals>.<genexpr>new_axisr   z ConcatFromSequence => Concat: %sc                 S     g | ]}|j qS r!   r=   r.  r!   r!   r"   r         z(concat_from_sequence.<locals>.<listcomp>r9   r	  
_unsqueeze_outputszConcatFromSequence => Concat %sc                 S  rH  r!   r=   r.  r!   r!   r"   r     rI  )r   r   r)   r   rI   r  rk   rl   r)  r8   	Unsqueezer>   r   )r   r^   r   r   r   rG  r   
axis_valueunsqueezed_inputs
node_inputunsqueezed_inputr!   r!   r"   concat_from_sequence  s2   

rR  SplitToSequencec                   s  | j d }t| j dkrdS | j d }| jd  |du s$|du s$ du r&dS t| dd}|du r2dS |j}|du r;dS t|}|dk rG|| }|dk sO||krQdS t|}|jdurd|j rd|j nd}	|du rp|	du rpdS t|	t	rt|	dkr|	d }
t|
t
sJ |
} fddt|D }|j||||d}nM|jdkr|j} fddt|D }|j||||d}n0|jdkr|| }
t|
t
sdS t|
|  } fd	dt|D }|j||||d
}ndS t|tjr|g}t| dd}|du rdS |dkr2|j|g j dgd}g }t|D ]}|j|| |||  dgd}|| q|}td t|tjrA|g}|j| S )a  Rewriting pattern.

    From

        splits = onnx::SplitToSequence(input, split, axis=axis)

    to

        split_0, split_1, ..., split_n = onnx::Split(input, split, axis=axis)
        splits = onnx::SequenceConstruct(split_0, split_1, ..., split_n)

    or

        split_0, split_1, ..., split_n = onnx::Split(input, axis=axis, num_outputs=n+1)
        splits = onnx::SequenceConstruct(split_0, split_1, ..., split_n)

    where number of output tensors in `splits` is statically known.
    onnx::SequenceConstruct will be further optimized away if possible, by its own designated evaluator.
    This allows downstream `SequenceAt` users to be replaced by `split_x` accordingly.
    r   r9   Nr   c                      g | ]
} j  d | qS _split_r=   r   r   r!   r"   r   S      z%split_to_sequence.<locals>.<listcomp>)r   rL  c                   rT  rU  r=   r   rW  r!   r"   r   X  rX  c                   rT  rU  r=   r   rW  r!   r"   r   `  rX  )r   num_outputsrL  keepdims_axis)r@   rL  _squeezerK  z,SplitToSequence => Split + SequenceConstruct)r   rD   rH   r   rV   r   	is_staticr   rI   r   r`   rangeSplitr   r   mathceilr   r%   Valuer8   r>   r   r   rk   rl   r'  )r   r^   r   r   splitr   rV   ranksplit_valuesplit_shapesplit_dimension_sizerY  split_outputssplit_valuesrZ  axis_valsqueezed_valuesr   squeezedr!   rW  r"   split_to_sequence  sz   


	 





rm  
SequenceAtc           	      C  s   | j d }| j d }| jd }|d urY|d urY||}t|}t|trY|d urY|jdkr0d S | }z|| }W n
 tyD   Y d S w |	|| t
d|j|j ||S d S )Nr   r9   zSequenceAt %s => %s)r   rH   r   r   rI   r  r   r   r+  r   rk   rl   r>   r   )	r   r^   r   r   positionr   
input_valsposition_valresultr!   r!   r"   sequence_at  s&   





rs  preferred_shaper   other_shapec                   sb   dd  | du r
|S |du r| S t | t |kr"td|  d| t fddt| |D S )z>Merge two shapes, preferring dimensions from preferred_shapes.c                 S  s>   | |kr| S t | tjs| S t |tjs|S | jd u r|S | S r   r   )r   dim2r!   r!   r"   
merge_dims  s   
z!_merge_shapes.<locals>.merge_dimsNz4Shapes must have the same rank, got preferred_shape=z, other_shape=c                   s   g | ]	\}} ||qS r!   r!   )r   r   rv  rw  r!   r"   r         z!_merge_shapes.<locals>.<listcomp>)rD   
ValueErrorr%   r   r  )rt  ru  r!   rx  r"   r#    s   r#  original_nodereplacementc                 C  s   t  }| jD ]}|du rq||jtt   |jdusJ ||j q|jD ]}|du r0q)||jt< t	t
||jt< q)dS )zXRecord the set of original input values that contributed to the constant-folded outputs.N)r%  r   updater$  r   r   r>   r   rx   reprsortedmetadata_props)r{  r|  folded_fromr   
new_outputr!   r!   r"   _record_contributing_values  s   


r  c                   @  s   e Zd ZdZdd ddBddZdCddZdDddZdEddZdFdd ZdGd"d#Z	dHd&d'Z
dId,d-ZdJd0d1ZdKd2d3ZdLd6d7ZdMd:d;ZdNd?d@ZdAS )Or   a6  A pass that folds constant expressions in the model.

    Attributes:
        shape_inference: Whether to perform shape inference.
        input_size_limit: Maximum size of input tensors to fold.
        output_size_limit: Maximum size of output tensors to fold.
        should_fold: An optional function that takes a node and returns True if
            the node should be considered for folding.
            The function should return True/False value to indicate if this particular
            node should be folded, or None to use the default folding rules.
    c                 C     d S r   r!   r,   r!   r!   r"   <lambda>      zFoldConstantsPass.<lambda>)should_foldshape_inferencer   input_size_limitr`   output_size_limitr   Callable[[ir.Node], bool | None]r   r7   c                C  sD   || _ || _|| _|| _i | _i | _i | _d| _t | _	| 
  d S )NF)r  r  r  r  _opset_imports_counts_sizes	_modifiedr|   _state_reset)rh   r  r  r  r  r!   r!   r"   r     s   zFoldConstantsPass.__init__c                 C  s   i | _ i | _d| _t | _dS )z$Reset internal states for a new run.FN)r  r  r  r|   r  r   r!   r!   r"   r    s   zFoldConstantsPass._resetr   r   c           
   
     s4  i }ddd dd	d
fdd|j D } fdd|j D }dd | D }tdd | D r=td|j d S zBtj	|j
| j|j |j}tj|tj|||}|jD ] }|j|v r|||j }tj|}t|j||_tj||_q\W d S  ty }	 ztd||	 W Y d }	~	d S d }	~	ww )Nr/  r   r   onnx.TensorProto | Nonec                 S  s4   t | dd}|d ur| jd usJ tj| jS d S )N   r   )r   rU   r%   serdeserialize_tensor)r/  rC   r!   r!   r"   get_constant_value  s
   z;FoldConstantsPass._do_inference.<locals>.get_constant_valuerC   onnx.TypeProto | Nonec                 S  s:   | j d urtj| j }| jd urtj|| j |S d S r   )r   r%   r  serialize_typerV   serialize_shape_into)rC   
type_protor!   r!   r"   get_type  s   

z1FoldConstantsPass._do_inference.<locals>.get_typec                       i | ]}|d ur|j  |qS r   r=   r.  )r  r!   r"   r          z3FoldConstantsPass._do_inference.<locals>.<dictcomp>c                   r  r   r=   r.  )r  r!   r"   r    r  c                 S  s   i | ]\}}|d ur||qS r   r!   )r   kr!  r!   r!   r"   r        c                 s  r1  r   r!   )r   tr!   r!   r"   r#     r2  z2FoldConstantsPass._do_inference.<locals>.<genexpr>z?Skipping shape inference for node %r due to missing input type.z9Skipping shape inference for node %r due to exception: %s)r/  r   r   r  )rC   r   r   r  )r   rG   r)   r+   rk   rl   r>   rb   defs
get_schemar.   r  r2   r  infer_node_outputsr%   r  serialize_noderH    deserialize_type_proto_for_shaper#  rV   deserialize_type_proto_for_typer   rg   )
rh   r   output_typesinput_types
input_dataschemar   inferred_typeinferred_shaperq   r!   )r  r  r"   _do_inference  sN   






zFoldConstantsPass._do_inferenceoutput_namer5   output_arraynp.ndarray | Anyir.Tensor | Nonec           	      C  s   t |tjstd|t| dS t|}||_|j	| j
krSd}|jD ]}|dur?t| dkr?t|}|dur?||j	7 }q$|j	| }|dkrStd||j	 dS |S )a4  
        Shared helper for constant/init creation:
        - Validates the folded Python value is a numpy ndarray.
        - Wraps it in an ir.Tensor and names it.
        - Applies output_size_limit logic with input-usage compensation.
        Returns the ir.Tensor or None if it should be skipped.
        zASkip storing constant folded value %s due to unsupported type %s.Nr   r9   z;Skip storing constant folded array %s due to large size %s.)rI   rL   r   rk   infor   r%   r:  r>   r   r  r   rD   usesr   )	rh   r   r  r  r:  removed_input_size	input_valinput_arrayincreased_sizer!   r!   r"   _prepare_folded_tensor%  s4   




z(FoldConstantsPass._prepare_folded_tensorrM   ir.Node | Nonec                 C  s\   |j d }| ||j|}|du rdS td|j|j|j tjddg t	d|fd}|S )z=Create a new Constant node with the given array as its value.r   Nz-New constant for value %s dtype: %s shape: %sr   r8   rC   )r   r*   )
rH   r  r>   rk   rl   r<   rV   r%   Node
AttrTensor)rh   r   rM   original_valuer:  r!   r!   r"   new_constantM  s   
zFoldConstantsPass.new_constantr   c                 C  sd   |j d }| ||j|}|du rdS tj|jtt|j|j|d}t	
d|j|j|j |S )zACreate a new initializer value with the given array as its value.r   N)r>   r   rV   rU   z0New Initializer for value %s dtype: %s shape: %s)rH   r  r>   r%   rb  r   r   r<   rV   rk   rl   )rh   r   rM   r  r:  initializerr!   r!   r"   new_initializer_  s"   
z!FoldConstantsPass.new_initializeris_functionReplacement | Nonec                   s  t |jD ]$\}}j|}t|tjr)td|j	|j	|j	 |
|| d_qt|dr4t| njr@t|s@| |jjvrQtd|j	|j dS j|j }t|j|j|}|D ]O}|shJ t }	z	|||	j}
W n ty } ztd|j	d|j d|j d	|d}~ww |
durt|
tr|
  S t|
tjr|
g}
t|
|	j  S qbt|drtd
|j	 dS t|rtd|j	|j|j dS t|rtd|j	|j|j dS tdd |jD rtd|j	 dS tdd |jD rdS |}|du rtd|j	 dS |du rtD ]}t||r/td|j	|  dS qdd |jD }fdd|D }t|rt |jt |ksSJ |j|jft!v rkt"dd t#|j|D rknt$t%j&rdd |D }td|| dS ntd|j	 dd |jD }dd   fdd|j'( D }t)j*|j|j|g|R i |}|du rdS t |j+d krt|t,t-fs|r.||}|du rdS t|j+|gS /||}|du rdS |j0dusJ |j01| t|gg S t2d!|j dS )"zDProcess a node and return a Replacement if the node can be replaced.z%Node [%s]: Replacing input %s with %sTr8   zPSkipping constant folding for node %r due to missing opset import for domain %r.Nz'Error during constant folding for node z (z::)z.Skipping constant folding for Constant node %rzYSkipping constant folding for control flow op %r (%s::%s) because it is not supported yetz>Skipping constant folding for non-deterministic op %r (%s::%s)c                 s  s     | ]}|d ur|  V  qd S r   )is_graph_inputr.  r!   r!   r"   r#     r3  z1FoldConstantsPass.process_node.<locals>.<genexpr>z[Skipping constant folding for node %r because it is graph input to preserve graph signaturec                 s  s"    | ]}|d ur|j d u V  qd S r   rU   r.  r!   r!   r"   r#     r   FzHSkipping constant folding for node %r because should_fold returned FalsezHSkipping constant folding for node %r because %s is preserved by defaultc                 S  s   g | ]}|d ur|j nd qS r   r  r.  r!   r!   r"   r     r  z2FoldConstantsPass.process_node.<locals>.<listcomp>c                   s    g | ]}|d uo|j  jkqS r   )r   r  r   r:  r   r!   r"   r     s    c                 s  s2    | ]\}}|d urt | dkp| V  qd S )Nr9   )rD   	consumers)r   r   is_larger!   r!   r"   r#     s    c                 S  s   g | ]	}|d ur|j qS r   )r   r  r!   r!   r"   r     s    zBSkipping constant folding for node %r due to large input sizes: %sz:Constant folding node %r because should_fold returned Truec                 S  s   g | ]}t |qS r!   )r   r.  r!   r!   r"   r     r   c                 S  s"   | j tjjkrtj| jS | jS r   )r   r%   r&   TENSORr  r  rC   )avr!   r!   r"   convert  s   z/FoldConstantsPass.process_node.<locals>.convertc                   s   i | ]	\}}| |qS r!   r!   )r   r>   r   )r  r!   r"   r    ry  z2FoldConstantsPass.process_node.<locals>.<dictcomp>r9   z:Skipping constant folding for op %s with multiple outputs.)3	enumerater   r  r   rI   r%   rb  rk   rl   r>   replace_input_withr  r6   rZ   r  r-   r  r2   r  r   r   r.   RewriterContextrg   RuntimeErrorrv   r[   r  r3   r)   r  DEFAULT_CONSTANT_FOLD_BLACKLISTrD   _DEFAULT_ALWAYS_FOLD_OPSr   r  isEnabledForloggingINFOr*   rG   _reference_evaluatorrr   rH   r   r  r  r  r  register_initializerrm   )rh   r   r  r   rC   r   r_   op_optimizers	optimizercontextr   rq   r  r.   input_tensorslarge_inputsinput_sizesinput_valuesattr_valuesrH   r|  new_initializer_valuer!   )r  rh   r"   process_nodew  s  







	





 

zFoldConstantsPass.process_noder|  rv   rootir.Graph | ir.Functionc                 C  sz   t d|j|j|j t|| dd |jD }tj	|||g|j
|j|j t|tjr8|jd u s4J t| d| _d S )NzReplacing node: %s::%s %sc                 S  s   g | ]}|d ur|qS r   r!   )r   r!  r!   r!   r"   r   0  r0  z2FoldConstantsPass.replace_node.<locals>.<listcomp>T)rk   rl   r2   r.   r>   r  r   r%   conveniencereplace_nodes_and_valuesry   rH   rx   rI   Graphr  _clear_unused_initializersr  )rh   r   r|  r  node_inputsr!   r!   r"   replace_node&  s   

zFoldConstantsPass.replace_noder   ir.Attrc                 C  sZ   |  rd S |jtjjkr| |  d S |jtjjkr)| D ]	}| | q!d S d S r   )	is_refr   r%   r&   r'   visit_graphr  r(   	as_graphs)rh   r   r  r!   r!   r"   visit_attribute@  s   z!FoldConstantsPass.visit_attributec                 C  sR   t |tj}| j||d}|d u r |j D ]}| | qd S | ||| d S )N)r  )rI   r%   Functionr  r*   r+   r  r  )rh   r   r  r  r|  r   r!   r!   r"   
visit_nodeI  s   zFoldConstantsPass.visit_noder  ir.Graphc                 C  sx   |D ]}|  || qt|jD ])\}}|d u rq| j|}t|tjs&qt|||s-q|j	|_	||j|< d| _
qd S )NT)r  r  rH   r  r   rI   r%   rb  #_sym_value_can_replace_graph_outputr>   r  )rh   r  r   r   r   r   r!   r!   r"   r  T  s   
zFoldConstantsPass.visit_graphr   ir.Functionc                 C  s   |D ]}|  || qd S r   )r  )rh   r   r   r!   r!   r"   visit_functionh  s   z FoldConstantsPass.visit_functionmodelir.ModelFoldConstantsResultc                 C  sH   |    |j| _| |j |j D ]}| | qt|| j	| j
jS r   )r  opset_importsr  r  r  	functionsr+   r  r  r  r  r   )rh   r  r   r!   r!   r"   calll  s   zFoldConstantsPass.callN)
r  r   r  r`   r  r`   r  r  r   r7   )r   r7   r   r   r   r7   )r   r   r  r5   r  r  r   r  )r   r   rM   r  r   r  )r   r   rM   r  r   r   )r   r   r  r   r   r  )r   r   r|  rv   r  r  r   r7   )r   r  r   r7   )r   r   r  r  r   r7   )r  r  r   r7   )r   r  r   r7   )r  r  r   r  )rs   rt   ru   rz   r   r  r  r  r  r  r  r  r  r  r  r  r  r!   r!   r!   r"   r     s"    


8
(

 
0

	

r   r  r  r   r   r   c                 C  s2   |   }d u r
dS |j| urdS | rdS dS )NFT)producerr  is_graph_output)r  r   r   r  r!   r!   r"   r  v  s   
r  r+   rw   c                 C  sh   | D ]/}|d u s|  sq| s1| s1|  sJ |jd us"J |jd us)J |jj|j qd S r   )is_initializerr  r  r  r>   initializerspop)r+   rC   r!   r!   r"   r    s   r  c                   @  s    e Zd ZU ded< dddZdS )	r  r   r   r   r   c                 C  r   r   )modifiedr   r!   r!   r"   __bool__  s   zFoldConstantsResult.__bool__N)r   r   )rs   rt   ru   r{   r   r!   r!   r!   r"   r    s   
 r  Fc                 C  r  r   r!   r,   r!   r!   r"   r    r  r  )onnx_shape_inferencer  r  r  r  r  r  r  r  r  r  c                C  s   t ||||d}|| S )a  
    Applies constant folding optimization to the model.

    Args:
        model: The ONNX model to optimize.
        onnx_shape_inference: Whether to enable ONNX shape inference during
            constant folding. Defaults to False.
        input_size_limit: The maximum size of input tensors
            that can be considered for constant folding. Defaults to
            `DEFAULT_CONSTANT_FOLD_INPUT_SIZE_LIMIT`.
        output_size_limit: The maximum size of output tensors
            that can be stored after constant folding. Defaults to
            `DEFAULT_CONSTANT_FOLD_OUTPUT_SIZE_LIMIT`.
        should_fold: An optional function that takes a node and returns True if
            the node should be considered for folding, False if it should not be folded,
            or None to use the default rules. Defaults to a function that always returns None.

    Returns:
        An instance of `FoldConstantsResult`.

    )r  r  r  r  )r   )r  r  r  r  r  folder_passr!   r!   r"   r     s   r   )r   r   r   r   )r   r   r.   r5   r   r   r  )r[   r\   r   r7   )r   r   r   r   r   r   )NN)r   r   r<   r   r   r   r   r   )r   r   r   r   )r   r   r   r`   r   r   )r   r   r   r`   r   r`   r   )r   r   r>   r5   r   r   r   r   )r   r   r   r|   r   r   )rt  r   ru  r   r   r   )r{  r   r|  rv   r   r7   )r  r  r   r   r   r   r   r   )r+   rw   r   r7   )r  r  r  r   r  r`   r  r`   r  r  r   r  )\
__future__r   __all__dataclassesr  r`  rR   r   r   r	   r
   r   r   rL   rb   onnx.reference.opsonnx_irr%   onnxscript.utils.utilsr0   onnxscript.irr   r  &DEFAULT_CONSTANT_FOLD_INPUT_SIZE_LIMIT'DEFAULT_CONSTANT_FOLD_OUTPUT_SIZE_LIMITr   	frozensetr/   r  	getLoggerrs   rk   r-   r3   r6   rZ   r   r]   r  	dataclassrv   rb  r  r   r   r|   Builderr  r   r  r   r   r   r   r{   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rS   r  rV   r   r"  r&  r(  r7  rA  rE  rR  rm  rs  r#  r  passesInPlacePassr   r  r  
PassResultr  r   r!   r!   r!   r"   <module>   s   






)	&$

+



)
; m

   
4
