o
    s::j`                     @  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DequantizeLinearDynamicQuantizeLinearQuantizeLineari    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 m/home/nk/hobo-godmode/plappi-mvp/.venv/lib/python3.10/site-packages/onnxscript/optimizer/_constant_folding.py	<genexpr>E       z&_is_control_flow_op.<locals>.<genexpr>)irAttributeTypeGRAPHGRAPHSany
attributesvaluesr   r"   r    r#   _is_control_flow_opC   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_opH      r4   r/   strc                 C  s   | j |ko
t| jS r   )r/   r1   r2   r3   )r   r/   r"   r"   r#   _is_onnx_opL   r5   r7   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)r7   lenr+   nextiteritemsoutputs
isinstancer&   AttrrD   Tensornparrayfloat32r?   int64StringTensorbytes_typingcastTensorProtocolconst_valueshaper=   )r   	attr_name
attr_valueir_valuerV   r"   r"   r#   _process_constant_nodeV   s8   


 r[   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)r[   )r\   r   r"   r"   r#   r      s   
r   c                   @  s    e Zd Zddd	ZdddZdS )ReferenceEvaluatorr3   r6   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)selfr3   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debugrk   rh   warning)ri   r3   r_   r`   argskwargs	evaluatorer"   r"   r#   evaluate   s   zReferenceEvaluator.evaluateN)r3   r6   r_   r6   r`   ra   r   rb   )r3   r6   r_   r6   r`   ra   r   r   )__name__
__module____qualname__rk   rs   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)rt   ru   rv   __doc____annotations__r"   r"   r"   r#   rw      s   
 rw   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ri   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_maprD   ir.Value | NoneSymbolicValue | Nonec                 C  s   |d u rd S | j |S r   )r~   get)ri   rD   r"   r"   r#   get_sym_value   s   zOptimizerState.get_sym_valueir.Value	sym_valueSymbolicValuer8   c                 C  s   || j |< d S r   r   )ri   rD   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_limitr:   )	_get_numpy_valuer&   DataTypeINT64ndimShapetolistr   rJ   )ri   rD   rV   r   r"   r"   r#   get_shape_value   s   

zOptimizerState.get_shape_valueN)r   r   )rD   r   r   r   )rD   r   r   r   r   r8   )rD   r   r   r   )	rt   ru   rv   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`   ra   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   )ri   r`   r"   r"   r#   	valid_for   s   zPartialEvaluator.valid_forN)r`   ra   r   r   )rt   ru   rv   r{   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__r3   r6   opnamer`   ra   c                   s$   | j ||fg } fdd|D S )Nc                   s   g | ]
}|  r|jqS r"   )r   r   )r   rq   r`   r"   r#   
<listcomp>   s
    
z>PartialEvaluatorRegistry.lookup_evaluators.<locals>.<listcomp>)r   r   )ri   r3   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   rJ   ra   tuple)ri   r   r3   r`   r   r"   r   r#   register   s   

z!PartialEvaluatorRegistry.register)r3   r6   r   r6   r`   ra   )r   N)r   r6   r3   r6   r   r   )rt   ru   rv   r{   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   rJ   r&   SymbolicDimrD   )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.)rV   r=   sizenumpyr&   r   STRINGviewFileNotFoundErrorrl   rn   r?   rJ   rM   ndarray)r   r=   r   rV   rN   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 Nr:   r   )r   r   r=   r   item)r   rD   r"   r"   r#   _get_bool_valueR  s   
r   indexra   c                 C     |t | jk r| j| S d S r   )rE   inputsr   r   r"   r"   r#   
_get_input]     
r   c                 C  r   r   )rE   rI   r   r"   r"   r#   _get_outputc  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=   rD   r&   r   	UNDEFINED)r   r   inputr"   r"   r#   _get_input_element_typei  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+   rJ   r&   rK   rD   ra   )r   r?   r   r   attr_valr"   r"   r#   _get_int_attributep  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   rE   rJ   ra   rD   )input_indexr   shape_valuer   r   r   r"   r#   get_dim_value  s   

zadd.<locals>.get_dim_valuer   r:   N+)rJ   ra   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rJ   ra   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   r:   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>rA   rA   )r   r   r   r   r   r   r   r&   r   allr9   
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   r:   N)r   rW   r   r   r   r   )r   r_   r   r   rW   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#   rT     s   



rT   CastLikec                 C  sN   | j d }t| d}t| d}|tjjkrd S ||kr ||S |j||dS )Nr   r:   )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>rA   r   )r   rW   r   r   r   r&   r   r   r9   r   list)	r   r_   r   r   rW   r  r  shape_slicer   r"   r"   r#   rW     s   

rW   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   r:   r@   )r   rW   rJ   ra   r9   )r   r_   r   r   rW   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>G  s
    zif_op.<locals>.<dictcomp>c                   s     | | S r   )r   r>   	renamingsr"   r#   renameN  s   zif_op.<locals>.rename_)r   r   r+   r   r   r&   r'   r(   rJ   rK   as_graphr  rI   clearzipremover?   rw   )r   r_   r   
