U
    qhng                     @  s  d dl mZ d dlmZ d dlmZmZmZmZm	Z	m
Z
mZ d,dddddd	d
Zd-ddddddddddd
ddZd.dddddddddddddddddZd/ddddddddddddd d!Zd0dddddddddddd"d#d$Zd1dd%ddd&d'd(Zd2dd%ddd)d*d+ZdS )3    )annotations)MutableMapping)AttributeProto
GraphProto
ModelProtoTensorProtocheckerhelperutilsNr   zlist[tuple[str, str]] | Nonezlist[tuple[str, list[str]]])g1g2io_mapreturnc                 C  sT  t | tk	rtdt |tk	r(tddddddd}ddd	dd
dd}g }|sZg }dd |D }||| |||d}|r|d|f |dd | jD dd |jD }|r|d|f |dd | jD dd |jD }|r|d|f |dd | jD dd |jD |dd | jD dd |jD  }|rP|d|f |S )a  Checks whether there are name collisions between two graphs

    Returns a list of tuples where the first element represents the member containing overlapping names
    (One of: "node", "edge", "value_info", "initializer", "sparse_initializer"), and the
    second element contains a list of names that appear in both graphs on that category.

    Optionally, it takes an io_map, representing the output/inputs to be connected. It provided, overlapping
    present in the io_map argument will be ignored.
     g1 argument is not an ONNX graph g2 argument is not an ONNX graphz	list[str])c1c2r   c                 S  s   t t| t|@ S )N)listset)r   r    r   0/tmp/pip-unpacked-wheel-xnis5xre/onnx/compose.py_overlapping$   s    z-check_overlapping_names.<locals>._overlappingNr   zset[str] | None)graphexcluder   c                 S  sn   |d krt  }g }| jD ]P}|jD ]}|dkr"||kr"|| q"|jD ]}|dkrH||krH|| qHq|S )N )r   nodeinputappendoutput)r   r   edgesnior   r   r   _edge_names'   s    


z,check_overlapping_names.<locals>._edge_namesc                 S  s   h | ]}|d  qS    r   ).0elemr   r   r   	<setcomp>8   s     z*check_overlapping_names.<locals>.<setcomp>)r   Zedgec                 S  s   g | ]
}|j qS r   namer&   er   r   r   
<listcomp>@   s     z+check_overlapping_names.<locals>.<listcomp>
value_infoc                 S  s   g | ]
}|j qS r   r)   r+   r   r   r   r-   F   s     initializerc                 S  s   g | ]}|j jqS r   valuesr*   r+   r   r   r   r-   L   s     c                 S  s   g | ]}|j jqS r   r0   r+   r   r   r   r-   M   s     c                 S  s   g | ]}|j jqS r   indicesr*   r+   r   r   r   r-   O   s     c                 S  s   g | ]}|j jqS r   r2   r+   r   r   r   r-   P   s     sparse_initializer)N)typer   
ValueErrorr   r.   r/   r4   )r   r   r   r   r#   resultZio_map_inputsoverlapr   r   r   check_overlapping_names   sJ      r9   zlist[tuple[str, str]]zlist[str] | Nonez
str | None)
r   r   r   inputsoutputsprefix1prefix2r*   
doc_stringr   c	                   s  t | tk	rtdt |tk	r(tds0rrTt }	|	|  |	} t| d} rxt }
|
| |
}t|d}fdd|D }dd |D dd |D d	d
 |D dd | jD }dd |jD }|s|r |sdd | jD }dd |jD }n2t|fdd| jD }fdd|jD }|sbdd | jD }dd |jD }n2t|fdd| jD }fdd|jD }t|t| jk st|t| jk rt	
