§
    �Wêj$G  ã                   óž  — d Z ddlZddlmZmZ ddlmZ dZdZ	dZ
dZ ee
¦  «         ee¦  «        z  Zd	ej        d
ej        fd„Zdej        d
ej        fd„Zdej        d
ej        fd„Zdej        d
ej        fd„Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z	 	 d"dej        deeeeeef                  dedededed
ej        fd„Z G d „ d!¦  «        ZdS )#a?  
Adaptive RoI-pooling feature extraction.

Automatically dispatches between:
  - Naive per-bbox loop: zero setup cost, best for small B
  - SAT (integral image) path: O(C*H*W) setup, O(1) per-bbox mean/min/max query,
    best for large B

Calibrated for ~300x300 feature maps with C~10.

Crossover points (B * avg_patch_area / H*W):
  - entropy/margin requested: ~2.0   (SAT setup amortized across the extra maps)
  - otherwise:                ~50.0  (naive loop is extremely fast without probs)

Pooling ops (pooling_ops parameter)
------------------------------------
Two families of ops are supported, and they behave differently:

  - Per-channel ops:  'mean', 'min', 'max'
        Each produces one value per input channel (C dims).
  - Per-region ops:   'entropy', 'margin'
        Each collapses the channel axis into a single confidence/uncertainty
        scalar per bbox (1 dim). Always computed from channel-softmax
        probabilities regardless of `apply_softmax` (they are only
        meaningful over a probability distribution).

The output is the concatenation of all requested per-channel ops (in the
order given, each C-wide) followed by all requested per-region ops (in the
order given, each 1-wide). For example pooling_ops=('mean', 'min', 'max',
'entropy', 'margin') on a C-channel input produces a (B, 3*C + 2) array.
é    N)ÚListÚTuple)Údefaultdict©ÚmeanÚmax)r   Úminr   ÚentropyÚmargin)r   r	   r   )r
   r   ÚfmapÚreturnc                 ó0  — | j         \  }}}|                      |d¦  «                             ¦   «         }||                     dd¬¦  «        z  }t	          j        ||¬¦  «         ||                     dd¬¦  «        dz   z  }|                     |||¦  «        S )z8Channel-wise softmax along axis=0 of a (C, H, W) tensor.éÿÿÿÿr   T)ÚaxisÚkeepdims)Úoutçê-�™—q=)ÚshapeÚreshapeÚcopyr   ÚnpÚexpÚsum)r   ÚCÚHÚWÚfs        úŒ/Users/tedpeters/Documents/Projects/Claude Projects/TPC Houses/house-viewer/.venv/lib/python3.11/site-packages/pymupdf/layout/roi_pooling.pyÚ_softmax_channelsr   5   s’   € àŒj�G€A€qˆ!Ø�Š�Q˜ÑÔ× Ò Ñ"Ô"€AØˆ�Š�A ˆÑ	%Ô	%Ñ%€AÝ„Fˆ1�!ÐÑÔÐØˆ�Š�A ˆÑ	%Ô	%¨Ñ	-Ñ-€AØ�9Š9�Q˜˜1ÑÔÐó    Úprobsc                 ód   — d}| t          j        | |z   ¦  «        z                       d¬¦  «         S )zAPer-pixel entropy of a (C, H, W) probability map. Returns (H, W).r   r   ©r   )r   Úlogr   )r!   Úepss     r   Ú_pixel_entropyr&   ?   s4   € à
€CØ•R”V˜E C™KÑ(Ô(Ñ(×-Ò-°1Ð-Ñ5Ô5Ð5Ð5r    c                 óò   — | j         d         }|dk     r| d         S t          j        | dd¬¦  «        dd…         }t          j        | |d¬¦  «        }|                     d¬¦  «         |d         |d         z
  S )zJPer-pixel top1-top2 margin of a (C, H, W) probability map. Returns (H, W).r   é   éþÿÿÿr#   Né   )r   r   ÚargpartitionÚtake_along_axisÚsort)r!   r   ÚidxÚtop2s       r   Ú_pixel_marginr0   E   s|   € àŒ�AŒ€AØˆ1‚u€uØ�QŒxˆÝ
