ó
    À‘´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  SSKJr  SSKJr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r\4             SS jjr          SS jr      SS jr        SS jrg)u¯  Check every cell the scan read against the parse's reading of the same cell.

The scan is the reader for a table printed as an image, and it has one failure
mode: it turns thousands separators into decimal points. The parse reads the same
image and is already in the artifacts. It is not a second table and contributes
no structure â€” it is a second opinion on what a cell says, available for free,
and it catches that failure.

Every cell in the scan's grid is checked. A cell leaves here confirmed by a
second reader, read off the page by an agent, or on the scan's word alone when
the agent could not be asked or gave no answer for it:

- The parse read the same text. Two independent readers agree, and the cell
  stands.
- The parse read something different. The agent reads the cell.
- The parse has no cell there. The agent reads the cell. Having no second
  opinion is a reason to look harder, not a reason to wave it through. With no
  parse table at all, every non-empty cell goes to the agent.
- No reader is configured, the reader's call fails, or it returns nothing for
  a cell. The cell keeps the scan's reading, and the gap is logged.

Cells pair by how much one box covers the other, taken against the smaller of
the two. The readers agree on where a cell is and disagree on how much room it
takes: a row heading is bound by the parse to the word itself and by the scan to
the whole row band, one box sitting entirely inside the other. Measured against
their combined area those overlap almost not at all.

Texts are compared as they stand. A currency symbol read as a letter, a comma
read as a period, a parenthesis dropped from a negative â€” each changes what the
document states, and a rule deciding which of those were too cosmetic to ask
about would be deciding the thing the agent is there to decide.