t| }|||j} t|t|jk st|t|jk r t	
t|}|||j}|D ]>\}}||krFtd| d||kr$td| dq$t| ||}t|dkr|d \}}td| dd| d d t }|j| j t|j}|j|j t|j}dd d d!d" fd#d$  ||| |rPt||jfd%d| jD  |jfd&d|jD  n*|j| j |jfd'd|jD  |rt||jfd(d| jD  |jfd)d|jD  n*|jfd*d| jD  |j|j |j| j |jfd+d|jD  |j| j |jfd,d|jD  |j| j |jfd-d|jD  |d.k	rx|nd/| j|jg|_|d.krd0| j d1|j d| j d2 | j d2 |j d2 |j }||_|S )3a  Combines two ONNX graphs into a single one.

    The combined graph is defined by connecting the specified set of outputs/inputs. Those inputs/outputs
    not specified in the io_map argument will remain as inputs/outputs of the combined graph.

    Arguments:
        g1 (GraphProto): First graph
        g2 (GraphProto): Second graph
        io_map (list of pairs of string): The pairs of names [(out0, in0), (out1, in1), ...]
                                          representing outputs of the first graph and inputs of the second
                                          to be connected
        inputs (list of string): Optional list of inputs to be included in the combined graph
                                 By default, all inputs not present in the ``io_map`` argument will be
                                 included in the combined model
        outputs (list of string): Optional list of outputs to be included in the combined graph
                                  By default, all outputs not present in the ``io_map`` argument will be
                                  included in the combined model
        prefix1 (string): Optional prefix to be added to all names in g1
        prefix2 (string): Optional prefix to be added to all names in g2
        name (string): Optional name for the combined graph
                       By default, the name is g1.name and g2.name concatenated with an undescore delimiter
        doc_string (string): Optional docstring for the combined graph
                             If not provided, a default docstring with the concatenation of g1 and g2 docstrings is used

    Returns:
        GraphProto
    r   r   prefixc                   s<   g | ]4} r |d   n|d  r.|d  n|d fqS r   r%   r   r&   ior<   r=   r   r   r-      s   z merge_graphs.<locals>.<listcomp>c                 S  s   h | ]}|d  qS )r   r   rB   r   r   r   r(      s     zmerge_graphs.<locals>.<setcomp>c                 S  s   h | ]}|d  qS r$   r   rB   r   r   r   r(      s     c                 S  s   i | ]\}}||qS r   r   )r&   Zout_nameZin_namer   r   r   
<dictcomp>   s      z merge_graphs.<locals>.<dictcomp>c                 S  s   h | ]
}|j qS r   r)   r&   r"   r   r   r   r(      s     c                 S  s   h | ]
}|j qS r   r)   r&   r!   r   r   r   r(      s     c                 S  s   g | ]
}|j qS r   r)   rG   r   r   r   r-      s     c                 S  s   g | ]
}|j qS r   r)   rG   r   r   r   r-      s     c                   s   g | ]}|j  kr|j qS r   r)   rG   	input_setr   r   r-      s     
 c                   s&   g | ]}|j  ks|j kr|j qS r   r)   rG   )rI   io_map_g2_insr   r   r-      s   
 
c                 S  s   g | ]
}|j qS r   r)   rF   r   r   r   r-      s     c                 S  s   g | ]
}|j qS r   r)   rF   r   r   r   r-      s     c                   s&   g | ]}|j ks|j  kr|j qS r   r)   rF   )io_map_g1_outs
output_setr   r   r-      s   
 
c                   s   g | ]}|j  kr|j qS r   r)   rF   rL   r   r   r-      s     
 zOutput z is not present in g1zInput z is not present in g2r   z=Cant merge two graphs with overlapping names. Found repeated z names: , 
zYConsider using ``onnx.compose.add_prefix`` to add a prefix to names in one of the graphs.r   intNone)	sub_graphstartendr   c                   sv   t ||D ]f}| j| }|jD ]&}|jtjkr |jdt|jj qt|j	D ]\}}|krP| |j	|< qPq
d S Nr   )
ranger   	attributer5   r   ZGRAPHglen	enumerater   )rR   rS   rT   Znode_idxr   attrindexZname_)
connect_ioreversed_io_mapr   r   r]      s    