Œ/˜% ¨!Ð
,Ñ
,Ô
,¨R¨S¨SÔ
1€CÝÔ˜e S¨qÐ1Ñ1Ô1€DØ‡I‚I�1€IÑÔÐØ�Œ7�T˜!”WÑÐr    Úarrc           	      ó\  — | j         dd…         }| j         d         | j         d         }}t          j        g |¢|dz   ‘|dz   ‘R t          j        ¬¦  «        }t          j        | d|ddd…dd…f         ¬¦  «         t          j        |ddd…dd…f         d|ddd…dd…f         ¬¦  «         |S )zBSummed Area Table over the last two axes. Returns (..., H+1, W+1).Nr)   r   r*   ©Údtype.)r   r   )r   r   ÚzerosÚfloat64Úcumsum)r1   Úprefixr   r   Úsats        r   Ú
_build_satr:   P   sÃ   € àŒY�s˜�sŒ^€FØŒ9�RŒ=˜#œ) Bœ-€q€AÝ
Œ(Ð*�VÐ*˜Q ™UÐ* A¨¡EÐ*Ð*µ"´*Ð
=Ñ
=Ô
=€CÝ„Iˆc˜  C¨¨¨¨Q¨R¨R KÔ 0Ð1Ñ1Ô1Ð1Ý„Iˆc�#�q�r�r˜1˜2˜2�+Ô R¨S°°a°b°b¸!¸"¸"°Ô-=Ð>Ñ>Ô>Ð>Ø€Jr    c                 óx   — | d|dz   |dz   f         | d||dz   f         z
  | d|dz   |f         z
  | d||f         z   S )z8Vectorized rectangle sum on a SAT. Coords are inclusive..r*   © )r9   Úy1Úx1Úy2Úx2s        r   Ú_sat_rect_sumrA   Z   sc   € ð 	ˆC��a‘˜˜a™ÐÔ Ø
ˆc�2�r˜A‘vˆoÔ
ñ	à
ˆc�2˜‘6˜2ˆoÔ
ñ	ð ˆc�2�rˆkÔ
ñ	ðr    c                 ó^  — |t          |¦  «        z  }|t          |¦  «        z  }t          j        | dd…df         |z  ¦  «                             t          j        ¦  «                             d|dz
  ¦  «        }t          j        | dd…df         |z  ¦  «                             t          j        ¦  «                             d|dz
  ¦  «        }t          j        | dd…df         |z  ¦  «                             t          j        ¦  «        dz
                       d|dz
  ¦  «        }	t          j        | dd…df         |z  ¦  «                             t          j        ¦  «        dz
                       d|dz
  ¦  «        }