cond_inputcondbranch
graph_attrgraphformal_outsactual_outsr  graph_nodessub_nodevr"   r  r#   if_op5  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   rI   _merge_shapesrW   rh   rl   rn   r?   metar   r   setr   r   )r   r_   r   r   r   rr   r"   r"   r#   identity_  s&   


r'  SequenceConstructc                 C  s*   ~| j d }|d ur||t| j d S )Nr   )rI   r   r  r   )r   r_   r   r   r"   r"   r#   sequence_constructv  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 Identityr:   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   )rW   
IndexError)r+  rW   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   rW   r"   r"   r#   r$         zconcat.<locals>.<genexpr>c                 s  s     | ]}|j D ]}|V  qqd S r   )r   )r   rW   r   r"   r"   r#   r$         )r+  r   r   r   )r   rE   r   r   rl   rm   r*  r*   r&   r   rI   r   )r   r_   r   r   
new_inputsshapesconcatenatedr   r"   )r   r.  r   r#   concat  s:   
r8  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   r:   T)rD   )r   r   rE   rI   r&   tensorr   r   )r   r   true_tensorr   maskr   r_   r"   r#   optimized_dropout  s   


z"dropout.<locals>.optimized_dropout   NFr:   r   )r   rE   r   r   r   r   )r   r_   r   r?  r   ratior"   r>  r#   dropout  s   
rB  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   r:   )rE   r   rW   r   r   r   r   r   r   r   r   )r   r_   r   r   r   expanded_shapeexpanded_sym_shaper"   r"   r#   expand  s    


rF  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  r2  r   r"   r/  r"   r"   r#   r$     r3  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>r:   r
  
_unsqueeze_outputszConcatFromSequence => Concat %sc                 S  rI  r"   r>   r/  r"   r"   r#   r     rJ  )r   r   r*   r   rJ   r  rl   rm   r*  r9   	Unsqueezer?   r   )r   r_   r   r   r   rH  r   
axis_valueunsqueezed_inputs
node_inputunsqueezed_inputr"   r"   r#   concat_from_sequence  s2   

rS  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   r:   Nr   c                      g | ]
} j  d | qS _split_r>   r   r   r"   r#   r   T      z%split_to_sequence.<locals>.<listcomp>)r   rM  c                   rU  rV  r>   r   rX  r"   r#   r   Y  rY  c                   rU  rV  r>   r   rX  r"   r#   r   a  rY  )r   num_outputsrM  keepdims_axis)rA   rM  _squeezerL  z,SplitToSequence => Split + SequenceConstruct)r   rE   rI   r   rW   r   	is_staticr   rJ   r   ra   rangeSplitr   r   mathceilr   r&   Valuer9   r?   r   r   rl   rm   r(  )r   r_   r   r   splitr   rW   ranksplit_valuesplit_shapesplit_dimension_sizerZ  split_outputssplit_valuesr[  axis_valsqueezed_valuesr   squeezedr"   rX  r#   split_to_sequence  sz   


	 





rn  
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   r:   zSequenceAt %s => %s)r   rI   r   r   rJ   r  r   r   r,  r   rl   rm   r?   r   )	r   r_   r   r   positionr   
input_valsposition_valresultr"   r"   r#   sequence_at  s&   





rt  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   rw  rx  r"   r#   r         z!_merge_shapes.<locals>.<listcomp>)rE   
ValueErrorr&   r   r  )ru  rv  r"   ry  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   ry   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_limitra   output_size_limitr   Callable[[ir.Node], bool | None]r   r8   c                C  sD   || _ || _|| _|| _i | _i | _i | _d| _t | _	| 
  d S )NF)r  r  r  r  _opset_imports_counts_sizes	_modifiedr}   _state_reset)ri   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 )Nr0  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   rV   r&   serdeserialize_tensor)r0  rD   r"   r"   r#   get_constant_value  s
   z;FoldConstantsPass._do_inference.<locals>.get_constant_valuerD   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_typerW   serialize_shape_into)rD   
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  r2  r   r"   )r   tr"   r"   r#   r$     r3  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)r0  r   r   r  )rD   r   r   r  )r   rH   r*   r,   rl   rm   r?   rc   defs
get_schemar/   r  r3   r  infer_node_outputsr&   r  serialize_noderI    deserialize_type_proto_for_shaper$  rW   deserialize_type_proto_for_typer   rh   )
ri   r   output_typesinput_types
input_dataschemar   inferred_typeinferred_shaperr   r"   )r  r  r#   _do_inference  sN   