z merge_graphs.<locals>.connect_ioc                   s   g | ]}|j  kr|qS r   r)   rG   rH   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   rG   rH   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   rG   rJ   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   rF   rM   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   rF   rM   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   rF   )rK   r   r   r-      s     
 c                   s   g | ]}|j  kr|qS r   r)   r&   initr_   r   r   r-      s     
 c                   s   g | ]}|j j kr|qS r   r0   r`   r_   r   r   r-      s   c                   s   g | ]}|j  kr|qS r   r)   )r&   vir_   r   r   r-     s     
 N_zGraph combining  and z

)r5   r   r6   CopyFromadd_prefix_graphr   r   r   rY   r
   Z	Extractorr	   
make_modelZextract_modelr   r9   joinr   extendr/   r4   r.   r*   r>   )r   r   r   r:   r;   r<   r=   r*   r>   Zg1_copyZg2_copyZg1_outsZg2_insZ	g1_inputsZ	g2_inputsZ
g1_outputsZ
g2_outputse1e2Zg1_out_nameZ
g2_in_nameZoverlapping_namescategorynamesrX   Zg2_nodes_beginZg2_nodes_endr   )r]   rI   rK   rJ   rL   r<   r=   r^   r   merge_graphsX   s    &


((





"

rn   onnx.compose.merge_models1.0r   r%   r   z
int | None)m1m2r   r:   r;   r<   r=   r*   r>   producer_nameproducer_versiondomainmodel_versionr   c              	     sB  t | tk	rtdt |tk	r(td| j|jkrNtd| j d|j d| j}i }t| jt|j }|D ]H}|j|kr||j }|j|krtd| j d|j qp|j||j< qp sĈr" rt }||  |} t	|  d} rt }|| |}t	|d} fd	d
|D }t
| j|j|||||d}tj||	|
||||d}i }| jD ]}|j||j< q^|jD ]V}|j|kr||j }||jkrtd|j d| d|j dn|j||j< qxt|| tdd | jD dd |jD @ }|rtdd| |j| j |j|j t| |S )a=  Combines two ONNX models into a single one.

    The combined model is defined by connecting the specified set of outputs/inputs.
    Those inputs/outputs not specified in the io_map argument will remain as
    inputs/outputs of the combined model.

    Both models should have the same IR version, and same operator sets imported.

    Arguments:
        m1 (ModelProto): First model
        m2 (ModelProto): Second model
        io_map (list of pairs of string): The pairs of names [(out0, in0), (out1, in1), ...]
                                          representing outputs of the first graph and inputs of the second
                                          to be connected
        inputs (list of string): Optional list of inputs to be included in the combined graph
                                 By default, all inputs not present in the ``io_map`` argument will be
                                 included in the combined model
        outputs (list of string): Optional list of outputs to be included in the combined graph
                                  By default, all outputs not present in the ``io_map`` argument will be
                                  included in the combined model
        prefix1 (string): Optional prefix to be added to all names in m1
        prefix2 (string): Optional prefix to be added to all names in m2
        name (string): Optional name for the combined graph
                       By default, the name is g1.name and g2.name concatenated with an undescore delimiter
        doc_string (string): Optional docstring for the combined graph
                             If not provided, a default docstring with the concatenation of g1 and g2 docstrings is used
        producer_name (string): Optional producer name for the combined model. Default: 'onnx.compose'
        producer_version (string): Optional producer version for the combined model. Default: "1.0"
        domain (string): Optional domain of the combined model. Default: ""
        model_version (int): Optional version of the graph encoded. Default: 1

    Returns:
        ModelProto
    z m1 argument is not an ONNX modelz m2 argument is not an ONNX modelzIR version mismatch z != z-. Both models should have the same IR versionzPCan't merge two models with different operator set ids for a given domain. Got: rd   r?   c                   s<   g | ]4} r |d   n|d  r.|d  n|d fqS rA   r   rB   rD   r   r   r-   r  s   z merge_models.<locals>.<listcomp>)r:   r;   r*   r>   )rs   rt   ru   rv   opset_imports
ir_versionzaCan't merge models with different values for the same model metadata property. Found: property = z, with values .c                 S  s   h | ]
}|j qS r   r)   )r&   fr   r   r   r(     s     zmerge_models.<locals>.<setcomp>zPCan't merge models with overlapping local function names. Found in both graphs: rN   )r5   r   r6   rx   r   Zopset_importru   versionre   
add_prefixrn   r   r	   rg   Zmetadata_propsvaluekeyZset_model_props	functionsrh   Z	MergeFromr   Zcheck_model)rq   rr   r   r:   r;   r<   r=   r*   r>   rs   rt   ru   rv   rx   Zopset_import_maprw   entryZfound_versionZm1_copyZm2_copyr   modelZmodel_propsZ
meta_entryr}   Zfunction_overlapr   rD   r   merge_models  s    1





	



r   TFstrzbool | Nonezdict[str, str] | None)r   r@   rename_nodesrename_edgesrename_inputsrename_outputsrename_initializersrename_value_infosinplacename_mapr   c
                 C  s  t | tk	rtd|s*t }
|
|  n| }
dddddd}|	dkrLi }	|r|
jD ]8}|jD ]}||||	|< q`|jD ]}||||	|< qzqV|r|
jD ]}|||j|	|j< q|r|
jD ]}|||j|	|j< q|r|
jD ]6}|||j|_|jD ]}|j	rt
|j	|d|	d qq|rx|
jD ]}|||j|	|j< q$|
jD ]2}|||jj|	|jj< |||jj|	|jj< qD|r|
jD ]}|||j|	|j< q|
jD ]n}t|jD ](\}}|j| |	kr|	| |j|< qt|jD ](\}}|j| |	kr|	| |j|< qq|
jD ]}|j|	kr|	|j |_q|
jD ]}|j|	kr@|	|j |_q@|
jD ]}|j|	krf|	|j |_qf|
jD ]B}|jj|	kr|	|jj |j_|jj|	kr|	|jj |j_q|
jD ]}|j|	kr|	|j |_q|
S )	a  Adds a prefix to names of elements in a graph: nodes, edges, inputs, outputs,
    initializers, sparse initializer, value infos.

    It can be used as a utility before merging graphs that have overlapping names.
    Empty names are not prefixed.

    Arguments:
        graph (GraphProto): Graph
        prefix (str): Prefix to be added to each name in the graph
        rename_nodes (bool): Whether to prefix node names
        rename_edges (bool): Whether to prefix node edge names
        rename_inputs (bool): Whether to prefix input names
        rename_outputs (bool): Whether to prefix output names
        rename_initializers (bool): Whether to prefix initializer and sparse initializer names
        rename_value_infos (bool): Whether to prefix value info names
        inplace (bool): If True, mutates the graph directly.
                        Otherwise, a copy will be created
        name_map: (Dict): shared name_map in subgraph

    Returns:
        GraphProto
    #graph argument is not an ONNX graphr   )r@   r*   r   c                 S  s   t |dkr| | S |S rU   )rY   )r@   r*   r   r   r   	_prefixed  s    z#add_prefix_graph.<locals>._prefixedNT)r   r   )r5   r   r6   re   r   r   r   r*   rW   rX   rf   r/   r4   r1   r3   r.   rZ   )r   r@   r   r   r   r   r   r   r   r   rX   r   r    r,   r   rW   ra   Zsparse_initr!   r   Zinput_Zin_descZout_descr/   r4   r.   r   r   r   rf     s    "






   


  