t          j        |	|¦  «        }	t          j        |
|¦  «        }
|||	|
fS )z<Map image-space bboxes to feature-grid indices (vectorized).Nr   r*   r(   é   )Úfloatr   ÚfloorÚastypeÚintpÚclipÚceilÚmaximum)Úbbr   r   Ú
page_widthÚpage_heightÚsxÚsyÚgx1Úgy1Úgx2Úgy2s              r   Ú_grid_coords_vecrT   d   sm  € à	
�U�:ÑÔÑ	€BØ	
�U�;ÑÔÑ	€BÝ
Œ(�2�a�a�a˜�d”8˜b‘=Ñ
!Ô
!×
(Ò
(­¬Ñ
1Ô
1×
6Ò
6°q¸!¸a¹%Ñ
@Ô
@€CÝ
Œ(�2�a�a�a˜�d”8˜b‘=Ñ
!Ô
!×
(Ò
(­¬Ñ
1Ô
1×
6Ò
6°q¸!¸a¹%Ñ
@Ô
@€CÝŒ7�2�a�a�a˜�d”8˜b‘=Ñ!Ô!×(Ò(­¬Ñ1Ô1°AÑ5×
;Ò
;¸A¸qÀ1¹uÑ
EÔ
E€CÝŒ7�2�a�a�a˜�d”8˜b‘=Ñ!Ô!×(Ò(­¬Ñ1Ô1°AÑ5×
;Ò
;¸A¸qÀ1¹uÑ
EÔ
E€CÝ
Œ*�S˜#Ñ
Ô
€CÝ
Œ*�S˜#Ñ
Ô
€CØ��S˜#ÐÐr    c                 ó:   — d„ | D ¦   «         }d„ | D ¦   «         }||fS )z~Split a pooling_ops tuple into (channel_ops, region_ops), each
    preserving the relative order they appeared in pooling_ops.c                 ó$   — g | ]}|t           v ¯|‘ŒS r<   )Ú_CHANNEL_OPS©Ú.0Úops     r   ú
<listcomp>z_split_ops.<locals>.<listcomp>t   s"   € ÐBÐBÐB˜"¨rµ\Ð/AÐ/A�2Ð/AÐ/AÐ/Ar    c                 ó$   — g | ]}|t           v ¯|‘ŒS r<   )Ú_REGION_OPSrX   s     r   r[   z_split_ops.<locals>.<listcomp>u   s"   € Ð@Ð@Ð@˜¨bµKÐ.?Ð.?�"Ð.?Ð.?Ð.?r    r<   )Úpooling_opsÚchannel_opsÚ
region_opss      r   Ú
_split_opsra   q   s6   € ð CÐB ÐBÑBÔB€KØ@Ð@˜{Ð@Ñ@Ô@€JØ˜
Ð"Ð"r    c                 óF   — | t          |¦  «        z  t          |¦  «        z   S ©N)Úlen)r   r_   r`   s      r   Ú_output_dimre   y   s    € Ø�s�;ÑÔÑ¥# j¡/¤/Ñ1Ð1r    c           	      óè  — t          |¦  «        \  }}| j        d         }	t          |¦  «        }
t          |	||¦  «        }t	          j        |
|ft          j        ¬¦  «        }t          |
¦  «        D �]ÿ}||         ||         ||         ||         f\  }}}}| d d …||dz   …||dz   …f         }|j        dk    rŒIg }|D ]‘}|dk    r*| 	                    | 
                    d¬¦  «        ¦  «         Œ2|dk    r*| 	                    |                     d¬¦  «        ¦  «         Œb|dk    r)| 	                    |                     d¬¦  «        ¦  «         Œ’|r·|d d …||dz   …||dz   …f         }|D ]�}|d	k    rH| 	                    t	          j        t          |¦  «         
                    ¦   «         g¦  «        ¦  «         ŒP|d
k    rG| 	                    t	          j        t          |¦  «         
                    ¦   «         g¦  «        ¦  «         Œž|rt	          j        |¦  «        nt	          j        dt          j        ¬¦  «        }|                     t          j        ¦  «        ||d |j        d         …f<   �Œ|S )Nr   r3   r*   r   )r*   r(   r#   r   r	   r
   r   )ra   r   rd   re   r   r5   Úfloat32ÚrangeÚsizeÚappendr   r   r	   Úarrayr&   r0   ÚconcatenaterF   )Ú	fmap_usedr!   rP   rQ   rR   rS   r^   r_   r`   r   ÚBÚout_dimr   ÚiÚy1iÚy2iÚx1iÚx2iÚpatchÚpartsrZ   ÚppÚpooleds                          r   Ú_path_naivery   �   sq  € Ý(¨Ñ5Ô5Ñ€K�ØŒ˜Ô€AÝˆC‰Œ€AÝ˜!˜[¨*Ñ5Ô5€GÝ
Œ(�A�w�<¥r¤zÐ
2Ñ
2Ô
2€Cå�1‰XŒXð =ñ =ˆØ  œV S¨¤V¨S°¬V°S¸´VÐ;ÑˆˆS�#�sØ˜!˜!˜!˜S  q¡˜[¨#¨c°A©g¨+Ð5Ô6ˆØŒ:˜Š?ˆ?ØàˆØð 	5ð 	5ˆBØ�VŠ|ˆ|Ø—’˜UŸZšZ¨V˜ZÑ4Ô4Ñ5Ô5Ð5Ð5Ø�u’�Ø—’˜UŸYšY¨F˜YÑ3Ô3Ñ4Ô4Ð4Ð4Ø�u’�Ø—’˜UŸYšY¨F˜YÑ3Ô3Ñ4Ô4Ð4øàð 	GØ�q�q�q˜#˜c A™g˜+ s¨3°©7 {Ð2Ô3ˆBØ ð Gð G�Ø˜’?�?Ø—L’L¥¤­>¸"Ñ+=Ô+=×+BÒ+BÑ+DÔ+DÐ*EÑ!FÔ!FÑGÔGÐGÐGØ˜8’^�^Ø—L’L¥¤­=¸Ñ+<Ô+<×+AÒ+AÑ+CÔ+CÐ*DÑ!EÔ!EÑFÔFÐFøà*/ÐR•” Ñ&Ô&Ð&µR´X¸aÅrÄzÐ5RÑ5RÔ5RˆØ#)§=¢=µ´Ñ#<Ô#<ˆˆAÐ�”˜Q”ÐÐÑ Ñ Ø€Jr    c                 óœ  — | j         d         }t          |¦  «        }|r"t          j        ||ft          j        ¬¦  «        nd}	|r"t          j        ||ft          j        ¬¦  «        nd}
||z
  dz   }||z
  dz   }t          t          ¦  «        }t          |¦  «        D ]E}|t          ||         ¦  «        t          ||         ¦  «        f          	                    |¦  «         ŒF| 
                    ¦   «         D ]Ó\  \  }}}t          j        |t          j        ¬¦  «        }t          |¦  «        }t          j        ||||f| j        ¬¦  «        }t          |¦  «        D ]7\  }}| dd…||         ||         |z   …||         ||         |z   …f         ||<   Œ8|r|                     d¬¦  «        |	|<   |r|                     d¬¦  «        |
