ó
    À‘´j¸.  ã                  ó@  • S r SSKJr  SSKJrJrJrJr  SSKJ	r	  SSK
JrJr  SSKJr  SSKJrJr  SSKJr  SS	KJrJr  S
r\\\\\4   r\4       SS jjr                  SS jr              SS jr        SS jrSS jrSS jrSS jr g)u×  Match the Set-of-Mark/Camelot tables against docling's tables and pictures.

One page at a time, every SoM table is overlapped against every docling table
and picture on that page. There are only a handful of tables per page, so the
match is all-pairs; no spatial index. Boxes from the three sources are first
normalized to one frame â€” 0..1 with the page top-left as origin â€” so they
compare directly:

- docling table / picture boxes: PDF points, bottom-left origin (flip y).
- SoM `som_region`: already normalized top-left (used as-is).
- Camelot `bbox` (fallback when a SoM table has no region): PDF points,
  bottom-left origin.

An edge is drawn when either box covers the other past `MATCH_FRACTION`, so a
large SoM region containing a small docling table and a small SoM table inside a
large docling table both register. SoM tables and docling tables are then grouped
into regions by connected overlap, and each region's cardinality is read off the
matrix in `models.py`.
é    )Úannotations)ÚDictÚListÚOptionalÚTuple)ÚCoordOrigin)ÚPictureItemÚ	TableItem)ÚExtractedTable)Úcamelot_bbox_to_normÚcoverage_fraction)ÚRegionMatch)ÚParseResultÚTableProvenancegš™™™™™É?c                óì  • U R                   nU R                   Vs0 s H%  oDR                  UR                  UR                  4_M'     nnU R                  5       n[        U Vs1 s H  owR                  iM     snUR                   Vs1 s H.  owR                  (       d  M  UR                  S   R                  iM0     sn-  UR                   Vs1 s H.  oDR                  (       d  M  UR                  S   R                  iM0     sn-  5      n/ n	U HL  n
UR                  U
S5      u  p¼U	R                  [        U
UUUUR                  UR                  UU5      5        MN     U	$ s  snf s  snf s  snf s  snf )a×  Match the SoM tables against the docling document, page by page.