zFoldConstantsPass._do_inferenceoutput_namer6   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   r:   z;Skip storing constant folded array %s due to large size %s.)rJ   rM   r   rl   infor   r&   r;  r?   r   r  r   rE   usesr   )	ri   r   r  r  r;  removed_input_size	input_valinput_arrayincreased_sizer"   r"   r#   _prepare_folded_tensor&  s4   




z(FoldConstantsPass._prepare_folded_tensorrN   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   r9   rD   )r   r+   )
rI   r  r?   rl   rm   r=   rW   r&   Node
AttrTensor)ri   r   rN   original_valuer;  r"   r"   r#   new_constantN  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   rW   rV   z0New Initializer for value %s dtype: %s shape: %s)rI   r  r?   r&   rc  r   r   r=   rW   rl   rm   )ri   r   rN   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 %sTr9   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$     r4  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   rV   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 )Nr:   )rE   	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  rD   )avr"   r"   r#   convert  s   z/FoldConstantsPass.process_node.<locals>.convertc                   s   i | ]	\}}| |qS r"   r"   )r   r?   r   )r  r"   r#   r    rz  z2FoldConstantsPass.process_node.<locals>.<dictcomp>r:   z:Skipping constant folding for op %s with multiple outputs.)3	enumerater   r  r   rJ   r&   rc  rl   rm   r?   replace_input_withr  r7   r[   r  r.   r  r3   r  r   r   r/   RewriterContextrh   RuntimeErrorrw   r\   r  r4   r*   r  DEFAULT_CONSTANT_FOLD_BLACKLISTrE   _DEFAULT_ALWAYS_FOLD_OPSr   r  isEnabledForloggingINFOr+   rH   _reference_evaluatorrs   rI   r   r  r  r  r  register_initializerrn   )ri   r   r  r   rD   r   r`   op_optimizers	optimizercontextr   rr   r  r/   input_tensorslarge_inputsinput_sizesinput_valuesattr_valuesrI   r}  new_initializer_valuer"   )r  ri   r#   process_nodex  s  







	





 

zFoldConstantsPass.process_noder}  rw   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   1  r1  z2FoldConstantsPass.replace_node.<locals>.<listcomp>T)rl   rm   r3   r/   r?   r  r   r&   conveniencereplace_nodes_and_valuesrz   rI   ry   rJ   Graphr  _clear_unused_initializersr  )ri   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)ri   r   r  r"   r"   r#   visit_attributeA  s   z!FoldConstantsPass.visit_attributec                 C  sR   t |tj}| j||d}|d u r |j D ]}| | qd S | ||| d S )N)r  )rJ   r&   Functionr  r+   r,   r  r  )ri   r   r  r  r}  r   r"   r"   r#   
visit_nodeJ  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  rI   r  r   rJ   r&   rc  #_sym_value_can_replace_graph_outputr?   r  )ri   r  r   r   r   r   r"   r"   r#   r  U  s   
zFoldConstantsPass.visit_graphr   ir.Functionc                 C  s   |D ]}|  || qd S r   )r  )ri   r   r   r"   r"   r#   visit_functioni  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   )ri   r  r   r"   r"   r#   callm  s   zFoldConstantsPass.callN)
r  r   r  ra   r  ra   r  r  r   r8   )r   r8   r   r   r   r8   )r   r   r  r6   r  r  r   r  )r   r   rN   r  r   r  )r   r   rN   r  r   r   )r   r   r  r   r   r  )r   r   r}  rw   r  r  r   r8   )r   r  r   r8   )r   r   r  r  r   r8   )r  r  r   r8   )r   r  r   r8   )r  r  r   r  )rt   ru   rv   r{   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  w  s   
r  r,   rx   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,   rD   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   )rt   ru   rv   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/   r6   r   r   r  )r\   r]   r   r8   )r   r   r   r   r   r   )NN)r   r   r=   r   r   r   r   r   )r   r   r   r   )r   r   r   ra   r   r   )r   r   r   ra   r   ra   r   )r   r   r?   r6   r   r   r   r   )r   r   r   r}   r   r   )ru  r   rv  r   r   r   )r|  r   r}  rw   r   r8   )r  r  r   r   r   r   r   r   )r,   rx   r   r8   )r  r  r  r   r  ra   r  ra   r  r  r   r  )\
__future__r   __all__dataclassesr  ra  rS   r   r   r	   r
   r   r   rM   rc   onnx.reference.opsonnx_irr&   onnxscript.utils.utilsr1   onnxscript.irr   r  &DEFAULT_CONSTANT_FOLD_INPUT_SIZE_LIMIT'DEFAULT_CONSTANT_FOLD_OUTPUT_SIZE_LIMITr   	frozensetr0   r  	getLoggerrt   rl   r.   r4   r7   r[   r   r^   r  	dataclassrw   rc  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   rT   r  rW   r   r#  r'  r)  r8  rB  rF  rS  rn  rt  r$  r  passesInPlacePassr   r  r  
PassResultr  r   r"   r"   r"   r#   <module>   s   	






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