|<   ŒÔ|	|
fS )a­  
    Compute per-bbox min and/or max via grouped batch slicing: bboxes with
    the same (height, width) in feature-grid units are stacked into one
    array and reduced together, avoiding a per-bbox python loop.

    min/max cannot be expressed via a summed-area table (unlike mean), so
    this always has to run against the actual bboxes -- there is nothing
    here that can be precomputed once and reused across different bbox
    sets (contrast with RoiPoolingSession's sat_mean / sat_region, which
    ARE bbox-independent and shareable).

    Returns:
        (max_all, min_all) -- each either an (B, C) float32 array or None
        depending on whether it was requested.
    r   r3   Nr*   )r(   rC   r#   )r   rd   r   Úemptyrg   r   Úlistrh   Úintrj   Úitemsrk   rG   r4   Ú	enumerater   r	   )rm   rP   rQ   rR   rS   Úneed_maxÚneed_minr   rn   Úmax_allÚmin_allÚph_arrÚpw_arrÚgroupsrp   ÚphÚpwÚindicesr.   ÚnÚpatchesÚjÚbis                          r   Ú_grouped_minmaxrŽ   ¨   sÕ  € ð  	Œ˜Ô€AÝˆC‰Œ€AØ4<ÐF�bŒh˜˜1�v¥R¤ZÐ0Ñ0Ô0Ð0À$€GØ4<ÐF�bŒh˜˜1�v¥R¤ZÐ0Ñ0Ô0Ð0À$€Gà�3‰Y˜‰]€FØ�3‰Y˜‰]€FÝ�ÑÔ€FÝ�1‰XŒXð ;ð ;ˆØ•�F˜1”I‘”¥ F¨1¤I¡¤Ð/Ô0×7Ò7¸Ñ:Ô:Ð:Ð:Ø#Ÿ\š\™^œ^ð 	4ð 	4Ñ‰ˆˆR�'ÝŒh�w¥b¤gÐ.Ñ.Ô.ˆÝ�‰HŒHˆÝ”(˜A˜q " b˜>°´ÐAÑAÔAˆÝ˜s‘^”^ð 	Rð 	R‰EˆAˆrØ" 1 1 1 c¨"¤g¨c°"¬g¸©lÐ&:¸CÀ¼GÀCÈÄGÈbÁLÐ<PÐ#PÔQˆG�A‰JˆJØð 	4Ø"Ÿ;š;¨F˜;Ñ3Ô3ˆG�C‰LØð 	4Ø"Ÿ;š;¨F˜;Ñ3Ô3ˆG�C‰LøØ�GÐÐr    c           	      óx  ‡‡— t          |¦  «        \  }}| j        \  }	}
}t          |¦  «        }||z
  dz   ||z
  dz   z                       t          j        ¦  «        }d }d|v r[t          | ¦  «        }t          |||||¦  «        |t          j        d d …f         z  j	                             t          j
        ¦  «        }d|v }d|v }|s|rt          | ||||||¦  «        nd\  }}|||dœŠi Š|D ]t}|dk    rt          |¦  «        }n|dk    rt          |¦  «        }t          |¦  «        }t          |||||¦  «        |z                       t          j
        ¦  «        }|‰|<   Œuˆfd	„|D ¦   «         }|ˆfd
