
    h                         S SK r S SKrS SKrS SKrS SKrS SKJr  S SKJr  S SK	J
r
  S SKrS SKrS SKJrJrJrJr  S SKrSSKJrJrJr  S\R.                  S	\R.                  S
\R.                  4S jr  S-S\R.                  S	\R.                  S\S-  S\S
\R.                  4
S jjr " S S5      r " S S5      r " S S\5      r " S S\ R>                  S9r  " S S5      r! " S S\!5      r" " S S\!5      r# " S S\#5      r$ " S  S!\#5      r% " S" S#\#5      r& " S$ S%\ R>                  S9r' " S& S'\'5      r(SS(\RR                  S)S0 4S*\*\
-  S+\\*   S-  4S, jjr+g).    N)Sequence)Enum)Path)
ModelProtoTensorProtohelpernumpy_helper   )
apply_plotload_model_with_shape_infersmooth_distributionpkqkreturnc                    [         R                  " U R                  U R                  S9nU SS [         R                  " U SS USS -  5      -  USS& U S:H  US:  -  nSX#'   U S:  US:  -  n[         R
                  X$) '   U$ )z
See https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.rel_entr.html#scipy.special.rel_entr.
Python implementation.
dtypeNr   )npemptyshaper   loginf)r   r   resc2c1s        \/var/www/fran/franai/venv/lib/python3.13/site-packages/onnxruntime/quantization/calibrate.pyrel_entrr      s    
 ((288288
,CURVVBqEBqEM**CF
'bAg	BCG
q&R!V	BvvCHJ    baseaxisc                 J   Ub  US:  d   S5       eUc   S5       e[         R                  " U 5      R                  [         R                  5      n SU -  [         R                  " XSS9-  n [         R                  " U5      R                  [         R                  5      n[         R
                  " X5      u  pSU-  [         R                  " XSS9-  n[        X5      n[         R                  " XCS9nUb  U[         R                  " U5      -  nUR                  U R                  5      $ )z
Simplifeied version of entropy.
Source: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.entropy.html.
This avoids taking a dependency on scipy just for this function.
r   z0base={base} must be a positive number or `None`.z
qk is None      ?T)r    keepdimsr    )	r   asarrayastypefloat32sumbroadcast_arraysr   r   r   )r   r   r   r    vecss         r   entropyr,   '   s     <4!8W%WW#>'<'>	B		rzz	*B	rBFF248	8B	B		rzz	*B  (FB	rBFF248	8B
2
C
sA	RVVD\88BHHr   c                   h    \ rS rSr\" / SQ5      r\" / SQ5      rS r\S 5       r	\S 5       r
S rSrg	)

TensorDataC   )avgstdlowesthighesthist
hist_edgesbins)r0   r1   r2   r3   r5   c                    [        UR                  5       5      U l        UR                  5        H  u  p#U[        R
                  ;  a!  [        SU< S[        R
                   S35      eU[        R                  ;   av  [        US5      (       d  [        S[        U5       SU< 35      eUR                  [        R                  [        R                  4;  a  [        SUR                   SU< 35      e[        XU5        M     g )NzUnexpected value z not in .r   Unexpected type z for k=zUnexpected dtype )listkeys_attrsitemsr.   _allowed
ValueError_floatshasattrtyper   r   float16r'   setattr)selfkwargskvs       r   __init__TensorData.__init__G   s    6;;=)LLNDA
+++ #4QE*BUBUAVVW!XYYJ&&&q'**$'7Qyu%MNN772::rzz"::$'8	%NOODQ #r   c                     [        U S5      (       a  [        U S5      (       d  [        S[        U 5       S35      eU R                  U R                  4$ )Nr2   r3   z0Attributes 'lowest' and/or 'highest' missing in r8   )rA   AttributeErrordirr2   r3   rE   s    r   range_valueTensorData.range_valueS   sL    tX&&gdI.F.F #STWX\T]S^^_!`aaT\\**r   c                     [        U S5      (       a  [        U S5      (       d  [        S[        U 5       S35      eU R                  U R                  4$ )Nr0   r1   z)Attributes 'avg' and/or 'std' missing in r8   )rA   rL   rM   r0   r1   rN   s    r   avg_stdTensorData.avg_stdY   sI    tU##74+?+? #LSQUYKWX!YZZ$((##r   c                     U R                    Vs0 s H  o[        X5      _M     nnU R                  R                  US'   U$ s  snf )NCLS)r<   getattr	__class____name__)rE   rG   datas      r   to_dictTensorData.to_dict_   s?    -1[[9[74##[9nn--U :s   A)r<   N)rX   
__module____qualname____firstlineno__	frozensetr>   r@   rI   propertyrO   rR   rZ   __static_attributes__ r   r   r.   r.   C   sJ    Z[HIJG
  + +
 $ $
r   r.   c                   b    \ rS rSrS\\\\-  4   4S jrS r	S r
S rS rS rS	 rS
 rS rSrg)TensorsDataf   rY   c           
      |   Xl         0 U l        UR                  5        GH  u  p4[        U[        5      (       d  [        S[        U5       S35      e[        U[        5      (       a  U[        R                  :X  a.  [        U5      S:X  a  [        US   US   S9U R                  U'   M  [        U5      S:X  a'  [        US   US   US   US   S	9U R                  U'   M  [        S
US S[        U5       SU S35      e[        U[        5      (       d  [        S[        U5       S35      eX@R                  U'   GM     g )NzKeys must be strings not r8      r   r
   r2   r3         )r2   r3   r4   r6   zUnexpected tuple for rz	, it has z elements: zValues must be TensorData not )calibration_methodrY   r=   
isinstancestr	TypeErrorrB   tupleCalibrationMethodMinMaxlenr.   )rE   rl   rY   rG   rH   s        r   rI   TensorsData.__init__g   s"   "4	JJLDAa%%";DG9A FGG!U##%):)A)AAc!fPQk#-QqT1Q4#HDIIaLq6Q;#-QqT1Q4aPQdYZ[\Y]#^DIIaL"7!uIc!fX[YZX[[\ ]^^a,,"@a	 KLLIIaL !r   c              #   8   #    U R                    S h  vN   g  N7fNrY   rN   s    r   __iter__TensorsData.__iter__y   s     99s   c                     XR                   ;   $ rv   rw   rE   keys     r   __contains__TensorsData.__contains__|   s    iir   c                      U R                   U   $ rv   rw   r{   s     r   __getitem__TensorsData.__getitem__   s    yy~r   c                 ^    XR                   ;  a  [        SU< S35      eX R                   U'   g )Nz)Only an existing tensor can be modified, z is not.)rY   RuntimeError)rE   r|   values      r   __setitem__TensorsData.__setitem__   s-    ii!J3'QYZ[[		#r   c                 6    U R                   R                  5       $ rv   )rY   r;   rN   s    r   r;   TensorsData.keys   s    yy~~r   c                 6    U R                   R                  5       $ rv   )rY   valuesrN   s    r   r   TensorsData.values   s    yy!!r   c                 6    U R                   R                  5       $ rv   )rY   r=   rN   s    r   r=   TensorsData.items   s    yy  r   c                 b    U R                   R                  U R                  U R                  S.nU$ )N)rU   rY   rl   )rW   rX   rY   rl   )rE   rY   s     r   rZ   TensorsData.to_dict   s/     >>**II"&"9"9

 r   )rl   rY   N)rX   r\   r]   r^   dictrn   r.   rp   rI   rx   r}   r   r   r;   r   r=   rZ   ra   rb   r   r   rd   rd   f   sE    c:;M6M1N $ 
 "!r   rd   c                   $    \ rS rSrSrSrSrSrSrg)rq      r   r
   rg   rj   rb   N)	rX   r\   r]   r^   rr   Entropy
PercentileDistributionra   rb   r   r   rq   rq      s    FGJLr   rq   c                   t    \ rS rSr\S 5       r\R                  S\4S j5       r	S r
S rS rS\S	\4S
 jrSrg)CalibrationDataReader   c                 l    [        US5      =(       a    [        UR                  5      =(       d    [        $ )Nget_next)rA   callabler   NotImplemented)clssubclasss     r   __subclasshook__&CalibrationDataReader.__subclasshook__   s%    *-M(8;L;L2M`R``r   r   c                     [         e)z9generate the input data dict for ONNXinferenceSession runNotImplementedErrorrN   s    r   r   CalibrationDataReader.get_next   s
     "!r   c                     U $ rv   rb   rN   s    r   rx   CalibrationDataReader.__iter__   s    r   c                 8    U R                  5       nUc  [        eU$ rv   )r   StopIteration)rE   results     r   __next__CalibrationDataReader.__next__   s    >r   c                     [         erv   r   rN   s    r   __len__CalibrationDataReader.__len__       !!r   start_index	end_indexc                     [         erv   r   )rE   r   r   s      r   	set_rangeCalibrationDataReader.set_range   r   r   rb   N)rX   r\   r]   r^   classmethodr   abcabstractmethodr   r   rx   r   r   intr   ra   rb   r   r   r   r      sY    a a 	"$ " """S "S "r   r   )	metaclassc                       \ rS rSr     SS\\-  S\\   S-  4S jjrS/4S jrS r	S	\
4S
 jrS rS rS\4S jrS\4S jrSrg)CalibraterBase   N
model_pathop_types_to_calibratec                 ,   [        U[        5      (       a  [        [        U5      5      U l        O1[        U[        5      (       a  [        U5      U l        O[        S5      eX l        X0l        X@l        XPl	        X`l
        SU l        SU l        S/U l        g)a  
:param model_path: ONNX model to calibrate. It should be a model file path
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param symmetric: make range of tensor symmetric (central point is 0).
:param use_external_data_format: use external data format to store model which size is >= 2Gb.
:param per_channel: whether to compute ranges per each channel.
z model_path should be model path.NCPUExecutionProvider)rm   rn   r   r   modelr?   r   augmented_model_path	symmetricuse_external_data_formatper_channelaugment_modelinfer_sessionexecution_providers)rE   r   r   r   r   r   r   s          r   rI   CalibraterBase.__init__   s    " j#&&4T*5EFDJ
D))4Z@DJ?@@%:"$8!"(@%&!!$:#; r   r   c                 0    Xl         U R                  5         g)zj
reset the execution providers to execute the collect_data. It triggers to re-creating inference session.
N)r   create_inference_session)rE   r   s     r   set_execution_providers&CalibraterBase.set_execution_providers   s     $7 %%'r   c                     [         R                  " 5       n[         R                  R                  Ul        [         R
                  " U R                  UU R                  S9U l        g)z)
create an OnnxRuntime InferenceSession.
)sess_options	providersN)	onnxruntimeSessionOptionsGraphOptimizationLevelORT_DISABLE_ALLgraph_optimization_levelInferenceSessionr   r   r   )rE   r   s     r   r   'CalibraterBase.create_inference_session   sN     #1130;0R0R0b0b-(99%%%..
r   r   c                    UR                   R                   Vs0 s H  o"R                  U_M     nnUR                  UR                   R                   Vs0 s H  oDR                  U_M     sn5        UR                  UR                   R
                   Vs0 s H  oUR                  U_M     sn5        UR                   R                   Vs1 s H  ofR                  iM     nn[        5       n[        R                  [        R                  1n	UR                   R                   H  n
U R                  (       a  U
R                  U R                  ;   d  M0  [        R                  " U
R
                  U
R                  5       Hn  nX;   d  M
  X;   nUR                   R#                  S5      (       d  M0  UR                   R$                  R&                  U	;   d  MV  X;  d  M]  UR)                  U5        Mp     M     X4$ s  snf s  snf s  snf s  snf )z
select input/output tensors of candidate nodes to calibrate.
returns:
    tensors (set): set of tensor name.
    value_infos (dict): tensor name to value info.
tensor_type)graph
value_infonameupdateoutputinputinitializersetr   FLOATFLOAT16noder   op_type	itertoolschainrB   HasFieldr   	elem_typeadd)rE   r   vivalue_infosotitinitr   tensors_to_calibratetensor_type_to_calibrater   tensor_names               r   select_tensors_to_calibrate*CalibraterBase.select_tensors_to_calibrate   s    .3[[-C-CD-Crww{-CD%++2D2DE2DBGGRK2DEF%++2C2CD2CBGGRK2CDE-2[[-D-DE-DTyy-DE"u$/$5$5{7J7J#K KK$$D--A[A[1[#,??4::t{{#KK"1(5GG,,];;!#!4!4!>!>BZ!Z!,!?044[A $L % $00) EEDEs   G4G9G>	Hc                     U R                   $ )z@
return: augmented onnx model. Call after calling augment_graph
)r   rN   s    r   get_augment_model CalibraterBase.get_augment_model  s     zzr   c                     [         e)z
abstract method: augment the input model to prepare for collecting data. It will:
    1. augment the model to be able to collect desired statistics data
    2. save augmented model to augmented_model_paths
r   rN   s    r   augment_graphCalibraterBase.augment_graph  s
     "!r   data_readerc                     [         e)zp
abstract method: collect the tensors that will be used for range computation. It can be called multiple times.
r   )rE   r   s     r   collect_dataCalibraterBase.collect_data  
     "!r   r   c                     [         e)zU
abstract method: compute data based on the calibration method stored in TensorsData
r   rN   s    r   compute_dataCalibraterBase.compute_data"  r   r   )	r   r   r   r   r   r   r   r   r   )Naugmented_model.onnxFFF)rX   r\   r]   r^   rn   r   r   rI   r   r   r   r   r   r   r   r   rd   r  ra   rb   r   r   r   r      sz     7;3!& <$J <  (}t3 <D <R:R (

1 1:""(= ""k "r   r   c                      ^  \ rS rSr        SS\\-  S\\   S-  4U 4S jjjrS rS r	S\
4S	 jrS
 rS\4S jrSrU =r$ )MinMaxCalibrateri)  Nr   r   c
           	        > [         TU ]  UUUUUU	S9  / U l        SU l        [	        U R
                  R                  R                  5      U l        U R
                  R                  R                   V
s1 s H  oR                  iM     sn
U l
        X`l        U(       a  US:  d  US:  a  [        S5      eXpl        Xl        gs  sn
f )a'  
:param model_path: ONNX model to calibrate. It is a model path
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param symmetric: make range of tensor symmetric (central point is 0).
:param use_external_data_format: use external data format to store model which size is >= 2Gb
:param moving_average: compute the moving average of the minimum and maximum values instead of the global minimum and maximum.
:param averaging_constant: constant smoothing factor to use when computing the moving average.
:param max_intermediate_outputs: maximum number of intermediate outputs before an intermediate range is computed.
:param per_channel: whether to compute ranges per each channel.
)r   r   r   r   r   Nr   r
   z;Invalid averaging constant, which should not be < 0 or > 1.)superrI   intermediate_outputscalibrate_tensors_rangers   r   r   r   num_model_outputsr   model_original_outputsmoving_averager?   averaging_constantmax_intermediate_outputs)rE   r   r   r   r   r   r  r  r  r   r   rW   s              r   rI   MinMaxCalibrater.__init__*  s    . 	"7!5%=# 	 	
 %'!'+$!$TZZ%5%5%<%<!=AEAQAQAXAX&YAXv{{AX&Y#,1A59Ka9OZ[["4(@% 'Zs   2C c                   ^ ^^ T R                  T R                  5      u  p[        [        R                  " 5       5      m[
        R                  " [        R                  " S/[        R                  S9T5      nT R                  R                  R                  R                  U5        S mUUU 4S jnU H  nU" US5        U" US5        M     [        R                  " T R                  T R                  T R                   S9  g)	z
Adds ReduceMin and ReduceMax nodes to all quantization_candidates op type nodes in
model and ensures their outputs are stored as part of the graph output
:return: augmented ONNX model
r   c                     UR                    H?  n[        R                  R                  XR                  5      (       d  M3  UR
                  s  $    [        SU  S35      e)Nz&Model does not contain a version for 'z'.)opset_importonnxdefshasdomainversionr   )r   r   r  s      r   get_op_version6MinMaxCalibrater.augment_graph.<locals>.get_op_version^  sO     % 2 299==*=*=>>'/// !3 !GyPRSTTr   c                 <  > SnU S-   U-   nUS-   n[         R                  R                  X/U/X#S9n[         R                  R                  SUT/U/US9nTR                  R                  R
                   Vs0 s H  owR                  U_M     nnUR                  TR                  R                  R                   V	s0 s H  oR                  U	_M     sn	5        UR                  TR                  R                  R                   V
s0 s H  oR                  U
_M     sn
5        X;   a#  X   R                  R                  R                  nO[        SU < S35      eTR                  (       Ga,  [        X   R                  R                  R                   R"                  5      nS	/[%        S
U5      QnT" UTR                  5      S:  a1  UR&                  R)                  [        R*                  " SU5      5        O[-        [.        R0                  " 5       5      n[2        R4                  " [6        R8                  " U[6        R:                  S9U5      nUR                  R)                  U5        TR                  R                  R<                  R)                  U5        TR                  R                  R>                  RA                  XV/5        TR                  R                  R                  R)                  [        RB                  " X;S /5      5        g s  snf s  sn	f s  sn
f )Nr
   __Reshape)r#   r   Reshape)inputsoutputsr   z'Unable to guess tensor type for tensor zE, running shape inference before quantization may resolve this issue.r   rg      axesr   )"r  r   	make_noder   r   r   r   r   r   r   rB   r   r   r?   r   rs   r   dimrange	attributeappendmake_attributern   uuiduuid4r	   
from_arrayr   arrayint64r   r   extendmake_tensor_value_info)r   reduce_op_namer#   reduce_outputintermediate_outputreduce_nodereshape_noder   r   oi	onnx_typetensor_rankreduced_axesreduce_axes_namereduce_axesr  reshape_shape_namerE   s                   r   add_reduce_min_max:MinMaxCalibrater.augment_graph.<locals>.add_reduce_min_maxd  s    H (#->M"/*"<++//0C/Dx 0 K  ;;00+-?@&(	 1 L 261A1A1L1LM1L277B;1LKM4::3C3C3J3JK3Ja	3JKL4::3C3C3I3IJ3Ia	3IJK)'499EEOO	 =k_ MZ Z  !+":"?"?"K"K"Q"Q"U"UV !:E![$9:!.$**=B))001F1Fv|1\]'*4::<'8$"."9"9"((<WYW_W_:`br"sK%%,,-=>JJ$$0077DJJ!!((+)DEJJ##**6+H+Hdhci+jk3 NKJs   7L<LL	ReduceMin	ReduceMaxsave_as_external_dataN)r   r   rn   r)  r*  r	   r+  r   r,  r-  r   r   r'  r  saver   r   )rE   tensorsr  reshape_shaper=  tensorr  r<  s   `     @@r   r   MinMaxCalibrater.augment_graphS  s     55djjA
 .$//"RXX0NPbc

$$++M:	U,	l\ Fv{3v{3  			JJ%%"&"?"?	
r   c                     / U l         g rv   r  rN   s    r   clear_collected_data%MinMaxCalibrater.clear_collected_data  
    $&!r   r   c                      UR                  5       nU(       d  OwU R                  R                  U R                  R	                  S U5      5        U R
                  b3  [        U R                  5      U R
                  :X  a  U R                  5         M  [        U R                  5      S:X  a  U R                  c  [        S5      eU R                  5       n[        U[        5      (       d  [        S[        U5       S35      eU R                  5         g )Nr   No data is collected.z+compute_data must return a TensorsData not r8   )r   r  r'  r   runr  rs   rJ  r	  r?   r  rm   rd   ro   rB   )rE   r   r  ts       r   r   MinMaxCalibrater.collect_data  s     ))+F%%,,T-?-?-C-CD&-QR--9112d6S6SS))+  t(()Q.43O3O3W455![))I$q'RSTUU!!#r   c                 X   U(       d  U$ UR                  5        GH  u  p4[        U[        5      (       a  UR                  S   nUR                  S   nOUu  pV[        X#   [        5      (       a#  X#   R                  S   nX#   R                  S   nOX#   u  pxU R                  (       a'  XPR
                  Xu-
  -  -   n	X`R
                  X-
  -  -   n
O[        XW5      n	[        Xh5      n
[        U[        5      (       d  [        X#   [        5      (       a  [        XS9X#'   GM  X4X#'   GM     U$ )Nr   r
   rh   )r=   rm   r.   rO   r  r  minmax)rE   	old_range	new_ranger|   r   old_minold_maxnew_minnew_max	min_value	max_values              r   merge_rangeMinMaxCalibrater.merge_range  s   #//+JC%,,++A.++A.#( ).*55#.44Q7#.44Q7#,> ""#&=&=AR&SS	#&=&=AR&SS	1	1	 %,,
9>:0V0V!+9!P	"+!7	3 ,6 r   r   c                    [        U R                  5      S:X  a  U R                  $ [        [        U R                  S   5      5       Vs/ s H)  oR                  R                  5       U   R                  PM+     nnU R                   Vs/ s H  n[        [        X#SS95      PM     nn0 nU H=  nUR                  5        H&  u  pxUR                  U/ 5      R                  U5        M(     M?     X R                  S n	[        S[        U	5      S5       Vs/ s H  oU   R                  S5      S   PM     n
nU Vs0 s H  oU R                  ;  d  M  XU   _M     nn/ n[        S[        U	5      S5       H  nU R                  (       a8  [         R"                  " XU      SS9n[         R"                  " XUS-         SS9nO7[         R$                  " XU      SS9n[         R&                  " XUS-         SS9nU R(                  (       aU  [         R&                  " [         R*                  " U5      [         R*                  " U5      /SS9nUR                  U* U45        M  UR                  X45        M     [-        [.        R0                  [        [        XSS95      5      nU R                  (       a-  U R3                  U R                  U5      U l        U R                  $ UU l        U R                  $ s  snf s  snf s  snf s  snf )	zt
Compute the min-max range of tensor
:return: dictionary mapping: {added node names: (ReduceMin, ReduceMax) pairs }
r   FstrictNrg   r  r$   r
   )rs   r  r	  r%  r   get_outputsr   r   zipr=   
setdefaultr'  r
  
rpartitionr  r  r   nanmeannanminnanmaxr   absrd   rq   rr   r]  )rE   r6  output_namesr2  output_dicts_listmerged_output_dictdrG   rH   added_output_namescalibrate_tensor_namesmerged_added_output_dictpairsmin_value_arraymax_value_arraymax_absolute_valuenew_calibrate_tensors_ranges                    r   r  MinMaxCalibrater.compute_data  s    t(()Q.///JOPSTXTmTmnoTpPqJrsJrQ**668;@@Jrs (,'@'@
'@# \uEF'@ 	 

  "A	"--a4;;A> " # **@*@*BC>CAsK]G^`a>b"
>bq!,,S1!4>b 	 "

 /A$
.@TMhMhDh$A!$$.@ 	! $
 q#0115A"""$**-EYZF[-\cd"e"$**-EYZ]^Y^F_-`gh"i"$)),DXYEZ,[bc"d"$)),DXY\]X]E^,_fg"h~~%'YY0GP_I`/ahi%j"113EFGo?@ 6 '2$$d3/EUZ+[&\'
# ''+/+;+;D<X<XZu+vD( +++ ,GD(+++U t
"
$
s   	0K.	K3 K89K=	K=)r  r	  r  r  r  r  r
  )Nr  FFF{Gz?NF)rX   r\   r]   r^   rn   r   r   rI   r   rJ  r   r   r]  rd   r  ra   __classcell__rW   s   @r   r  r  )  s{     7;3!&!%'A$J'A  (}t3'A 'ARG
R'$(= $(B3,k 3, 3,r   r  c                      ^  \ rS rSr         SS\\-  S\\   S-  4U 4S jjjrS rS r	S\
4S	 jrS
\4S jrSrU =r$ )HistogramCalibrateri
  Nr   r   c                   > [         TU ]  UUUUUS9  / U l        SU l        [	        U R
                  R                  R                  5      U l        U R
                  R                  R                   Vs1 s H  oR                  iM     snU l
        SU l        XPl        Xpl        Xl        Xl        SU l        Xl        gs  snf )a  
:param model_path: ONNX model to calibrate. It is a model path.
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param use_external_data_format: use external data format to store model which size is >= 2Gb
:param method: A string. One of ['entropy', 'percentile'].
:param symmetric: make range of tensor symmetric (central point is 0).
:param num_bins: number of bins to create a new histogram for collecting tensor values.
:param num_quantized_bins: number of quantized bins. Default 128.
:param percentile: A float number between [0, 100]. Default 99.99.
:param scenario: see :class:`DistributionCalibrater`
)r   r   r   r   N)r  rI   r  r	  rs   r   r   r   r
  r   r  	collectormethodnum_binsnum_quantized_bins
percentiler   scenario)rE   r   r   r   r   r~  r   r  r  r  r  r   rW   s               r   rI   HistogramCalibrater.__init__  s    2 	"7!5%= 	 	
 %'!'+$!$TZZ%5%5%<%<!=AEAQAQAXAX&YAXv{{AX&Y# "4$$(!  'Zs   1B;c                 \   U R                  U R                  5      u  U l        nU R                   HE  nX R                  ;  d  M  U R                  R                  R
                  R                  X   5        MG     [        R                  " U R                  U R                  U R                  S9  g)zk
make all quantization_candidates op type nodes as part of the graph output.
:return: augmented ONNX model
rA  N)r   r   r   r  r   r   r'  r  rC  r   r   )rE   r   rF  s      r   r   !HistogramCalibrater.augment_graph7  s    
 261Q1QRVR\R\1].!;//F888

  ''..{/BC 0 			JJ%%"&"?"?	
r   c                     / U l         g rv   rI  rN   s    r   rJ  (HistogramCalibrater.clear_collected_dataG  rL  r   r   c                    U R                   R                  5        Vs1 s H  o"R                  iM     nnU R                   R                  5        Vs/ s H  o"R                  PM     nn UR	                  5       nU(       d  OU R                   R                  SU5      n/ n[        U5       HE  u  pXH   U;   a'  UR                  [        R                  " U	5      5        M4  UR                  U	5        MG     U R                  R                  U5        M  [        U R                  5      S:X  a  [        S5      eU R                   V
s/ s H  n
[        [        XJSS95      PM     nn
0 nU H=  nUR                  5        H&  u  pUR                  U/ 5      R                  U5        M(     M?     U Vs0 s H  nUU R                   ;   d  M  UUU   _M     nnU R"                  (       dO  [%        U R&                  U R(                  U R*                  U R,                  U R.                  U R0                  S9U l        U R"                  R3                  U5        U R5                  5         gs  snf s  snf s  sn
f s  snf )zi
Entropy Calibrator collects operators' tensors as well as generates tensor histogram for each operator.
Nr   rN  Fr`  )r~  r   r  r  r  r  )r   
get_inputsr   rb  r   rO  	enumerater'  copyr  rs   r?   r   rc  r=   rd  r   r}  HistogramCollectorr~  r   r  r  r  r  collectrJ  )rE   r   node_arginput_names_setrj  r  r   fixed_outputsoutput_indexr   r2  rk  merged_dictrm  rG   rH   r6  clean_merged_dicts                     r   r    HistogramCalibrater.collect_dataJ  s    :>9K9K9V9V9XY9XX==9XY6:6H6H6T6T6VW6V(6VW ))+F((,,T6:G M(1'(:$-@!((6):;!((0	 ); %%,,]; " t(()Q.455 (,'@'@
'@# \uEF'@ 	 

 "A	&&q"-44Q7 " # 9Df1qDLeLeGe.QA.f~~/{{..#'#:#:??DN 	01!!#] ZW,
 gs   III#)I(
I(r   c                    U R                   (       d  [        S5      e[        U [        5      (       a  [        R
                  nOd[        U [        5      (       a  [        R                  nO>[        U [        5      (       a  [        R                  nO[        S[        U 5       S35      e[        XR                   R                  5       5      $ )zh
Compute the min-max range of tensor
:return: dictionary mapping: {tensor name: (min value, max value)}
z9No collector created and can't generate calibration data.zUnknown calibrater z". This method must be overwritten.)r}  r?   rm   EntropyCalibraterrq   r   PercentileCalibraterr   DistributionCalibraterr   ro   rB   rd   compute_collection_result)rE   cals     r   r   HistogramCalibrater.compute_data~  s    
 ~~XYYd-..#++C233#..C455#00C1$t*=_`aa3 H H JKKr   )r	  r}  r  r~  r  r  r
  r  r  r  r   )	Nr  Fr  F      -X@same)rX   r\   r]   r^   rn   r   r   rI   r   rJ  r   r   rd   r  ra   rx  ry  s   @r   r{  r{  
  sv     7;3!&*!$J*!  (}t3*! *!X
 '2$(= 2$hLk L Lr   r{  c                   X   ^  \ rS rSr       SS\\-  S\\   S-  4U 4S jjjrSrU =r	$ )r  i  Nr   r   c	                 .   > [         T	U ]  UUUUUUUUS9  g)a|  
:param model_path: ONNX model to calibrate. It is a model path
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param use_external_data_format: use external data format to store model which size is >= 2Gb
:param method: A string. One of ['entropy', 'percentile', 'distribution'].
:param symmetric: make range of tensor symmetric (central point is 0).
:param num_bins: number of bins to create a new histogram for collecting tensor values.
:param num_quantized_bins: number of quantized bins. Default 128.
)r~  r   r  r  Nr  rI   )
rE   r   r   r   r   r~  r   r  r  rW   s
            r   rI   EntropyCalibrater.__init__  s/    * 	! $1 	 		
r   rb   )Nr  Fr,   Fr  r  
rX   r\   r]   r^   rn   r   r   rI   ra   rx  ry  s   @r   r  r    sC     7;3!&
$J
  (}t3
 
r   r  c                   X   ^  \ rS rSr       SS\\-  S\\   S-  4U 4S jjjrSrU =r	$ )r  i  Nr   r   c	                 .   > [         T	U ]  UUUUUUUUS9  g)ag  
:param model_path: ONNX model to calibrate. It is a model path
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param use_external_data_format: use external data format to store model which size is >= 2Gb
:param method: A string. One of ['entropy', 'percentile', 'distribution'].
:param symmetric: make range of tensor symmetric (central point is 0).
:param num_quantized_bins: number of quantized bins. Default 128.
:param percentile: A float number between [0, 100]. Default 99.99.
)r~  r   r  r  Nr  )
rE   r   r   r   r   r~  r   r  r  rW   s
            r   rI   PercentileCalibrater.__init__  s/    * 	! $! 	 		
r   rb   )Nr  Fr  Fr  r  r  ry  s   @r   r  r    sC     7;3!&
$J
  (}t3
 
r   r  c                   V   ^  \ rS rSr      SS\\-  S\\   S-  4U 4S jjjrSrU =r	$ )r  i  Nr   r   c           
      ,   > [         TU ]  UUUUUUUS9  g)a,  
:param model_path: ONNX model to calibrate. It is a model path
:param op_types_to_calibrate: operator types to calibrate. By default, calibrate all the float32/float16 tensors.
:param augmented_model_path: save augmented model to this path.
:param use_external_data_format: use external data format to store model which size is >= 2Gb
:param method: A string. One of ['entropy', 'percentile', 'distribution'].
:param symmetric: make range of tensor symmetric (central point is 0).
:param num_bins: number of bins to create a new histogram for collecting tensor values.
:param scenario: for float 8 only, if `scenario="same"`,
    the algorithm weights and float 8 follow the same distribution,
    if `scenario="p3"`, it assumes the weights follow
    a gaussian law and float 8 ~ X^3 where X is a gaussian law
)r~  r  r  Nr  )	rE   r   r   r   r   r~  r  r  rW   s	           r   rI   DistributionCalibrater.__init__  s,    . 	! $ 	 	
r   rb   )Nr  Fdistributionr  r  r  ry  s   @r   r  r    s@     7;3!&
$J
  (}t3
 
r   r  c                   `    \ rS rSrSr\R                  S 5       r\R                  S 5       rSr	g)CalibrationDataCollectori  zD
Base class for collecting data for calibration-based quantization.
c                     [         e)zk
Generate informative data based on given data.
    name_to_arr : dict
        tensor name to NDArray data
r   rE   name_to_arrs     r   r   CalibrationDataCollector.collect  s
     "!r   c                     [         e)z/
Get the optimal result among collection data.
r   rN   s    r   r  2CalibrationDataCollector.compute_collection_result  s
    
 "!r   rb   N)
rX   r\   r]   r^   __doc__r   r   r  r  ra   rb   r   r   r  r    s;     	" " 	" "r   r  c                   n    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
 rS r\SS j5       rS rS rSrg)r  i  aL  
Collecting histogram for each tensor. Percentile and Entropy method are supported.

ref: https://github.com//apache/incubator-mxnet/blob/master/python/mxnet/contrib/quantization.py
ref: https://docs.nvidia.com/deeplearning/tensorrt/pytorch-quantization-toolkit/docs/_modules/
             pytorch_quantization/calib/histogram.html
c                 Z    0 U l         Xl        X l        X0l        X@l        XPl        X`l        g rv   )histogram_dictr~  r   r  r  r  r  )rE   r~  r   r  r  r  r  s          r   rI   HistogramCollector.__init__  s)     " "4$ r   c                     U R                   $ rv   )r  rN   s    r   get_histogram_dict%HistogramCollector.get_histogram_dict   s    """r   c                     [        S5        U R                  S;   a  U R                  U5      $ U R                  S:X  a3  U R                  (       a  U R	                  U5      $ U R                  U5      $ [        S5      e)Nz/Collecting tensor data and making histogram ...>   r,   r  r  DOnly 'entropy', 'percentile' or 'distribution' methods are supported)printr~  collect_valuer   collect_absolute_valuer?   r  s     r   r  HistogramCollector.collect#  sl    ?@ ;;55%%k22[[L(~~22;??))+66cddr   c                 
   UR                  5        GHi  u  p#[        U[        5      (       a  U H9  n[        U[        R                  5      (       a  M$   S[        U5       SU< 35       e   U Vs1 s H  oUR                  iM     nn[        U5      S:X  d   SU SU< 35       e[        R                  " U5      nO<[        U[        R                  5      (       d  [        S[        U5       SU< 35      eUnUR                  5       nUR                  S:  a-  [        R                  " U5      n[        R                  " U5      n	O>[        R                  " SUR                  S9n[        R                  " SUR                  S9n	[        R                  " U5      nX R                   ;  at  [        R"                  " XpR$                  S9u  pUR'                  UR                  5      nUR                  [        R(                  :w  d   S5       eXX4U R                   U'   GM	  U R                   U   nUS	   nUS
   n[+        US5      (       d   S[        U5       35       e[+        US5      (       d   S[        U5       35       eUS   nUS   n[        R                  " U5      nUUS   :  aD  US   US   -
  n[        R,                  " US   U-   UU-   U5      n[        R.                  " UU45      n[        R"                  " UUS9u  pUR'                  UR                  5      nU
S[        U5      === U-  sss& UR                  [        R(                  :w  d   S5       eX[1        X5      [3        X5      4U R                   U'   GMl     gs  snf )z%
Collect histogram on absolute value
r9   z for tensor=r
   z6The calibration expects only one element type but got r   r   )r6   zMonly float32 or float16 is supported, every constant must be explicitly typedrg   rj   r   z'old_min should be a numpy array but is r  N)r=   rm   r:   r   ndarrayrB   r   rs   r%   r?   flattensizerg  rh  r,  absoluter  	histogramr  r&   float64rA   arangehstackrS  rT  )rE   r  rF  data_arrarradtypesdata_arr_npr[  r\  r4   r5   old_histogramrW  rX  old_histold_hist_edges	temp_amaxwidthnew_bin_edgess                       r   r  )HistogramCollector.collect_absolute_value2  sE    !, 1 1 3F(D))#C%c2::66l:J4PS9+Uabhak8ll6 $+348a''846{a' LVHT`ag`jk' !jj2"**55 #3DN3C<PVz!Z[[&%--/K!#IIk2	IIk2	HHQk.?.?@	HHQk.?.?@	++k2K000#%<<--#P '..{/@/@A
"((BJJ6 c6 04.V##F+ $ 3 3F ;'*'*w00k4[\`ah\i[j2kk0w00k4[\`ah\i[j2kk0(+!.q!1IIk2	~b11*1-q0AAE$&IInR.@5.H)V[J[]b$cM%'YY/N%ON#%<<.#Q '..{/@/@A
_s8}%1%"((BJJ6 c6 04WAXZ]^eZq.r##F+i !4 5s   /N c           	         UR                  5        GH[  u  p#[        R                  " U5      nUR                  5       nUR                  S:  a-  [        R
                  " U5      n[        R                  " U5      nO>[        R                  " SUR                  S9n[        R                  " SUR                  S9n[        R                  " [        [        U5      [        U5      5      UR                  S9nX R                  ;   a2  U R                  U   nU R                  XsXEU5      U R                  U'   GM#  [        R                  " X0R                  U* U4S9u  pUU	UUU4U R                  U'   GM^     g)z!
Collect histogram on real value
r   r   r%  N)r=   r   r%   r  r  rg  rh  r,  r   rT  ri  r  merge_histogramr  r  )
rE   r  rF  r  r[  r\  	thresholdr  r4   r5   s
             r   r   HistogramCollector.collect_valuel  s+    !, 1 1 3Fzz(+H'')H}}q IIh/	IIh/	HHQhnn=	HHQhnn=	S^S^!DHNN[I,,, $ 3 3F ;.2.B.B!Y9/##F+ $&<<--QZPZ\eOf#g /##F+) !4r   c                    Uu  pgpn
XZ::  a?  [         R                  " U[        U5      U
* U
4S9u  pX-   U[        X5      [	        X5      U
4$ U
S:X  a)  [         R                  " U[        U5      U* U4S9u  pX-  nOb[        U5      nSU
-  U-  n[        XZ-
  U-  S-   5      nUSU-  -   nUU-  U
-   n[         R                  " UUU* U4S9u  pUUUU-
  === U-  sss& UU[        X5      [	        X5      U4$ )Nr  r   rg   r
   )r   r  rs   rS  rT  r   )rE   r  r  rY  rZ  new_thresholdr  r  rW  rX  old_thresholdnew_histr  r4   r5   old_num_bins
old_stridehalf_increased_binsnew_num_binss                      r   r  "HistogramCollector.merge_histogram  s:   FSC7]),,xX~WdFefKH#G%G%  !#%<<#h-Q^P^`mOn#o  "8}.=
&)=+HZ*WZ[*[&\#+a2E.EE 3j @= P#%<<,P]~_lNm#n (<:M+MNRZZNG%G% r   c                 v   U R                   (       a  [        U R                   5      S:X  a  [        S5      e[        SU R                  < S35        U R                  S:X  a  U R                  5       $ U R                  S:X  a  U R                  5       $ U R                  S:X  a  U R                  5       $ [        S5      e)	Nr   z=Histogram has not been collected. Please run collect() first.z0Finding optimal threshold for each tensor using z algorithm ...r,   r  r  r  )r  rs   r?   r  r~  compute_entropycompute_percentilecompute_distributionrN   s    r   r  ,HistogramCollector.compute_collection_result  s    ""c$*=*=&>!&C\]]@~^_;;)#''))[[L(**,,[[N*,,..cddr   c                 v   U R                   S:  d  U R                   S:  a  [        S5      eU R                  nU R                   n0 n[        S[	        U5       35        [        SU R
                   35        [        SSU-
   SU S	35        UR                  5        GH  u  pEUS   nUS
   nUR                  5       n[        R                  " Xh-  5      n	U R                  (       a_  [        R                  " XS-  5      n
[        R                  " Xz   UR                  S9* [        R                  " Xz   UR                  S94X4'   O|SU-
  S-  n[        R                  " U	SU-
  5      n
[        R                  " X5      n[        R                  " X|   UR                  S9[        R                  " Xz   UR                  S94X4'   US   nUS   nX4   S   U:  a  XU   S
   4X4'   X4   S
   U:  a  X4   S   U4X4'   / X4   QUS S Q7X4'   [        R                  R!                  SS5      S;   d  GM  [#        Xg5        GM     U$ )Nr   d   z<Invalid percentile. Must be in range 0 <= percentile <= 100.Number of tensors : Number of histogram bins : zPercentile : (g      Y@,)r
   r   g      i@r"   rg   rj   QUANTIZATION_DEBUG0r
   1)r  r?   r  r  rs   r  r=   r(   r   cumsumr   searchsortedr,  r   osenvirongetr   )rE   r  r  thresholds_dictrF  r  r4   r5   totalcdf	idx_rightpercent_to_cut_one_sideidx_leftr[  r\  s                  r   r  %HistogramCollector.compute_percentile  s.   ??Q$//C"7[\\,,__
$S%8$9:;+DMM?;<uz12!J<qAB!/!5!5!7FQ<D"1JHHJE))DL)C~~OOCe1CD	 XXj3:;K;KLLHHZ2*:J:JK+'
 ,1:+=*F'OOC7N1NO	??3HHHZ19I9IJHHZ2*:J:JK+' "!I!!I&q)I5+4f6Ma6P*Q'&q)I5+:+B1+Ey*Q'&K(?&K$r(&KO#zz~~2C8HD4,; "8> r   c                    U R                   nU R                  n0 n[        S[        U5       35        [        SU R                   S35        [        SU R                   35        UR                  5        H^  u  pEU R                  XR5      nXcU'   / UQUS S Q7X4'   [        R                  R                  SS5      S;   d  ML  [        US	   US
   5        M`     U$ )Nr  r  z: (The number may increase depends on the data it collects)zNumber of quantized bins : rg   r  r  r  r   r
   )r  r  r  rs   r  r=   get_entropy_thresholdr  r  r  r   )rE   r  r  r  rF  r  optimal_thresholds          r   r  "HistogramCollector.compute_entropy  s    ,,!44$S%8$9:;+DMM?:tuv+D,C,C+DEF!/!5!5!7F $ : :9 Y&7F#&J(9&JIbqM&JO# zz~~2C8HD9Q<16 "8 r   c                    US::  a  [        SU S35      eUS S USS  -   S-  nUS:X  a  X-  R                  5       U R                  5       -  nXS-  -  R                  5       U R                  5       -  US-  -
  S-  n[        R                  " XAR                  S9[        R                  " XQR                  S94$ [        U5      U:X  a  [        U5      S-  S:X  a  XU-  -  R                  5       U R                  5       -  nXU-  U-
  S-  -  R                  5       U R                  5       -  S-  n[        R                  " XAR                  S9[        R                  " XQR                  S94$ [        R                  " U5      U-  nSU[        R                  " U5      '   SU[        R                  " U5      '   [        R                  " U5      U-  U-  nX-  R                  5       U R                  5       -  nXS-  -  R                  5       U R                  5       -  US-  -
  S-  n[        R                  " XAR                  S9[        R                  " XQR                  S94$ )	Nr   zpower=z <= 0 is invalid.r  r
   g      ?rg   r   )	r?   r(   r   r,  r   r   ri  isnanisinf)r4   r5   powerr   r0   r1   facts          r   _avg_stdHistogramCollector._avg_std  s   A:veW,=>??Sb/JqrN2c9A:=%%'$((*4C19$))+dhhj836AcIC88C'7'78"((3N^N^:___u:3u:>Q#6%-',,.;CEMC/A55::<txxzIcQC88C'7'78"((3N^N^:___vvf~& RXXd^ RXXd^5(4/}!!#dhhj0qy %%'$((*4sAv=#Exx#3#34bhhsJZJZ6[[[r   c           
         U R                   S:  a  [        S5      eU R                  n0 n[        S[	        U5       35        [        SU R                    35        [        SU R
                  < S35        UR                  5        GH?  u  p4US   nUS   nUR                  [        R                  :w  d   eU R
                  S	:X  a  U R                  XVSS
9u  pxO.U R
                  S:X  a  U R                  XVSS
9u  pxO[        S5      eUR                  [        R                  :w  d   eUR                  [        R                  :w  d   eUR                  [        R                  :w  d   e[        UUUUUR                  5       UR                  5       S9X#'   [        R                  R!                  SS5      S;   d  GM4  [#        XV5        GMB     U$ )Ni   z3Invalid num_bins. Must be in range 512 <= num_bins.r  r  zScenario : r  r   r
   r  )r  p3gUUUUUU?z,Invalid scenario. Must be in {'same', 'p3'}.)r0   r1   r4   r5   r2   r3   r  r  r  )r  r?   r  r  rs   r  r=   r   r   r  r	  r.   rS  rT  r  r  r  r   )	rE   r  r  rF  r  r4   r5   avg_coefstd_coefs	            r   r  'HistogramCollector.compute_distribution  s   ==3RSS,,$S%8$9:;+DMM?;<DMM,A./!/!5!5!7FQ<D"1J##rzz111}}&%)]]41]%M"($&%)]]49]%U"( !OPP>>RZZ///>>RZZ///##rzz111&0%!~~'"('O# zz~~2C8HD4,3 "86 r   c           	      &   US   nUS   nUR                   nUS-  nUS-  nUS   R                  n[        R                  " Xg-
  S-   5      n	[	        U	R                   5       V
s/ s H-  n
[        R
                  " SUS9[        R
                  " SUS94PM/     nn
[	        XvS-   S5       GH  n
Xj-
  n[        Xj-   S-   U5      nXL   XM   4XU-
  '   [        R                  " X<U 5      nUR                  5       n[        USU 5      n[        X=S 5      nUS==   U-  ss'   US==   U-  ss'   US:g  R                  [        R                  5      n[        R                  " U[        R                  S9nUR                   U-  n[	        U5       H  nUU-  nUU-   n[        UUU 5      UU'   M      US==   [        XU-  S 5      -  ss'   [        R                  " UR                   [        R                  S9n[	        U5       H.  nUU-  nUU-   n[        UUU 5      nUS:w  d  M#  UU   U-  UUU& M0     [        U5      n[        U5      nUb  Uc$  [        R
                  " [        R                  US9nO[        R
                  " [        UU5      US9nUXU-
  '   GM     [        R                  " U	5      nUU   nUS   nUS   nUS   U:  a  UUS   4nUS   U:  a  US   U4n[!        US   S5      (       d   e[!        US   S5      (       d   eU$ s  sn
f )	a&  Given a dataset, find the optimal threshold for quantizing it.
The reference distribution is `q`, and the candidate distribution is `p`.
`q` is a truncated version of the original distribution.
Ref: http://on-demand.gputechconf.com/gtc/2017/presentation/s7310-8-bit-inference-with-tensorrt.pdf
r   r
   rg   r   Nr  rj   r   )r  r   r   zerosr%  r,  rS  r  deepcopyr(   r&   r-  r   r   r,   argminrA   )rE   r  r  r4   r5   r  zero_bin_indexnum_half_quantized_binr   kl_divergencer6  
thresholdsr   r   sliced_distributionpleft_outliers_countright_outliers_countnonzerosquantized_binsnum_merged_binsindexstartendqnormdivmin_kl_divergence_idxr  r[  r\  s                                  r   r  (HistogramCollector.get_entropy_threshold;  sU    |q\
99!Q!3q!8!""!H1!LMTYZgZlZlTmnTmqrxx/!51IJTm
n  -/A1EA(,KN.2H=I6@6MzOd5eJ112"&--0K"L $((*A"%d<K&8"9#&tJ'7#8 aD''DbE))E Qrxx0H  XX&8IN166:LLO 12/o-(+,?c,J(Ku% 3 2#&9:^:`&a"bb rxx0A12/o-8E#./19#1%#84#?AeCL 3 $A&A#A&AyAIhhrvvU3hhwq!}E:8;M445] F` !#		- 8&'<=aL	aL	Q)+!*,=a,@ AQ)+!21!5y A(+W5555(+W5555  U os   "4L)r  r~  r  r  r  r  r   N)r
   )rX   r\   r]   r^   r  rI   r  r  r  r  r  r  r  r  staticmethodr	  r  r  ra   rb   r   r   r  r    s]    !#e8st@@e,\* \ \*&PX!r   r  r  Fr   r   c                    S nU[         R                  :X  al  UR                  SS5      nUR                  SS5      n	UR                  SS5      n
UR                  SS 5      nUR                  SS5      n[        U UUUUU	U
UUS9	nOU[         R                  :X  aF  UR                  S	S
5      nUR                  SS
5      nUR                  SS5      n[        U UUUUUUS9nOU[         R                  :X  aF  UR                  S	S5      nUR                  SS5      nUR                  SS5      n[        U UUUUUUS9nOFU[         R                  :X  a2  UR                  S	S5      nUR                  SS5      n[        U UUUUUS9nU(       a/  UR                  5         U(       a  XWl        UR                  5         U$ [        SU 35      e)Nr   Fr  r  rw  r  r   )r   r   r  r  r  r   r  r  r  )r   r   r  r  r  r  r  T)r   r   r  r  r  r  )r   r  r  zUnsupported calibration method )rq   rr   r  r  r   r  r   r  r   r  r   r   r   r?   )r   r   r   calibrate_methodr   r   extra_options
calibratorr   r  r  r  r   r  r  r  r  s                    r   create_calibratorr,    s    J,333!%%k59	&**+;UC*../CTJ#0#4#45OQU#V #''u=%! %=)1%=#


 
.66	6 $$Z5*../CSI!%%k59	&! %=1

 
.99	9 $$Z6"&&|V<
!%%k48	)! %=!

 
.;;	; $$Z6 $$Z8+! %=

   "-6*++-
67G6HI
JJr   )Nr   ),r   r  r   r  r)  collections.abcr   enumr   pathlibr   numpyr   r  r   r   r   r	   r   quant_utilsr   r   r   r  r   floatr   r,   r.   rd   rq   ABCMetar   r   r  r{  r  r  r  r  r  rr   rn   r,  rb   r   r   <module>r4     s      	  $     > >  U U  

 " 	





 $, 	
 ZZ8   F1 1h "ckk "4k" k"\^,~ ^,BDL. DLN
+ 
D
. 
D 
0  
F" ",E!1 E!T 37/&--"NK:NK#C=4/NKr   