rf   )r   r@   r   r   r   r   r   r   rename_functionsr   r   c
                 C  s   t | tk	rtd|	s,t }
|
|  |
} t| j|||||||dd	 |ri }| jD ]}||j }|||j< ||_qV| jD ]&}|jD ]}|j	|kr||j	 |_	qq|| jjD ]}|j	|kr||j	 |_	q| S )a  Adds a prefix to names of elements in a graph: nodes, edges, inputs, outputs,
    initializers, sparse initializer, value infos, and local functions.

    It can be used as a utility before merging graphs that have overlapping names.
    Empty names are not _prefixed.

    Arguments:
        model (ModelProto): Model
        prefix (str): Prefix to be added to each name in the graph
        rename_nodes (bool): Whether to prefix node names
        rename_edges (bool): Whether to prefix node edge names
        rename_inputs (bool): Whether to prefix input names
        rename_outputs (bool): Whether to prefix output names
        rename_initializers (bool): Whether to prefix initializer and sparse initializer names
        rename_value_infos (bool): Whether to prefix value info nanes
        rename_functions (bool): Whether to prefix local function names
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        ModelProto
    #model argument is not an ONNX modelT)r   r   r   r   r   r   r   )
r5   r   r6   re   rf   r   r   r*   r   Zop_type)r   r@   r   r   r   r   r   r   r   r   mZ
f_name_maprz   Z
new_f_namer    r   r   r   r|   "  s>    "