„|D ¦   «         z  }|s"t	          j        |dft          j
        ¬¦  «        S t	          j        |d¬¦  «        S )Nr*   r   r   r	   ©NN©r   r   r	   r
   r   c                 ó    •— g | ]
}‰|         ‘ŒS r<   r<   ©rY   rZ   Úchannel_resultss     €r   r[   z_path_sat.<locals>.<listcomp>ï   s   ø€ Ð7Ð7Ð7 Rˆ_˜RÔ Ð7Ð7Ð7r    c                 óH   •— g | ]}‰|         d d …t           j        f         ‘ŒS rc   )r   Únewaxis)rY   rZ   Úregion_resultss     €r   r[   z_path_sat.<locals>.<listcomp>ð   s-   ø€ ÐEÐEÐE°Bˆn˜RÔ    ¥B¤J Ô/ÐEÐEÐEr    r   r3   r#   )ra   r   rd   rF   r   r6   r:   rA   r–   ÚTrg   rŽ   r&   r0   r5   rl   )rm   r!   rP   rQ   rR   rS   r^   r_   r`   r   r   r   rn   ÚareasÚmean_allÚsat_fr€   r�   r‚   rƒ   rZ   Ú
region_mapÚsat_rÚregion_meanrv   r”   r—   s                            @@r   Ú	_path_satrŸ   Ï   s  øø€ Ý(¨Ñ5Ô5Ñ€K�ØŒo�G€A€qˆ!ÝˆC‰Œ€AØ�C‰i˜!‰m  c¡	¨A¡Ñ.×6Ò6µr´zÑBÔB€Eà€HØ�ÐÐÝ˜9Ñ%Ô%ˆÝ! %¨¨c°3¸Ñ<Ô<Ø�BœJ¨¨¨˜MÔ*ñ+Ü,-¯fªfµR´ZÑ.@Ô.@ð 	ð ˜Ð#€HØ˜Ð#€Hð ð	4Ø ð	4�˜	 3¨¨S°#°xÀÑJÔJÐJØ'3ñ €GˆWð
  (°ÀÐHÐH€Oà€NØð )ð )ˆØ�Š?ˆ?Ý'¨Ñ.Ô.ˆJˆJØ�8Š^ˆ^Ý& uÑ-Ô-ˆJÝ˜:Ñ&Ô&ˆÝ$ U¨C°°c¸3Ñ?Ô?Øñß &¢¥r¤zÑ 2Ô 2ð 	à(ˆ�rÑÐà7Ð7Ð7Ð7¨;Ð7Ñ7Ô7€EØ	ÐEÐEÐEÐE¸*ÐEÑEÔEÑE€Eàð 2ÝŒx˜˜A˜¥b¤jÐ1Ñ1Ô1Ð1ÝŒ>˜% aÐ(Ñ(Ô(Ð(r    FÚfeaturesÚbboxesrL   rM   r^   Úapply_softmaxc           	      óÀ  — | j         dk    sJ ‚| j        \  }}}}	|dk    sJ ‚t          |¦  «        t          z
  }