This checks values, not coverage. If the page prints a line the scan drew no box
around, the table is short a row and nothing here notices.
é    )Úannotations)ÚDictÚListÚOptionalÚTuple)ÚCoordOrigin)Ú	TableItem)Úlogger)ÚCellQuestionÚ
CellReader)Úcolumn_letterÚgrid_to_addressed_markdown)Úcoverage_fraction)ÚNormBoxÚnorm_box)ÚScannedTablegš™™™™™¹?c           	   ƒ  óÔ  #   • Uc/  [         R                  " SU R                  5        U R                  S4$ [	        XX%5      u  pgU(       d/  [         R                  " SU R                  5        U R                  S4$ [         R                  " SU R                  [        U5      [        S U R                   5       5      5        UR                  U[        U R                  5      U5      I Sh  v•N nU R                   V	s/ s H  n	[        U	5      PM     n
n	SnU Vs1 s H  oÌR                  iM     nnUR                   H¹  nUR                  U;  a.  [         R                  " SU R                  UR                  5        MA  X~R                     u  pŸX©   U   UR                  :w  a=  [         R                  " SU R                  UR                  X©   U   UR                  5        UR                  X©   U'   US	-  nM»     XØR                   Vs1 s H  nUR                  iM     sn-
  nU(       a+  [         R                  " S
U R                  [        U5      5        X«4$  GNns  sn	f s  snf s  snf 7f)aÁ  The scan's grid with every unconfirmed cell read off the page.

Returns the grid and how many cells the agent read. The grid keeps its shape:
only cell text changes, never the rows, the columns or the boxes.

Without a reader, the grid is returned unchanged and the reason is logged.
A run that cannot check is not the same as a run that checked and found
nothing. Without a parse table to check against, every non-empty cell is
sent to the reader.
Nz@Cell check: page {} no reader configured; the scan's grid standsr   z5Cell check: page {} every cell confirmed by the parsez1Cell check: page {} asking about {} of {} cell(s)c              3  ód   #   • U  H&  o  H  o"R                  5       (       d  M  S v •  M     M(     g7f)é   N)Ústrip)Ú.0ÚrowÚcs      Ú;/home/mande/repo/quber/src/quber/core/figures/crosscheck.pyÚ	<genexpr>Ú#crosscheck_cells.<locals>.<genexpr>W   s    é € ÐAš�#³¨1·w±w·y�A‰A±‰Ašùs   ‚0£0zPCell check: page {} the reader returned {} which it was not asked about; ignoredz#Cell check: page {} {} {!r} -> {!r}r   z[Cell check: page {} the reader returned nothing for {}; those cells keep the scan's reading)r
   ÚinfoÚpageÚcellsÚ
_questionsÚlenÚsumÚ
read_cellsr   ÚlistÚaddressÚwarningÚvalueÚsorted)ÚscannedÚ
table_itemÚ	page_dimsÚtable_imageÚreaderÚmatch_fractionÚ	questionsÚ	addressesÚreadingsr   ÚgridÚreadÚqÚaskedÚcellÚcolr   Úmissings                     r   Úcrosscheck_cellsr9   8   sï  é € ð$ �~Ü�ŠÐVÐX_×XdÑXdÔeØ�}‰}˜aÐÐä% g¸9ÓUÑ€IÞÜ�ŠÐKÈWÏ\É\ÔZØ�}‰}˜aÐÐä
‡K‚KØ;Ø�‰ÜˆI‹ÜÑA˜ŸšÓAÓAô	ð ×&Ñ& {Ô4NÈwÏ}É}Ó4]Ð_hÓi×i€Hà!(§¢Ó/¢˜#ŒD�ŽI¡€DÐ/Ø€DÙ )Ó*¢	˜1�YŒY¡	€EÐ*Ø—”ˆØ�<‰<˜uÓ$Ü�NŠNØbØ—‘Ø—‘ôñ
 ØŸ\™\Ñ*‰ˆØ‰9�S‰>˜TŸZ™ZÓ'Ü�KŠKØ5Ø—‘Ø—‘Ø‘	˜#‘Ø—
‘
ôð Ÿ™ˆ‰	�#‰Ø�‰	Šñ% ð( ¯.ª.Ó9ª. Q�q—y”y©.Ñ9Ñ9€GÞÜ�ŠØiØ�L‰LÜ�7‹Oô	
ð
 ˆ:ÐòA jùâ/ùâ*ùò* :ùs=   ‚C&I(Ã(IÃ)I(Ã;IÄI(ÄIÄ-CI(ÈI#È;I(ÉI(c           
     ó¶  • [        X5      n/ n0 n[        U R                  5       H¯  u  px[        U5       H›  u  pšU
R                  5       (       d  M  [	        U	[        U R                  U   5      :  a  U R                  U   U	   OS5      n[        X´U5      nUb  XÊ:X  a  Mk  [        U	5       US-    3nXy4Xm'   UR                  [        XÚUS95        M�     M±     XV4$ )zMThe cells the parse did not confirm, and where each address sits in the grid.Nr   )r%   Ú	scan_readÚ
parse_read)Ú_parse_cellsÚ	enumerater   r   r   r!   Ú
cell_boxesÚ_best_matchr   Úappendr   )r)   r*   r+   r.   Úparse_cellsr/   r0   r   Útextsr7   ÚtextÚboxÚotherr%   s                 r   r    r    |   sÝ   € ô ˜zÓ5€Kà$&€IØ,.€IÜ §¡Ö.‰
ˆÜ" 5Ö)‰IˆCØ—:‘:—<‘<ÙÜ¸3ÄÀW×EWÑEWÐX[ÑE\ÓA]Ó;]˜7×-Ñ-¨cÑ2°3Ò7ÐcgÓhˆCÜ °.ÓAˆEØÑ  U£]ÙÜ& sÓ+Ð,¨S°1©W¨IÐ6ˆGØ"% ˆIÑØ×Ñœ\°'ÐV[Ñ\Ö]ó *ñ /ð ÐÐó    c           	     óØ  • U c  / $ Uu  p#/ nU R                   R                   GHC  nUR                  nUb(  UR                  =(       d    SR	                  5       (       d  M=  UR
                  [        R                  :X  ac  UR                  U-  [        UR                  UR                  5      U-  UR                  U-  [        UR                  UR                  5      U-  4nOhUR                  U-  U[        UR                  UR                  5      -
  U-  UR                  U-  U[        UR                  UR                  5      -
  U-  4nUR                  UR                  U45        GMF     U$ )zIThe parse's cells for this table, boxed in the normalized top-left frame.Ú )ÚdataÚtable_cellsÚbboxrD   r   Úcoord_originr   ÚTOPLEFTÚlÚminÚtÚbÚrÚmaxrA   )r*   r+   ÚwidthÚheightÚoutr6   rL   rE   s           r   r=   r=   •   s-  € ð ÑØˆ	Ø�M€EØ%'€CØ—‘×+Õ+ˆØ�y‰yˆØ‰< §	¡	§¨R×6Ñ6×8Ñ8ÙØ×Ñ¤× 3Ñ 3Ó3Ø—6‘6˜E‘>¤3 t§v¡v¨t¯v©vÓ#6¸Ñ#?ÀÇÁÈ%ÁÔQTÐUY×U[ÑU[Ð]a×]cÑ]cÓQdÐgmÑQmÐn‰Cð —‘˜‘Øœ#˜dŸf™f d§f¡fÓ-Ñ-°Ñ7Ø—‘˜‘Øœ#˜dŸf™f d§f¡fÓ-Ñ-°Ñ7ð	ˆCð 	�
‰
�D—I‘I˜sÐ#×$ñ ,ð €JrG   c                óz   • U c  gSnUnU H,  u  pV[        [        X5      [        X`5      5      nXt:¼  d  M*  Xup4M.     U$ )zLWhat the parse read in the cell covering `box` best, or none past the floor.N)rT   r   )rE   rB   r.   Ú	best_textÚbestrD   rF   Úcovs           r   r@   r@   ®   sL   € ð �{ØØ#€IØ€DÛ"‰ˆÜÔ# CÓ/Ô1BÀ5Ó1NÓOˆØ�;Ø!’)ñ #ð ÐrG   N)r)   r   r*   úOptional[TableItem]r+   úTuple[float, float]r,   Úbytesr-   zOptional[CellReader]r.   ÚfloatÚreturnzTuple[List[List[str]], int])
r)   r   r*   r\   r+   r]   r.   r_   r`   z5Tuple[List[CellQuestion], Dict[str, Tuple[int, int]]])r*   r\   r+   r]   r`   úList[Tuple[str, NormBox]])rE   zOptional[NormBox]rB   ra   r.   r_   r`   zOptional[str]) Ú__doc__Ú
__future__r   Útypingr   r   r   r   Údocling_core.types.doc.baser   Údocling_core.types.doc.documentr	   Úlogurur
   Úquber.agents.cell_readerr   r   Ú%quber.core.extractors.camelot.acquirer   r   Ú5quber.core.extractors.camelot.correspondence.geometryr   Úquber.core.figures.geometryr   r   Úquber.core.figures.modelsr   ÚMATCH_FRACTIONr9   r    r=   r@   © rG   r   Ú<module>ro      sÿ   ðñ"õH #ç .Ó .å 3Ý 5Ý ç =ß [Ý Sß 9Ý 2ð €ð +ðAØðAà#ðAð #ðAð ð	Að
 !ðAð ðAð !õAðH Øð à#ð ð #ð ð ð	 ð
 ;ô ð2Ø#ðØ0Cðàôð2Ø	ðØ)BðØTYðàõrG   