r|   rP   )r   dim_idxr   r   c                 C  s  t | tk	rtd|s*t }||  n| }dd |jD }|jD ]d}t|jD ]$\}}||krR|d|  |j|< qRt|jD ]$\}}||kr|d|  |j|< qqD|jd }	|j	t
jdg |	g|	 dt
j|	 dtjd	g|gd
d tt|jD ]}
|jd}|jd|  }|j	t
jd||	g|jgd|j d dd |j jjjD }||d	 |j	t
|j|j jj| q |S )aE  Inserts an extra dimension with extent 1 to each output in the graph.

    Inserts an Unsqueeze node for each output. It can be used as a utility before merging graphs,
    for example when the second one expects a batch dimension.

    Arguments:
        graph (GraphProto): Graph
        dim_idx (int): Index of the dimension to be inserted.
                       A negative value means counting dimensions from the back.
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        GraphProto
    r   c                 S  s   g | ]
}|j qS r   r)   )r&   r   r   r   r   r-     s     z(expand_out_dim_graph.<locals>.<listcomp>Z_collapsed_dim_Z_expand_out_dim_idxConstantz	-constantz-valuer%   )r*   Z	data_typeZdimsvals)r:   r;   r*   r}   r   Z	Unsqueezez
unsqueeze-)r:   r;   r*   c                 S  s   g | ]
}|j qS r   )Z	dim_value)r&   dr   r   r   r-     s     )r5   r   r6   re   r   r   rZ   r   r*   r   r	   Z	make_nodeZmake_tensorr   ZINT64rV   rY   popZtensor_typeshapeZdiminsertZmake_tensor_value_infoZ	elem_type)r   r   r   rX   Zorig_out_namesr    r!   outinpZexpand_dim_krc   r"   Zprev_outputZ	new_shaper   r   r   expand_out_dim_graphl  sh    


  r   )r   r   r   r   c                 C  s@   t | tk	rtd|s,t }||  |} t| j|dd | S )aE  Inserts an extra dimension with extent 1 to each output in the graph.

    Inserts an Unsqueeze node for each output. It can be used as a utility before merging graphs,
    for example when the second one expects a batch dimension.

    Arguments:
        model (ModelProto): Model
        dim_idx (int): Index of the dimension to be inserted.
                       A negative value means counting dimensions from the back.
        inplace (bool): If True, mutates the model directly.
                        Otherwise, a copy will be created

    Returns:
        ModelProto
    r   T)r   )r5   r   r6   re   r   r   )r   r   r   r   r   r   r   expand_out_dim  s    
r   )N)NNNNNN)
NNNNNNro   rp   r   r%   )TTTTTTFN)TTTTTTTF)F)F)
__future__r   typingr   Zonnxr   r   r   r   r   r	   r
   r9   rn   r   rf   r|   r   r   r   r   r   r   <module>   s\   $ I      " H          *         $x        $M S 