|
r5t	          dt          |
¦  «        › dt          t          ¦  «        › d�¦  «        ‚t          |¦  «        \  }}t          |¦  «        }t          |¦  «        }|dk    r1t          j
        dt          |||¦  «        ft          j        ¬¦  «        S | d         }t          j        |t          j        ¬¦  «        }t          ||	|||¦  «        \  }}}}t!          ||z
  dz   ||z
  dz   z                       ¦   «         ¦  «        }||z  t!          ||	z  ¦  «        z  }|rdnd	}||k    }|r1|s|rt%          |¦  «        }nd
}|r|n|}t'          |||||||¦  «        S |rt%          |¦  «        }|r|nd
}n|}|rt%          |¦  «        nd
}t)          |||||||¦  «        S )al  
    Extract per-bbox features via configurable pooling ops.

    Args:
        features: (1, C, H, W) feature map (raw activations or logits).
        bboxes: list of [x1, y1, x2, y2] in the same coordinate space as
            page_width/page_height (NOT necessarily the feature map's own
            H/W; this function rescales internally).
        page_width, page_height: dimensions of the coordinate space the
            bboxes are expressed in (e.g. the page raster used to run the
            model, not the model's internal H/W).
        pooling_ops: subset of {'mean', 'min', 'max', 'entropy', 'margin'}.
            - 'mean'/'min'/'max' are per-channel (C dims each) and are
              computed on `features` directly, or on softmax(features) if
              apply_softmax=True.
            - 'entropy'/'margin' are per-region scalars (1 dim each) and are
              ALWAYS computed on softmax(features), regardless of
              apply_softmax -- they are only meaningful over a probability
              distribution, so this is not user-configurable.
            Output is the concatenation of per-channel ops (in the order
            given) followed by per-region ops (in the order given).
        apply_softmax: whether the per-channel ops ('mean'/'min'/'max') pool
            over raw `features` or over channel-softmax probabilities.
            Has no effect on 'entropy'/'margin'.

    Returns:
        np.ndarray of shape (B, C*len(channel_ops) + len(region_ops)).

    Adaptively dispatches between a naive per-bbox loop and a SAT-based
    vectorized path based on the estimated computational cost ratio.
    é   r*   úUnknown pooling_ops: ú. Valid ops are ú.r   r3   g       @g      I@N)Úndimr   ÚsetÚ