Returns one `RegionMatch` per region: every SoM table with a box lands in
exactly one record (replace / som_merged / docling_undercount / image_table /
chart / docling_miss), and every docling table with a provenance box that no
SoM table matched yields a `som_miss` record. A SoM table with neither
`som_region` nor `bbox`, and a docling table with no provenance, land in no
record and are not reported.
r   )g      ƒ@g     Àˆ@)ÚdocumentÚpagesÚpage_noÚwidthÚheightÚprovenance_by_refÚsortedÚpageÚtablesÚprovÚpicturesÚgetÚextendÚ_match_page)ÚparseÚ
som_tablesÚmatch_fractionr   ÚpÚ	page_dimsÚprov_by_refÚtr   Úmatchesr   r   r   s                Ú8/home/mande/repo/quber/src/quber/core/fusion/matching.pyÚmatch_tablesr)   +   s<  € ð �~‰~€HØ9>¿ºÓEº°A—‘˜QŸW™W a§h¡hÐ/Ò/¹€IÐEØ×)Ñ)Ó+€KäÙ#Ó$š�A�Œ™Ñ$Ø&.§o¢oÓ
@¢o ¿½Óˆ1�6‰6�!‰9×Ô¡oÑ
@ñ	Aà&.×&7Ò&7Ó
BÒ&7 ¿6½6Óˆ1�6‰6�!‰9×ÔÑ&7Ñ
Bñ	Có€Eð "$€GÛˆØ!Ÿ™ d¨NÓ;‰ˆØ�‰ÜØØØØØ—‘Ø×!Ñ!ØØó	ö	
ñ ð €Nùò1 Fùò 	%ùÚ
@ùÚ
Bs#   ›,E"Á"E'ÂE,
ÂE,
ÃE1
Ã&E1
c                óÚ  • [        [        U5      5       Vs/ s H'  nX8   R                  U :X  d  M  U[        X8   X5      4PM)     n	nU	 VV
s/ s H  u  pŠU
c  M
  XŠ4PM     n	nn
U Vs/ s HM  nUR                  (       d  M  UR                  S   R
                  U :X  d  M5  UR                  [        X±U5      4PMO     nnU VV
s/ s H  u  pÚU
c  M
  XÚ4PM     nnn
U Vs/ s HW  nUR                  (       d  M  UR                  S   R
                  U :X  d  M5  UR                  [        XáU5      [        U5      4PMY     nnU VV
Vs/ s H  u  pÚnU
c  M  XÚU4PM     nn
nnU	 VVs0 s H	  u  nnU/ _M     nnnU VVs0 s H	  u  nnU/ _M     nnnU	 VVs0 s H	  u  nnUS_M     nnnU	 Ht  u  nnU Hh  u  nn[        [        UU5      [        UU5      5      nUU:¼  d  M.  UU   R                  U5        UU   R                  U5        [        UU   U5      UU'   Mj     Mv     [        U	 VVs/ s H  u  nnUPM
     snnU VVs/ s H  u  nnUPM
     snnU5      n/ n[        5       n[        5       nU HF  u  nnUR                  U5        UR                  U5        UR                  [        U UUXcU5      5        MH     U	 H»  u  nnUU;   a  M  / n/ nSnU H]  u  nn n![        [        UU 5      [        U U5      5      nUU:¼  d  M/  UR                  U5        UR!                  U!5        [        UU5      nM_     U(       a!  UR                  [#        U SU/UUUSS95        MŸ  UR                  [#        U SU/SS95        M½     U H*  u  nnUU;   a  M  UR                  [#        U S	U/S
S95        M,     U$ s  snf s  sn
nf s  snf s  sn
nf s  snf s  snn
nf s  snnf s  snnf s  snnf s  snnf s  snnf )Nr   ç        Úchartz2SoM table over a docling picture, no docling table)r   ÚkindÚsom_indicesÚdocling_picture_refsÚpicture_classesÚoverlapÚdetailÚdocling_missz6SoM table with no overlapping docling table or picture)r   r-   r.   r2   Úsom_missz+docling table with no overlapping SoM table)r   r-   Údocling_table_refsr2   )ÚrangeÚlenr   Ú_som_boxr   r   Úself_refÚ_docling_boxÚ_picture_classesÚmaxr   ÚappendÚ_connected_regionsÚsetÚupdateÚ_classify_regionr   r   )"r   r   r   r!   Údocling_tablesÚdocling_picturesr%   r"   ÚiÚsomsÚbr&   ÚdtablesÚrefr#   ÚdpicsÚcÚ_Ús_to_dÚd_to_sÚbest_covÚsboxÚdboxÚcovÚ
componentsr'   Úmatched_somsÚmatched_dtablesÚ	som_groupÚdtable_groupÚpic_refsÚpic_classesÚpboxÚclassess"                                     r(   r   r   U   s  € ô ”s˜:“Ô'óâ'ˆAØ‰=×Ñ Ñ%ó 	4ˆŒH�Z‘] EÓ2Ó3Ù'ð 	ð ñ
  $Ô5št‘t�q q‹FˆQ‹F™t€DÑ5ñ  óâˆAØ�6�6ó 	5à—f‘f˜Q‘i×'Ñ'¨4Ñ/ó 	5ˆ�‰”\ !¨FÓ3Ó4Ùð ð ñ
 '.Ô?¢g™F˜C°‹x�‹x¡g€GÑ?ñ "óâ!ˆAØ�6�6ó 	Jà—f‘f˜Q‘i×'Ñ'¨4Ñ/ó 	Jˆ�‰”\ !¨FÓ3Ô5EÀaÓ5HÓIÙ!ð 
ð ñ
 +0ÕAª%™Y˜S Q°1‹[ˆc�a‹[©%€EÒAñ 7;Ô#;²d©d¨a° A r¢E±d€FÑ#;Ù:AÔ#Bº'±°°Q C¨¢G¹'€FÑ#BÙ59Ô!:²T©T¨Q° ! S¢&±T€HÑ!:Û‰ˆˆ4Û ‰IˆC�ÜÔ'¨¨dÓ3Ô5FÀtÈTÓ5RÓSˆCØ�nÕ$Ø�q‘	× Ñ  Ô%Ø�s‘×"Ñ" 1Ô%Ü! (¨1¡+¨sÓ3�˜“ó !ñ ô $±4Ô$8²4©4¨1¨a£Q±4Ò$8ÉWÔ:UÊWÁ6À3È»3ÉWÒ:UÐW]Ó^€Jà!#€GÜ ›U€LÜ #£€OÛ#-Ñˆ	�<Ø×Ñ˜IÔ&Ø×Ñ˜|Ô,Ø�‰Ô'¨¨i¸À{Ð`hÓiÖjñ $.ó ‰ˆˆ4Ø�ÓÙØ ˆØ!#ˆØˆÛ"'ÑˆC��wÜÔ% d¨DÓ1Ô3DÀTÈ4Ó3PÓQˆAØ�NÕ"Ø—‘ Ô$Ø×"Ñ" 7Ô+Ü˜#˜q“k’ñ #(ö Ø�N‰NÜØØ Ø!" Ø)1Ø$/ØØOñö
ð �N‰NÜØØ'Ø!" ØSñ	öñ3 óF ‰ˆˆQØ�/Ó!ÙØ�‰ÜØØØ$' 5ØDñ	ö	
ñ ð €Nùòwùó
 6ùòùó
 @ùòùô
 Bùó $<ùÛ#BùÛ!:ùó %9ùÓ:Usp   —N-±N-Á	N2ÁN2Á'N8Â N8ÂN8Ã	N=ÃN=ÃOÃ6OÄ&OÅ
OÅOÅ"OÅ:OÆOÈ)O!
É O'c           
     ó0  ^• [        U5      n[        U5      n[        U4S jU 5       SS9nUS:X  a¬  US:X  a¦  UR                  US   5      n	XAS      n
U	SL=(       a    U	R                  S;   nU
R                  =(       d    SR                  5       (       + =(       d    U
R                  S:*  nU(       a,  U(       a%  [        U S	UUUS
U	(       a  U	R                  OS S3S9$ Xv:”  a  SnSU SU S3nOXg:”  a  SnSU SU S3nO
SnU SU S3n[        U UUUUUS9$ )z-Read one region's cardinality off the matrix.c              3  óH   >#   • U  H  nTR                  US 5      v •  M     g7f)r+   N)r   )Ú.0rD   rN   s     €r(   Ú	<genexpr>Ú#_classify_region.<locals>.<genexpr>È   s   øé € Ð7ªY¨ˆx�|‰|˜A˜s×#Ð#ªYùs   ƒ"r+   )Údefaulté   r   N)ÚocrÚemptyÚ Úimage_tablez#docling table read by OCR (verdict=zn/az), Camelot empty)r   r-   r.   r5   r1   r2   Ú
som_mergedzdocling found z tables, SoM z: SoM merged stacked tablesÚdocling_undercountz
SoM found z tables, docling z(: docling dropped/merged a complex tableÚreplacez SoM table(s) agree with z docling table(s))r7   r<   r   ÚverdictÚmarkdownÚstripÚcamelot_accuracyr   )r   rU   rV   r%   r!   rN   rJ   ÚdrQ   r   ÚsomÚno_text_layerÚcamelot_emptyr-   r2   s        `         r(   rA   rA   ½   sL  ø€ ô 	ˆI‹€AÜˆLÓ€AÜ
Ô7©YÓ7ÀÑ
E€Cð 	ˆAƒv�!�q“&Ø�‰˜|¨A™Ó/ˆØ 1™Ñ&ˆØ DÐ(×M¨T¯\©\Ð=MÑ-MˆØ Ÿ\™\×/¨R×6Ñ6Ó8Ô8×W¸C×<PÑ<PÐTWÑ<WˆÞž]ÜØØ"Ø%Ø#/ØØ<ÎT¸T¿\º\ÐW\Ð<]Ð]mÐnñð ð 	ƒuØ ˆØ! !  M°!°Ð4OÐP‰Ø	
‹Ø#ˆØ˜a˜SÐ 1°!°Ð4\Ð]‰àˆØ�3Ð/°¨sÐ2CÐDˆäØØØØ'ØØñð ó    c                óL  ^^• 0 mSS jnSS jnS	U4S jjmS
UU4S jjnUR                  5        H#  u  pgU H  nU" U" U5      U" U5      5        M     M%     0 n	U  HO  nUR                  U5      (       d  M  T" U" U5      5      n
U	R                  U
/ / 45      S   R                  U5        MQ     U HA  nU" U5      nUT;  a  M  T" U5      n
U	R                  U
/ / 45      S   R                  U5        MC     U	R	                  5        Vs/ s H  oÌS   (       d  M  UPM     sn$ s  snf )a  Group SoM tables and docling tables into connected overlap regions.

Only SoM tables that overlap at least one docling table (and the docling
tables they reach) form regions here; unmatched SoM tables and unmatched
docling tables are handled by the caller.
c                ó   • SU  3$ )NÚs© )rD   s    r(   Úkey_sÚ!_connected_regions.<locals>.key_sú   s   € Ø�1�#ˆwˆrq   c                ó   • SU  3$ )Nrm   ru   )rH   s    r(   Úkey_dÚ!_connected_regions.<locals>.key_dý   s   € Ø�3�%ˆyÐrq   c                ór   >• TR                  X 5        TU    U :w  a  TTU       TU '   TU    n TU    U :w  a  M  U $ ©N©Ú
setdefault)ÚxÚparents    €r(   ÚfindÚ _connected_regions.<locals>.find   sK   ø€ Ø×Ñ˜!ÔØ�Q‰i˜1‹nØ˜v a™yÑ)ˆF�1‰IØ�q‘	ˆAð �Q‰i˜1�nð ˆrq   c                ól   >• TR                  X 5        TR                  X5        T" U5      TT" U 5      '   g r|   r}   )ÚarF   r�   r€   s     €€r(   ÚunionÚ!_connected_regions.<locals>.union  s0   ø€ Ø×Ñ˜!ÔØ×Ñ˜!ÔÙ˜q›'ˆ‰t�A‹wŠrq   r   ra   )rD   ÚintÚreturnÚstr)rH   r‰   rˆ   r‰   )r   r‰   rˆ   r‰   )r„   r‰   rF   r‰   rˆ   ÚNone)Úitemsr   r~   r=   Úvalues)Úsom_idsÚdtable_refsrL   rv   ry   r…   rD   ÚrefsrH   ÚgroupsÚrootÚnodeÚgr�   r€   s                @@r(   r>   r>   ï   s  ù€ ð  €Fôô÷÷"ð "ð
 —<‘<–>‰ˆÛˆCÙ‘%˜“(™E #›JÖ'ó ñ "ð 68€FÛˆØ�z‰z˜!�}‰}ÙÙ‘E˜!“H‹~ˆØ×Ñ˜$  R Ó)¨!Ñ,×3Ñ3°AÖ6ñ	 ó
 ˆÙ�S‹zˆØ�vÓÙÙ�D‹zˆØ×Ñ˜$  R Ó)¨!Ñ,×3Ñ3°CÖ8ñ ð —}‘}”Ó/’�!¨A­$�A‘Ñ/Ð/ùÒ/s   ÄD!ÄD!c                ó|   • U R                   b  U R                   $ U R                  b  [        U R                  X5      $ g)z´A SoM table's box in the normalized top-left frame.

Prefers the SoM region (already normalized); falls back to Camelot's bbox
(PDF points, bottom-left) when the region is absent.
N)Ú
som_regionÚbboxr   )Útabler   r   s      r(   r8   r8      s:   € ð ×ÑÑ#Ø×ÑÐØ‡z�zÑÜ# E§J¡J°Ó>Ð>Ørq   c                óx  • U R                   (       d  gU R                   S   R                  nUR                  [        R                  :X  a:  UR
                  U-  UR                  U-  UR                  U-  UR                  U-  4$ [        UR
                  UR                  UR                  UR                  4X5      $ )zBA docling item's provenance bbox in the normalized top-left frame.Nr   )
r   r–   Úcoord_originr   ÚTOPLEFTÚlr&   ÚrrF   r   )Úitemr   r   r–   s       r(   r:   r:   -  sˆ   € à�9�9ØØ�9‰9�Q‰<×Ñ€DØ×ÑœK×/Ñ/Ó/Ø—‘˜‘ §¡¨¡°·±¸%±ÀÇÁÈ&ÁÐQÐQÜ §¡¨¯©°·±¸¿¹Ð @À%ÓPÐPrq   c                ó*  • [        U SS5      nUb  [        USS5      OSnUb  [        USS5      OSnU(       a  US   R                  /$ / n[        U S/ 5       H7  n[        USS5      nU(       d  M  UR                  US   R                  5        M9     U$ )a$  docling's top predicted class for a picture (empty if unclassified).

Predictions are ordered by descending confidence, so the first entry is
docling's call (e.g. `bar_chart`). Reads the current `meta.classification`
field, falling back to the deprecated `annotations` list for older output.
ÚmetaNÚclassificationÚpredictionsr   r   Úpredicted_classes)ÚgetattrÚ
class_namer=   )ÚpicturerŸ   r    r¡   rZ   ÚannÚ	predicteds          r(   r;   r;   7  sž   € ô �7˜F DÓ)€DØ>BÑ>N”W˜TÐ#3°TÔ:ÐTX€NØBPÑB\”'˜.¨-¸Ô>Ðbf€KÞØ˜A‘×)Ñ)Ð*Ð*à€GÜ�w ¨rÖ2ˆÜ˜CÐ!4°dÓ;ˆ	ßˆ9Ø�N‰N˜9 Q™<×2Ñ2Ö3ñ 3ð €Nrq   N)r    r   r!   úList[ExtractedTable]r"   Úfloatrˆ   úList[RegionMatch])r   r‡   r   r©   r   r©   r!   r¨   rB   zList[TableItem]rC   zList[PictureItem]r%   úDict[str, TableProvenance]r"   r©   rˆ   rª   )r   r‡   rU   ú	List[int]rV   ú	List[str]r%   r«   r!   r¨   rN   zDict[int, float]rˆ   r   )r�   r¬   rŽ   r­   rL   zDict[int, List[str]]rˆ   z!List[Tuple[List[int], List[str]]])r—   r   r   r©   r   r©   rˆ   úOptional[NormBox])r�   zTableItem | PictureItemr   r©   r   r©   rˆ   r®   )r¥   r	   rˆ   r­   )!Ú__doc__Ú
__future__r   Útypingr   r   r   r   Údocling_core.types.doc.baser   Údocling_core.types.doc.documentr	   r
   Úquber.core.extractors.baser   Ú5quber.core.extractors.camelot.correspondence.geometryr   r   Úquber.core.fusion.modelsr   Úquber.core.parsers.resultr   r   ÚMATCH_FRACTIONr©   ÚNormBoxr)   r   rA   r>   r8   r:   r;   ru   rq   r(   Ú<module>rº      sX  ðñõ( #ç .Ó .å 3ß Bå 5÷õ 1ß Bð €à
��u˜e UÐ*Ñ
+€ð +ð'Øð'à$ð'ð ð'ð õ	'ðTeØ
ðeàðeð ðeð %ð	eð
 $ðeð (ðeð ,ðeð ðeð ôeðP/Ø
ð/àð/ð ð/ð ,ð	/ð
 %ð/ð ð/ð ô/ðd.0Øð.0Ø%.ð.0Ø8Lð.0à&ô.0ôb
ôQõrq   