_VALID_OPSÚ
ValueErrorÚsortedra   Úboolrd   r   r5   re   rg   Úasarrayr6   rT   rD   r   r   rŸ   ry   )r    r¡   rL   rM   r^   r¢   ÚNr   r   r   Úunknown_opsr_   r`   Úneeds_probsrn   r   rK   rP   rQ   rR   rS   Úavg_patch_areaÚcost_metricÚ	thresholdÚuse_satr!   rm   s                              r   Ú$extract_bbox_features_by_roi_poolingr¶   û   sK  € ðN Œ=˜AÒÐÐÐØ”�J€A€qˆ!ˆQØ�Š6ˆ6ˆ6ˆ6å�kÑ"Ô"¥ZÑ/€KØð AÝð @µ¸Ñ1DÔ1Dð @ð @Ý*0µÑ*<Ô*<ð@ð @ð @ñ Aô Að 	Aõ )¨Ñ5Ô5Ñ€K�Ý�zÑ"Ô"€KåˆF‰Œ€AØˆA‚v€vÝŒx˜�K¨¨;¸
ÑCÔCÐDÍBÌJÐWÑWÔWÐWà�AŒ;€DÝ	Œ�F¥"¤*Ð	-Ñ	-Ô	-€BÝ)¨"¨a°°JÀÑLÔLÑ€Cˆˆc�3õ ˜S 3™Y¨™]¨s°S©y¸1©}Ñ=×CÒCÑEÔEÑFÔF€NØ�nÑ$¥u¨Q°©U¡|¤|Ñ3€KØ"Ð,��¨€Ià˜IÒ%€Gàð Nàð 	˜Kð 	Ý% dÑ+Ô+ˆEˆEàˆEØ*Ð4�E�E°ˆ	Ý˜ E¨3°°S¸#¸{ÑKÔKÐKð ð 	EÝ)¨$Ñ/Ô/ˆIØ!,Ð6�I�I°$ˆEˆEàˆIØ/:ÐDÕ% dÑ+Ô+Ð+ÀˆEÝ˜9 e¨S°#°s¸CÀÑMÔMÐMr    c                   óx   — e Zd ZdZ	 	 ddej        dedefd„Zde	e
eeeef                  d	ed
edej        fd„ZdS )ÚRoiPoolingSessionaC  
    Precomputes the bbox-INDEPENDENT parts of ROI pooling once for a given
    (features, pooling_ops, apply_softmax) combination, then lets you
    query() it against multiple different bbox sets cheaply.

    Motivating case: BoxRFDGNN pools the same feature_map/class_logits
    tensor twice per page -- once for node bboxes, once for edge-union
    bboxes (when use_image_edge=True). Calling
    extract_bbox_features_by_roi_pooling() twice rebuilds the channel
    softmax and the 'mean'/'entropy'/'margin' summed-area tables (SATs)
    twice, even though those depend only on the tensor + pooling_ops, not
    on which bboxes are being queried. This class builds them once and
    reuses them for every query() call.

    'min'/'max' are NOT expressible via a SAT (unlike mean), so they are
    always recomputed per query() call directly from that call's bboxes
    (grouped batch slicing) -- there is nothing to share for those ops.

    When to use this vs. extract_bbox_features_by_roi_pooling():
      - Querying a tensor ONCE (e.g. YF's per-page feature map): use the
        plain function. It dispatches naive-vs-SAT based on bbox count, so
        small queries stay cheap; a session would force the SAT build cost
        even for a single small query.
      - Querying the SAME tensor MULTIPLE times (e.g. node bboxes then edge
        bboxes against the same feature_map): use a session. The one-time
        SAT build cost is paid once and amortized across all query() calls,
        which is strictly cheaper than paying it (or the naive-path cost)
        separately per call.
    r   Fr    r^   r¢   c                 ó¢  — |j         dk    sJ ‚|j        \  }}}}|dk    sJ ‚t          |¦  «        t          z
  }|r5t	          dt          |¦  «        › dt          t          ¦  «        › d�¦  «        ‚|||c| _        | _        | _        t          |¦  «        \  | _
        | _        |d         }	t          | j        ¦  «        }
|s|
rt          |	¦  «        }nd }|r|n|	| _        d| j
        v rt          | j        ¦  «        nd | _        i | _        | j        D ]=}|dk    rt%          |¦  «        nt'          |¦  «        }t          |¦  «        | j        |<   Œ>d S )	Nr¤   r*   r¥   r¦   r§   r   r   r
   )r¨   r   r©   rª   r«   r¬   Ú_CÚ_HÚ_Wra   Ú_channel_opsÚ_region_opsr­   r   Ú
_fmap_usedr:   Ú	_sat_meanÚ_sat_regionr&   r0   )Úselfr    r^   r¢   r¯   r   r   r   r°   r   r±   r!   rZ   rœ   s                 r   Ú__init__zRoiPoolingSession.__init__w  s¡  € àŒ} Ò!Ð!Ð!Ð!Ø”^‰
ˆˆ1ˆa�Ø�AŠvˆvˆvˆvå˜+Ñ&Ô&­Ñ3ˆØð 	EÝð DµV¸KÑ5HÔ5Hð Dð DÝ.4µZÑ.@Ô.@ðDð Dð Dñ Eô Eð Eð %& q¨!Ð!ˆŒ�”˜$œ'Ý.8¸Ñ.EÔ.EÑ+ˆÔ˜4Ô+à˜Œ{ˆÝ˜4Ô+Ñ,Ô,ˆØð 	˜Kð 	Ý% dÑ+Ô+ˆEˆEàˆEØ#0Ð:˜%˜%°dˆŒð $ tÔ'8Ð8Ð8õ % T¤_Ñ5Ô5Ð5Ø>Bð 	ŒàˆÔØÔ"ð 	:ð 	:ˆBØ24¸	²/°/�¨Ñ.Ô.Ð.Å}ÐUZÑG[ÔG[ˆJÝ#-¨jÑ#9Ô#9ˆDÔ˜RÑ Ð ð	:ð 	:r    r¡   rL   rM   r   c           	      ó4  ‡— t          |¦  «        }|dk    r@t          j        dt          | j        | j        | j        ¦  «        ft          j        ¬¦  «        S t          j        |t          j	        ¬¦  «        }t          || j        | j        ||¦  «        \  }}}}	|	|z
  dz   ||z
  dz   z                       t          j	        ¦  «        }
d}| j        �Qt          | j        |||	|¦  «        |
t          j        dd…f         z  j                             t          j        ¦  «        }d| j        v }d| j        v }|s|rt%          | j        ||||	||¦  «        nd\  }}|||dœŠˆfd	„| j        D ¦   «         }| j        D ]i}t          | j        |         |||	|¦  «        |
z                       t          j        ¦  «        }|                     |dd…t          j        f         ¦  «         Œj|s"t          j        |dft          j        ¬¦  «        S t          j        |d¬
¦  «        S )aE  
        Pool this session's tensor over a new set of bboxes. Cheap to call
        repeatedly: 'mean'/'entropy'/'margin' are O(1) per bbox (SAT lookup,
        built once in __init__); 'min'/'max' still cost a grouped batch
        slicing pass over these specific bboxes (unavoidable, see class
        docstring).
        r   r3   r*   Nr   r	   r�   r‘   c                 ó    •— g | ]
}‰|         ‘ŒS r<   r<   r“   s     €r   r[   z+RoiPoolingSession.query.<locals>.<listcomp>´  s   ø€ ÐAÐAÐA¨� Ô$ÐAÐAÐAr    r#   )rd   r   r5   re   rº   r½   r¾   rg   r®   r6   rT   r¼   r»   rF   rÀ   rA   r–   r˜   rŽ   r¿   rÁ   rj   rl   )rÂ   r¡   rL   rM   rn   rK   rP   rQ   rR   rS   r™   rš   r€   r�   r‚   rƒ   rv   rZ   rž   r”   s                      @r   ÚqueryzRoiPoolingSession.query•  s-  ø€ õ �‰KŒKˆØ�Š6ˆ6Ý”8˜Q¥¨D¬G°TÔ5FÈÔHXÑ YÔ YÐZÝ"$¤*ð.ñ .ô .ð .õ ŒZ˜¥b¤jÐ1Ñ1Ô1ˆÝ-¨b°$´'¸4¼7ÀJÐP[Ñ\Ô\ÑˆˆS�#�sØ˜‘)˜a‘- C¨#¡I°¡MÑ2×:Ò:½2¼:ÑFÔFˆàˆØŒ>Ð%Ý% d¤n°c¸3ÀÀSÑIÔIØ¥¤
¨A¨A¨A Ô.ñ/Ü01·&²&½¼Ñ2DÔ2Dð ð ˜DÔ-Ð-ˆØ˜DÔ-Ð-ˆð ð8Ø$ð8�O˜DœO¨S°#°s¸CÀÈ8ÑTÔTÐTØ+7ñ 	ˆ�ð
 $,°GÀGÐLÐLˆØAÐAÐAÐA¨tÔ/@ÐAÑAÔAˆàÔ"ð 	5ð 	5ˆBÝ(¨Ô)9¸"Ô)=¸sÀCÈÈcÑRÔRØ!ñ"ß#)¢6­"¬*Ñ#5Ô#5ð à�LŠL˜ Q Q Q­¬
 ]Ô3Ñ4Ô4Ð4Ð4àð 	6Ý”8˜Q ˜F­"¬*Ð5Ñ5Ô5Ð5ÝŒ~˜e¨!Ð,Ñ,Ô,Ð,r    N©r   F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚndarrayÚtupler­   rÃ   r   r   rD   r}   rÆ   r<   r    r   r¸   r¸   X  s¡   € € € € € ðð ð< CRØ&+ð:ð : ¤ð :¸%ð :Ø#ð:ð :ð :ð :ð<(-˜D  u¨e°U¸EÐ'AÔ!BÔCð (-Øð(-Ø+.ð(-Ø35´:ð(-ð (-ð (-ð (-ð (-ð (-r    r¸   rÇ   ) rË   Únumpyr   Útypingr   r   Úcollectionsr   ÚDEFAULT_FEATURE_MAP_POOLING_OPSÚ DEFAULT_CLASS_LOGITS_POOLING_OPSrW   r]   r©   rª   rÌ   r   r&   r0   r:   rA   rT   ra   re   ry   rŽ   rŸ   rD   r}   rÍ   r­   r¶   r¸   r<   r    r   ú<module>rÓ      sQ  ððð ð@ Ð Ð Ð Ø Ð Ð Ð Ð Ð Ð Ð Ø #Ð #Ð #Ð #Ð #Ð #ð #2Ð Ø#NÐ  à%€Ø#€ØˆS�ÑÔ   [Ñ!1Ô!1Ñ1€
ð˜BœJð ¨2¬:ð ð ð ð ð6˜"œ*ð 6¨¬ð 6ð 6ð 6ð 6ð˜œð ¨¬
ð ð ð ð ð�B”Jð  2¤:ð ð ð ð ðð ð ð
ð 
ð 
ð#ð #ð #ð2ð 2ð 2ð ð  ð  ðN$ð $ð $ðN%)ð %)ð %)ðb )ØðVNð VNØŒjðVNà��u˜e U¨EÐ1Ô2Ô3ðVNð ðVNð ð	VNð
 ðVNð ðVNð „ZðVNð VNð VNð VNðze-ð e-ð e-ð e-ð e-ñ e-ô e-ð e-ð e-ð e-r    