Ë
    ?aºj±O  ã                  ój  — d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddlZ ej                  d«       ddlmZ ddlZddlmZ ddlZddlmZmZ ddlmc mZ dd	lmZ dd
lmZ ddlm Z m!Z! ddl"m#Z# ddl$m%Z%  ee&«      jO                  «       jP                  d   Z)e)dz  a*dde)dfdde)dfdde)dz  dffZ+e	 G d„ d«      «       Z,d+d„Z-d,d„Z. G d„ dej^                  «      Z0 G d„ d ej^                  «      Z1d-d!„Z2d.d"„Z3d/d#„Z4d0d1d$„Z5d0d2d%„Z6d3d&„Z7d4d'„Z8d5d(„Z9d5d)„Z:e;d*k(  r e8«        yy)6zãCompare graph sizes and joint/individual weak-label GNN fits on AC28 and ME1a.

Every score is a diagnostic on provisional CSV-seeded masks. In particular,
holding out a run does not validate its registration or defect extent.
é    )ÚannotationsN)Ú	dataclass)ÚPathÚAgg)ÚcKDTree)ÚTensorÚnn)ÚMeshGraphProcessor)Úmetrics)Úfixed_physical_normalizeÚsplit_embedded_units)Úseed_everything)Úgeodesic_distanceé   z$results/ME1a_DT_comparison/gnn_jointÚAC28_16hÚAC28Ú16hÚ
AC28_18h01Ú18h01Ú
ME1a_14h06ÚME1a_DTzexperiments/ME1a_DTÚ14h06c                  ó†   — e Zd ZU ded<   ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   d
ed<   d
ed<   ded<   ded<   y)ÚSampleÚstrÚnameÚpartr   ÚnodeÚedgeÚattrÚprocessÚtargetz
np.ndarrayÚbinaryÚfine_binaryÚfine_from_coarseÚfloatÚtransfer_iouÚintÚactual_nodesN)Ú__name__Ú
__module__Ú__qualname__Ú__annotations__© ó    õL   /Users/bsk/Downloads/á„†á…©á†¯á„�á…¦á†¨á„‰á…³/models/gnn_joint_experiment.pyr   r   &   sC   … à
ƒIØ
ƒIØ
ƒLØ
ƒLØ
ƒLØƒOØƒNØÓØÓØ Ó ØÓØÔr/   r   c           
     óB  — t        j                  | dz  d¬«      5 }t        |d   j                  t        «      «      j                  |«      }t        |d   j                  t        «      «      \  }}t         j                  ||d   j                  t        «      f   }t         j                  |t        j                  dt        |d   «      «      f   }t        j                  |d   ||d	z    t         j                  «      }t        j                  |d
   ||d	z    t        «      }d d d «       t        t        j                  d«      «      }t        j                   t        j"                  ||j                  t         j                  «      gd	«      d   «      S # 1 sw Y   ŒvxY w)Nz/data_processed/tabular/process_and_geometry.npzF©Úallow_pickleÚrun_idÚprocess_feature_namesÚgeometry_feature_namesÚ Úxr   Úfeature_validr   )ÚnpÚloadÚlistÚastyper   Úindexr   Úr_ÚrepeatÚlenÚasarrayÚfloat32Úboolr   ÚwhereÚtorchÚtensorÚconcatenate)	ÚrootÚrunÚdÚidxÚnamesÚunitsÚrawÚvalidÚscaleds	            r0   Ú_processrR   6   sK  € Ü	�‰�ÐIÑIÐX]Õ	^ÐbcÜ�1�X‘;×%Ñ%¤cÓ*Ó+×1Ñ1°#Ó6ˆÜ+¨AÐ.EÑ,F×,MÑ,MÌcÓ,RÓS‰ˆˆuÜ—‘�e˜QÐ7Ñ8×?Ñ?ÄÓDÐDÑEˆÜ—‘�eœRŸY™Y r¬3¨qÐ1IÑ/JÓ+KÓLÐLÑMˆÜ�j‰j˜˜3™  C¨¡EÐ*¬B¯J©JÓ7ˆÜ—
‘
˜1˜_Ñ-¨c°#°a±%Ð8¼$Ó?ˆ÷ 
_ô &¤b§h¡h¨u°c¸1Ó&=¸uÀeÓL€FÜ�<‰<œŸ™¨°·±¼R¿Z¹ZÓ0HÐ'IÈ1ÓMÈaÑPÓQÐQ÷ 
_Ð	^ús   ›DFÆFc                ó  — g }t         D �]Ø  \  }}}}t        j                  |d|› d�z  d¬«      5 }t        j                  |d   t        j                  «      }t        j                  |d   d d …df   t
        «      }t        j                  |d   t        j                  «      j                  d	d
«      }	d d d «       t        j                  |d| › d�z  d¬«      5 }t        j                  |d   t        j                  «      }
t        j                  |d   t        j                  «      }t        j                  |d   t
        «      }|d   j                  t        «      }t        j                  |d   t        j                  «      }t        j                  |d   t        j                  «      j                  «       }d d d «       d d …df   j                  «       }|d d …dfxx   dz  cc<   t        t        j                  d«      «      }t        j                  ||j                  t        j                  «      gd«      }t        
«      }t        j                  |j!                  	d	¬«      d   «      }t        j"                  t        j$                  |D �cg c]"  }t'        t)        |
«      |t+        |«      «      ‘Œ$ c}«      d¬«      }t        j,                  d|dz  dz  z  «      j                  t        j                  «      }|dk  }|j!                  d	¬«      d   }||   }t/        |z  j1                  «       t3        d||z  j1                  «       «      z  «      }|j5                  t7        ||t9        j:                  |«      t9        j:                  «      t9        j:                  |«      t=        ||«      t9        j:                  |«      ||||t)        |
«      «      «       �ŒÛ |S # 1 sw Y   �Œ6xY w# 1 sw Y   �Œ=xY wc c}w )Nzdata_processed/paired/z_cad_ply_targets.npzFr2   Ú
cad_pos_mmÚweak_defect_maskr   Údefect_anchor_cad_mméÿÿÿÿé   zdata_processed/graphs/graph_z.npzÚpos_mmr8   r9   Úfeature_namesÚ
edge_indexÚ	edge_attrr   ç     @�@)Úworkers)Úaxisg      à¿g      $@é   )ÚRUNSr:   r;   rB   rC   rD   Úreshaper=   r   Úint64Úcopyr   rE   rH   r   ÚuniqueÚqueryÚminÚstackr   rA   r(   Úexpr&   ÚsumÚmaxÚappendr   rF   rG   rR   )ÚbudgetÚoutr   r   rI   rJ   rK   Úfine_posr$   ÚanchorsÚposrO   rP   rZ   r   r    Ú
lengths_mmr   ÚtreeÚseedsÚiÚdistancer"   r#   r%   Útransferredr'   s                              r0   Úload_samplesrx   B   sB  € Ø
€Cß!% Ñˆˆd�D˜#Ü�W‰W�TÐ4°S°EÐ9MÐNÑNÐ]bÕcÐghÜ—z‘z ! L¡/´2·:±:Ó>ˆHÜŸ*™* QÐ'9Ñ%:º1¸a¸4Ñ%@Ä$ÓGˆKÜ—j‘j Ð#9Ñ!:¼B¿J¹JÓG×OÑOÐPRÐTUÓVˆG÷ dô �W‰W�TÐ:¸6¸(À$ÐGÑGÐV[Õ\Ð`aÜ—*‘*˜Q˜x™[¬"¯*©*Ó5ˆCÜ—*‘*˜Q˜s™V¤R§Z¡ZÓ0ˆCÜ—J‘J˜q Ñ1´4Ó8ˆEØ˜oÑ.×5Ñ5´cÓ:ˆMÜ—:‘:˜a ™o¬r¯x©xÓ8ˆDÜ—:‘:˜a ™n¬b¯j©jÓ9×>Ñ>Ó@ˆD÷ ]ð š!˜Q˜$‘Z—_‘_Ó&ˆ
ØŠQ�ˆT‹
�fÑ‹
Ü'¬¯©°¸¸QÓ(?ÀÓOˆÜ�~‰~˜t U§\¡\´"·*±*Ó%=Ð>ÀÓBˆÜ�s‹|ˆÜ—	‘	˜$Ÿ*™* W°b˜*Ó9¸!Ñ<Ó=ˆÜ—6‘6œ"Ÿ(™(Ù-2ó$4Ù-2¨ô %6´c¸#³hÀÀjÔRUÐVWÓRXÕ$YØ-2ñ$4ó 5Ø;<ô>ˆä—‘˜˜x¨$™°1Ñ4Ñ4Ó5×<Ñ<¼R¿Z¹ZÓHˆØ˜TÑ!ˆØŸ:™: h¸˜:Ó;¸AÑ>ÐØÐ-Ñ.ˆÜ˜k¨KÑ7×<Ñ<Ó>ÄÀQÈÐWbÑIb×HgÑHgÓHiÓAjÑjÓkˆØ�
‰
”6˜$ ¤e§l¡l°4Ó&8¼%¿,¹,ÀtÓ:LÌeÏlÉlÐ[_ÓN`Ü" 4¨Ó-¬u¯|©|¸FÓ/CÀVÈ[Ø*¨L¼#¸c»(óDö 	Eð3 "&ð8 €J÷7 dÑcú÷ ]Ñ\üò$4s   °BO'ÃC O4Ê'PÏ'O1	Ï4O>	c                  ó:   ‡ — e Zd ZdZddˆ fd„Z	 	 	 	 	 	 dd„Zˆ xZS )ÚResidualGeoGNNzIShort residual edge messages plus multiscale positions for small regions.c                óè  •— t         ‰| �  «        t        j                  t        j                  |d«      t        j
                  «       t        j                  dd«      «      | _        t        j                  t        j                  |dz   dz   |«      t        j
                  «       t        j                  |«      «      | _        t        j                  t        |«      D �cg c]V  }t        j                  t        j                  ||z   |«      t        j
                  «       t        j                  ||«      «      ‘ŒX c}«      | _        t        j                  t        |«      D �cg c]V  }t        j                  t        j                  |dz  |«      t        j
                  «       t        j                  ||«      «      ‘ŒX c}«      | _        t        j                  t        |«      D �cg c]  }t        j                  |«      ‘Œ c}«      | _        t        j                  t        j                  |dz  |«      t        j
                  «       t        j                  |d«      «      | _        y c c}w c c}w c c}w )Né   r`   r   )ÚsuperÚ__init__r	   Ú
SequentialÚLinearÚGELUr!   Ú	LayerNormr   Ú
ModuleListÚrangeÚmsgÚupdateÚnormÚhead)ÚselfÚnode_dimÚedge_dimÚprocess_dimÚwidthÚstepsÚ_Ú	__class__s          €r0   r~   zResidualGeoGNN.__init__e   sÀ  ø€ Ü‰ÑÔÜ—}‘}¤R§Y¡Y¨{¸BÓ%?ÄÇÁÃÌBÏIÉIÐVXÐZ\ÓL]Ó^ˆŒÜ—M‘M¤"§)¡)¨H°r©M¸BÑ,>ÀÓ"FÌÏÉË	ÔSU×S_ÑS_Ð`eÓSfÓgˆŒ	Ü—=‘=ÜRWÐX]ÔR^ó"`ÙR^ÈQô #%§-¡-´·	±	¸%À(Ñ:JÈEÓ0RÔTV×T[ÑT[ÓT]Ü02·	±	¸%ÀÓ0Gõ#IØR^ñ"`ó aˆŒä—m‘mÜUZÐ[`ÔUaó%cÙUaÐPQô &(§]¡]´2·9±9¸UÀQ¹YÈÓ3NÔPR×PWÑPWÓPYÜ35·9±9¸UÀEÓ3Jõ&LØUañ%có dˆŒä—M‘MÄÀeÄÓ"MÁ¸1¤2§<¡<°Õ#6ÀÑ"MÓNˆŒ	Ü—M‘M¤"§)¡)¨E°A©I°uÓ"=¼r¿w¹w»yÌ"Ï)É)ÐTYÐ[\ÓJ]Ó^ˆ�	ùò"`ùò%cùâ"Ms   ÃAI%Å AI*Ç#I/c           
     ó@  — |d d …d d…f   }|d d …d d …d f   |j                  t        j                  dt        j                  z  dt        j                  z  dt        j                  z  g«      z  }t        j                  |j                  «       |j                  «       gd¬«      j                  d«      }| j                  |«      |   }	| j                  t        j                  |||	gd«      «      }
|
}|\  }}t        j                  |t        |
«      ¬«      j                  d«      j                  |
j                  «      d d …d f   }t        | j                   | j"                  | j$                  «      D ]w  \  }}} |t        j                  |
|   |gd«      «      }t        j&                  |
«      j)                  d||«      |z  } ||
 |t        j                  |
|gd«      «      z   «      }
Œy | j+                  t        j                  |
|gd«      «      j-                  d«      S )	NrX   r`   é   é   ©Údimr   )Ú	minlengthr   )Ú
new_tensorr:   ÚpirF   ÚcatÚsinÚcosÚflattenr!   r   ÚbincountrA   Ú	clamp_minÚtoÚdtypeÚzipr…   r†   r‡   Ú
zeros_likeÚ
index_add_rˆ   Úsqueeze)r‰   Únode_xr[   r\   Úglobal_xÚbatchrq   ÚanglesÚfourierr!   ÚhÚinitialÚsrcÚdstÚdegreeÚmessager†   r‡   ÚmÚaggs                       r0   ÚforwardzResidualGeoGNN.forwardp   s¸  € à’Q˜˜˜�U‰mˆØ’Qš˜4�Z‘ 3§>¡>´2·5±5¸!¼b¿e¹e¹)ÀQÌÏÉÁYÐPQÔTV×TYÑTYÑPYÐ2ZÓ#[Ñ[ˆÜ—)‘)˜VŸZ™Z›\¨6¯:©:«<Ð8¸aÔ@×HÑHÈÓKˆØ—,‘,˜xÓ(¨Ñ/ˆØ�I‰I”e—i‘i ¨°'Ð :¸AÓ>Ó?ˆØˆØ‰ˆˆSÜ—‘ ¬s°1«vÔ6×@Ñ@ÀÓC×FÑFÀqÇwÁwÓOÒPQÐSWÐPWÑXˆÜ%(¨¯©°4·;±;ÀÇ	Á	Ö%JÑ!ˆG�V˜TÙœŸ	™	 1 S¡6¨9Ð"5°qÓ9Ó:ˆAÜ×"Ñ" 1Ó%×0Ñ0°°C¸Ó;¸fÑDˆCÙ�Q™¤§	¡	¨1¨c¨(°AÓ 6Ó7Ñ7Ó8‰Að &Kð �y‰yœŸ™ A w <°Ó3Ó4×<Ñ<¸QÓ?Ð?r/   )é0   r`   )
rŠ   r(   r‹   r(   rŒ   r(   r�   r(   rŽ   r(   ©r¥   r   r[   r   r\   r   r¦   r   r§   r   Úreturnr   ©r*   r+   r,   Ú__doc__r~   r²   Ú__classcell__©r�   s   @r0   rz   rz   c   s-   ø„ ÙSö	_ð@Ø ð@Ø)/ð@Ø4:÷@r/   rz   c                  ó:   ‡ — e Zd ZdZddˆ fd„Z	 	 	 	 	 	 dd„Zˆ xZS )ÚGeoMLPzFControl with the same positional and process information, no messages.c           
     óÖ  •— t         ‰| �  «        t        j                  t        j                  |d«      t        j
                  «       t        j                  dd«      «      | _        t        j                  t        j                  |dz   dz   |«      t        j
                  «       t        j                  ||«      t        j
                  «       t        j                  |d«      «      | _        y )Nr|   r   )r}   r~   r	   r   r€   r�   r!   rˆ   )r‰   rŠ   r‹   rŒ   r�   r�   s        €r0   r~   zGeoMLP.__init__ƒ   s”   ø€ Ü‰ÑÔÜ—}‘}¤R§Y¡Y¨{¸BÓ%?ÄÇÁÃÌBÏIÉIÐVXÐZ\ÓL]Ó^ˆŒÜ—M‘M¤"§)¡)¨H°r©M¸BÑ,>ÀÓ"FÌÏÉË	Ü"$§)¡)¨E°5Ó"9¼2¿7¹7»9ÄbÇiÁiÐPUÐWXÓFYó[ˆ�	r/   c           	     óø  — |d d …d d…f   }|d d …d d …d f   |j                  t        j                  dt        j                  z  dt        j                  z  dt        j                  z  g«      z  }t        j                  |j                  «       |j                  «       gd¬«      j                  d«      }| j                  t        j                  ||| j                  |«      |   gd«      «      j                  d«      S )NrX   r`   r’   r“   r”   r   )r—   r:   r˜   rF   r™   rš   r›   rœ   rˆ   r!   r¤   )	r‰   r¥   r[   r\   r¦   r§   rq   r¨   r©   s	            r0   r²   zGeoMLP.forward‰   sÂ   € à’Q˜˜˜�U‰mˆØ’Qš˜4�Z‘ 3§>¡>´2·5±5¸!¼b¿e¹e¹)ÀQÌÏÉÁYÐPQÔTV×TYÑTYÑPYÐ2ZÓ#[Ñ[ˆÜ—)‘)˜VŸZ™Z›\¨6¯:©:«<Ð8¸aÔ@×HÑHÈÓKˆØ�y‰yœŸ™ F¨G°T·\±\À(Ó5KÈEÑ5RÐ#SÐUVÓWÓX×`Ñ`ÐabÓcÐcr/   )r³   )rŠ   r(   r‹   r(   rŒ   r(   r�   r(   r´   r¶   r¹   s   @r0   r»   r»   �   s-   ø„ ÙPö[ðdØ ðdØ)/ðdØ4:÷dr/   r»   c                ó  — |j                   j                  d   |j                  j                  d   |j                  j                  d   f}| dk(  rt	        |dddœŽS | dk(  rt        |Ž S | dk(  rt        |Ž S t        | «      ‚)	Nr   r   Úmeshr³   rX   )r�   rŽ   Úresidual_geoÚgeo_mlp)r   Úshaper    r!   r
   rz   r»   Ú
ValueError)ÚkindÚsampleÚdimss      r0   Ú
make_modelrÇ   ‘   s   € Ø�K‰K×Ñ˜aÑ  &§+¡+×"3Ñ"3°AÑ"6¸¿¹×8LÑ8LÈQÑ8OÐP€DØˆv‚~Ô0°$¸bÈÒJÐJØˆ~Ò¤n°dÐ&;Ð;ØˆyÒ¤¨ Ð.Ü
�TÓ
Ðr/   c           	     óà  — d}g g g }}}t        | «      D ]š  \  }}|j                  |j                  |z   «       |j                  t        j                  |j
                  f|t        j                  ¬«      «       |j                  t        |||j
                  z   «      «       ||j
                  z  }Œœ t        j                  | D �cg c]  }|j                  ‘Œ c}«      t        j                  |d«      t        j                  | D �cg c]  }|j                  ‘Œ c}«      t        j                  | D �cg c]  }|j                  ‘Œ c}«      t        j                  |«      |fS c c}w c c}w c c}w )Nr   ©r    r   )Ú	enumeraterl   r   rF   Úfullr)   ÚlongÚslicer™   r   r    rh   r!   )ÚsamplesÚoffsetÚedgesÚbatchesÚslicesru   rÅ   Úss           r0   ÚcombinerÔ   ™   s  € Ø€FØ  R�Fˆ7€EÜ˜wÖ'‰	ˆˆ6Ø�‰�V—[‘[ 6Ñ)Ô*Ø�‰”u—z‘z 6×#6Ñ#6Ð"8¸!Ä5Ç:Á:ÔNÔOØ�‰”e˜F F¨V×-@Ñ-@Ñ$@ÓAÔBØ�&×%Ñ%Ñ%‰ð	 (ô
 �I‰I¡wÓ/¡w !�q—v“v wÑ/Ó0´%·)±)¸EÀ1Ó2EÜ�I‰I¡wÓ/¡w !�q—v“v wÑ/Ó0´%·+±+ÑRYÓ>ZÑRYÈQ¸q¿y»yÐRYÑ>ZÓ2[Ü�I‰I�gÓ ð(ð (ùÒ/ùÚ/ùÒ>Zs   ÃE!ÄE&Ä1E+c                óF   —  | |d d Ž }|j                   dk(  r	|d d …df   S |S )Né   r`   r   )Úndim)Úmodelr§   Úoutputs      r0   r²   r²   ¦   s0   € Ù�E˜"˜1�IÐ€FØ!Ÿ;™;¨!Ò+ˆ6’!�Q�$‰<Ð7°Ð7r/   c                ó²  — g }t        ||«      D �]#  \  }}|dk(  r|j                  n*t        j                  |j                  | j
                  ¬«      }t        dt        |j                  j                  «       «      «      }t        |dk(  rdndt        |«      |z
  |z  «      }	t        j                  | |   ||j                  |	«      ¬«      }
| |   j                  «       }dd||z  j                  «       z  dz   |j                  «       |j                  «       z   dz   z  z
  }|j                  |
|z   «       �Œ& t        j                   |«      j#                  «       S )NÚsoftrÉ   r   g      i@r]   )Ú
pos_weightr`   )r¡   r"   rF   Ú	as_tensorr#   r    rk   r(   rj   rg   rA   ÚFÚ binary_cross_entropy_with_logitsr—   Úsigmoidrl   rh   Úmean)ÚlogitrÎ   rÒ   ÚmodeÚlossesrÅ   Úslr"   ÚpositiveÚweightÚbceÚprobÚdices                r0   Ú	risk_lossrë   «   s!  € Ø€FÜ˜' 6×*‰
ˆ�Ø"&¨&¢.�—’´e·o±oÀfÇmÁmÐ[`×[fÑ[fÔ6gˆÜ�qœ#˜fŸm™m×/Ñ/Ó1Ó2Ó3ˆÜ˜d fšn‘U°&¼3¸v»;ÈÑ;QÐU]Ñ:]Ó^ˆÜ×0Ñ0°°r±¸FÈv×O`ÑO`ÐagÓOhÔiˆØ�R‰y× Ñ Ó"ˆØ�A˜ ™×+Ñ+Ó-Ñ-°Ñ1°d·h±h³jÀ6Ç:Á:Ã<Ñ6OÐRSÑ6SÑTÑTˆØ�‰�c˜D‘jÖ!ð +ô �;‰;�vÓ×#Ñ#Ó%Ð%r/   c                óF  — t        j                  |«       t        | |d   «      }t         j                  j	                  |j                  «       dd¬«      }t        |«      }t        d«      }d}	d }
t        j                  «       }t        |«      D ]Ô  }|j                  «        |j                  d¬«       t        ||«      }t        |||d   |«      }|j                  «        |j!                  «        t        |j#                  «       «      }||k  sŒ�||d	z   }	}|j%                  «       j'                  «       D ��ci c]$  \  }}||j#                  «       j)                  «       “Œ& }
}}ŒÖ |j+                  |
«       |||	t-        t        j                  «       |z
  d
«      dœfS c c}}w )Nr   gú~j¼t“h?gñhãˆµøä>)ÚlrÚweight_decayÚinfT)Úset_to_nonerÖ   r   r`   )Ú	best_lossÚ
best_epochÚseconds)rF   Úmanual_seedrÇ   ÚoptimÚAdamWÚ
parametersrÔ   r&   ÚtimeÚ	monotonicr„   ÚtrainÚ	zero_gradr²   rë   ÚbackwardÚstepÚdetachÚ
state_dictÚitemsÚcloneÚload_state_dictÚround)rÄ   rÎ   ÚepochsÚseedÚ	loss_moderØ   Ú	optimizerr§   rñ   rò   ÚbestÚstartÚepochÚ
predictionÚlossÚvalueÚkÚvs                     r0   rú   rú   ¸   sr  € Ü	×Ñ�dÔÜ�t˜W Q™ZÓ(€EÜ—‘×!Ñ! %×"2Ñ"2Ó"4¸ÈDÐ!ÓQ€IÜ�GÓ€EÜ�e“€IØ€JØ€DÜ�N‰NÓ€EÜ�v–ˆØ�‰ŒØ×Ñ¨ÐÔ-Ü˜U EÓ*ˆ
Ü˜ W¨e°A©h¸	ÓBˆØ�‰ŒØ�‰ÔÜ�d—k‘k“mÓ$ˆØ�9ÓØ$)¨5°1©9�zˆIØ6;×6FÑ6FÓ6H×6NÑ6NÔ6PÔQÑ6P©d¨a°�A�q—x‘x“z×'Ñ'Ó)Ñ)Ð6PˆDÒQð ð 
×Ñ˜$ÔØ 	¸Ü#¤D§N¡NÓ$4°uÑ$<¸aÓ@ñBð Bð Bùó Rs   Ä7)Fc           
     óè  — | j                  «        t        j                  «       5  t        | t	        |g«      «      j                  «       j                  «       j                  «       }d d d «       t        |j                  «      }t        ||j                     |j                  «      }|d   |d   |d   |d   |d   |d   t        |j                  j                  «       «      |d   dœS # 1 sw Y   ŒƒxY w)NÚaverage_precisionÚthreshold_iouÚthreshold_diceÚtop_k_recallÚpredicted_positive_nodes)Ú	native_apÚ
native_iouÚ	mapped_apÚ
mapped_iouÚmapped_diceÚmapped_top_k_recallÚfine_prevalenceÚpredicted_positive_fine)ÚevalrF   Úno_gradr²   rÔ   rà   ÚcpuÚnumpyr   r#   r%   r$   r&   rá   )rØ   rÅ   ÚprobabilityÚnativeÚmappeds        r0   Úevaluater%  Ñ   sÙ   € Ø	‡J�J„LÜ	�‰�Ü˜e¤W¨f¨XÓ%6Ó7×?Ñ?ÓA×EÑEÓG×MÑMÓOˆ÷ 
ä�[ &§-¡-Ó0€FÜ�[ ×!8Ñ!8Ñ9¸6×;MÑ;MÓN€FØÐ 3Ñ4ÀFÈ?ÑD[ØÐ 3Ñ4ÀFÈ?ÑD[Ø!Ð"2Ñ3ÈFÐSaÑLbÜ$ V×%7Ñ%7×%<Ñ%<Ó%>Ó?Ø'-Ð.HÑ'Iñ	Kð K÷	 
ˆús   ¥AC(Ã(C1c                 ó¾	  — t        j                  t        ¬«      } | j                  dd¬«       | j                  dd¬«       | j                  dt        d¬	«       | j                  d
dd¬«       | j                  dt
        t        ¬	«       | j                  «       }|j                  j                  «       a|j                  j                  d«      D �cg c]  }t	        |«      ‘Œ }}|j                  j                  d«      }t        j                  dd¬«       t        j                  d«       t!        «        g }|D �]�  }t#        |«      }|D �ci c]  }|j$                  |“Œ }	}d|D �cg c]  }|j$                  ‘Œ c}|D �cg c]  }|j$                  ‘Œ c}fg}
|
|D ��cg c]Q  }d|j$                  › �|D �cg c](  }|j$                  |j$                  k7  sŒ|j$                  ‘Œ* c}|j$                  gf‘ŒS c}}z  }
|
|D �cg c]*  }d|j$                  › �|j$                  g|j$                  gf‘Œ, c}z  }
|
ddgdgfddgdgfgz  }
|D �]�  }|
D �]„  \  }}}t'        ||D �cg c]  }|	|   ‘Œ	 c}|j(                  d|j*                  ¬«      \  }}t        |› d|› d|› d�z  }t        j,                  |j/                  «       ||||j*                  dddœ|«       |D ]ø  }|	|   }|||j*                  |d j1                  |«      |||v |j2                  t	        |j4                  j7                  «       «      t	        |j8                  j7                  «       «      |j:                  d!œ|¥t=        ||«      ¥d"t?        |jA                  tB        «      «      i¥}|jE                  |«       tG        ||||d#tI        |d$   d«      d%tI        |d&   d«      d'|d(   d¬)«       Œú �Œ‡ �Œ� �Œ  d*dd+d,d-|j(                  |j*                  |d.œ}t        d/z  jK                  tM        jN                  |d0¬1«      d2¬3«       t        d4z  jQ                  d5d6¬7«      5 }tS        jT                  |tW        |d8   «      ¬9«      }|jY                  «        |j[                  |«       d d d «       t]        |||«       t_        |||«       y c c}w c c}w c c}w c c}w c c}w c c}}w c c}w c c}w # 1 sw Y   ŒMxY w):N)Údescriptionz	--budgetsz3000,5000,6000,12000)Údefaultz--modelszmesh,residual_geo,geo_mlpz--epochséP   )Útyper(  z--loss)rÛ   ÚhardrÛ   )Úchoicesr(  z--outÚ,T)ÚparentsÚexist_okr’   ÚjointÚholdout_Úsingle_ÚAC28_only_holdout_16hr   r   ÚAC28_only_holdout_18h01é   )r  r  r�   z.ptF)rÿ   rÄ   rm   Ú
train_runsr  Úweak_label_onlyÚproduction_validÚ+)rm   rÄ   r  Úsetupr6  Úeval_runÚseen_in_trainingr)   Úpositive_nativeÚpositive_fineÚlabel_transfer_iouÚ
checkpointÚAPr  ÚIoUr  Úsecró   )ÚflushÚ*joint_and_individual_weak_label_diagnosticrX   zL10 mm geodesic Gaussian/area from provisional CSV anchors at each graph sizezŠThe three runs and unvalidated labels cannot establish production accuracy; same-run fits are separate from leave-one-run-out predictions.)Ústatusr8  Úindependent_physical_runsÚlabel_policyÚselection_cautionÚepochs_per_fitr  Úrowszreport.jsonr`   )Úindentúutf-8©Úencodingz
report.csvÚwr7   )Únewliner   )Ú
fieldnames)0ÚargparseÚArgumentParserr·   Úadd_argumentr(   r   ÚOUTÚ
parse_argsrn   ÚresolveÚbudgetsÚsplitÚmodelsÚmkdirrF   Úset_num_threadsr   rx   r   rú   r  r  Úsaverÿ   Újoinr)   r#   rj   r$   r'   r%  r   Úrelative_toÚPROJECTrl   Úprintr  Ú
write_textÚjsonÚdumpsÚopenÚcsvÚ
DictWriterr<   ÚwriteheaderÚ	writerowsÚmake_figuresÚ	make_html)ÚparserÚargsr8   rY  ÚkindsrK  rm   rÎ   rÓ   Úby_nameÚsetupsrÄ   r:  Útrain_namesÚ
test_namesÚnrØ   Úfitr@  Ú	test_namerÅ   ÚrowÚreportÚfhÚwriters                            r0   Úmainr{  Þ   s»  € ä×$Ñ$´Ô9€FØ
×Ñ˜Ð-CÐÔDØ
×Ñ˜
Ð,GÐÔHØ
×Ñ˜
¬°bÐÔ9Ø
×Ñ˜Ð*:ÀFÐÔKØ
×Ñ˜¤d´CÐÔ8Ø×ÑÓ€DØ
�(‰(×
Ñ
Ó
€CØ#Ÿ|™|×1Ñ1°#Ô6Ó7Ñ6˜!Œs�1�vÐ6€GÐ7Ø�K‰K×Ñ˜cÓ"€EÜ‡I�I�d T€IÔ*Ü	×Ñ˜!ÔÜÔØ€DÜˆÜ˜vÓ&ˆÙ&-Ó.¡g �1—6‘6˜1‘9 gˆÐ.Ø©WÓ5©W¨˜QŸV›V¨WÑ5ÉÓ7PÉÀ1¸¿»ÈÑ7PÐQÐRˆØÙ#ô%Ù#�qð ˜qŸv™v˜hÐ'¹'Ó)V¹'°QÀQÇVÁVÈqÏvÉvÓEU¨!¯&«&¸'Ñ)VÐYZ×Y_ÑY_ÐX`ÒaØ#ò%ñ 	%ˆàÁWÓMÁWÀ�g˜aŸf™f˜XÐ&¨¯©¨°1·6±6°(Ò;ÀWÑMÑMˆØÐ+¨l¨^¸j¸\ÐJØ-°
¨|¸l¸^ÐLðNñ 	NˆäˆDÜ28Ñ.��{ JÜ" 4¹kÓ)J¹k¸¨'°!«*¸kÑ)JÈDÏKÉKÐ^`Ø-1¯Y©Yô8‘
��sä  d V¨1¨V¨H°A°e°W¸CÐ#@Ñ@�
Ü—
‘
¨%×*:Ñ*:Ó*<ÀdÐV\Ø*5ÀDÇIÁIÐbfØ05ñ7à8BôDó ",�IØ$ YÑ/�FØ%+°TÈÏ	É	Ð\aØ),¯©°+Ó)>ÈIØ/8¸KÐ/GØ+1×+>Ñ+>ÔSVÐW]×WdÑWd×WhÑWhÓWjÓSkÜ,/°×0BÑ0B×0FÑ0FÓ0HÓ,IØ17×1DÑ1DñOð !ðOô %-¨U°FÓ$;ðOð (¬¨Z×-CÑ-CÄGÓ-LÓ)MñO�Cð —K‘K Ô$Ü˜$ ¨¨y¸$ÄÀcÈ+ÑFVÐXYÓ@ZØ¤ s¨<Ñ'8¸!Ó!<¸eÀSÈÁ^Ð[_öaò ",ò 39ò ð ð< EØ"'ÀaØlð $pØ $§¡¸$¿)¹)ÈTñ	S€Fô
 	ˆ=Ñ×$Ñ$¤T§Z¡Z°¸qÔ%AÈGÐ$ÔTÜ
�Ñ
×	"Ñ	" 3°Ð	"Ô	3°rÜ—‘ ¬t°D¸±G«}Ô=ˆØ×ÑÔ˜f×.Ñ.¨tÔ4÷ 
4ô ��w Ô&Üˆd�G˜UÕ#ùò] 8ùò /ùÚ5ùÒ7PùÚ)Vùó %ùâMùò
 *K÷2 
4Ð	3úsO   ÃR*ÅR/Å'R4Æ R9
ÆS
Æ5R>ÇR>Ç"S
Ç?/S	ÉSÑASÒ>S
ÓSc           
     óÊ  ‡‡‡‡— t        j                  dddd¬«      \  }}‰D ]Ò  ŠdD ]Ë  \  Š}|D �‡cg c]  Št        ˆˆˆfd„| D «       «      ‘Œ }}|d   j                  |D �cg c]  }|d	   ‘Œ	 c}|D �cg c]  }|d
   ‘Œ	 c}d‰› d|› �¬«       |D �‡cg c]  Št        ˆˆˆfd„| D «       «      ‘Œ }}|d   j                  |D �cg c]  }|d	   ‘Œ	 c}|D �cg c]  }|d
   ‘Œ	 c}d‰› d|› �¬«       ŒÍ ŒÔ |D ]^  Št        ˆˆfd„| D «       «      }	|d   j	                  |	d	   |	d   dd¬«       |d   j                  t        ‰«      |	d	   |	d   fdd¬«       Œ` |d   j                  d«       |d   j                  d«       |d   j                  d«       |D ]6  }
|
j                  d«       |
j                  d«       |
j                  d¬«       Œ8 |d d D ]  }
|
j                  d«       Œ |d   j                  d «       |d   j                  d!d"¬#«       |j                  t        d$z  d%¬&«       t        j                  |«       y c c}w c c}w c c}w c c}w c c}w c c}w )'Nr   rX   )é   g      @T)ÚfigsizeÚconstrained_layout))r   zAC28 16h)r   z
AC28 18h01)r   z
ME1a 14h06c              3  óf   •K  — | ](  }|d    ‰k(  sŒ|d   ‰k(  sŒ|d   dk(  r|d   ‰k(  r|–— Œ* y­w)rm   rÄ   r:  r0  r;  Nr.   ©Ú.0Úrrm   rÄ   r   s     €€€r0   Ú	<genexpr>zmake_figures.<locals>.<genexpr>  sF   øè ø€ ð R© 1°°(±¸vÓ0EÈ!ÈFÉ)ÐW[ÓJ[Ø!" 7¡¨wÒ!6¸1¸Z¹=ÈDÒ;Pô ©ùs   ƒ1‘1š1r   r)   r  zo-Ú )Úlabelc              3  ó\   •K  — | ]#  }|d    ‰k(  sŒ|d   ‰k(  sŒ|d   d‰› �k(  r|–— Œ% y­w)rm   rÄ   r:  r1  Nr.   r�  s     €€€r0   r„  zmake_figures.<locals>.<genexpr>!  sB   øè ø€ ð B© 1°°(±¸vÓ0EÈ!ÈFÉ)ÐW[ÓJ[Ø!" 7¡°¸$¸Ð/@Ò!@ô ©ùs   ƒ,‘,š,c              3  ó^   •K  — | ]$  }|d    ‰k(  sŒ|d   ‰d   k(  sŒ|d   dk(  sŒ!|–— Œ& y­w)rm   rÄ   r   r;  r   Nr.   )r‚  rƒ  rm   ro  s     €€r0   r„  zmake_figures.<locals>.<genexpr>%  s<   øè ø€ Ðx™d˜ a¨¡k°VÓ&;ÀÀ&Á	ÈUÐSTÉXÓ@UÐZ[Ð\fÑZgÐkwÓZw”1™dùs   ƒ-‘-�-¦-r`   r?  é<   z#d35400)rÓ   Úcolor)rX   r’   zoffset points)ÚxytextÚ
textcoordsz Joint training: same-run weak APzLeave-one-run-out weak APzME1a weak-label transferÚlogzactual graph nodesg      Ð?)Úalphazmapped average precisionz$IoU of labels mapped to finest graphé   r  )ÚfontsizeÚloczcomparison.pngéª   )Údpi)ÚpltÚsubplotsÚnextÚplotÚscatterÚannotater   Ú	set_titleÚ
set_xscaleÚ
set_xlabelÚgridÚ
set_ylabelÚlegendÚsavefigrV  Úclose)rK  rY  ro  ÚfigÚaxesr†  rm   Úselectedrƒ  rw  ÚaxrÄ   r   s     `   `    @@r0   rk  rk    s¿  û€ Ü—‘˜Q ¨9ÈÔN�I€CˆÛˆó:‰KˆD�%ñ ahôiÙ`gÐV\ô õ R©ó Rõ RØ`gð ð ià�‰G�L‰L±XÓ>±X°˜!˜NÓ+°XÑ>ÑYaÓ@bÑYaÐTUÀÀ;ÃÐYaÑ@bÐdhÐswÐrxÐxyÐzð  zAð  qBˆLô  CáPWôYÙPWÀfô õ B©ó Bõ BØPWð ð Yà�‰G�L‰L±XÓ>±X°˜!˜NÓ+°XÑ>ÑYaÓ@bÑYaÐTUÀÀ;ÃÐYaÑ@bÐdhÐswÐrxÐxyÐzð  zAð  qBˆLõ  Cñ:ð ó ˆÜÔx™dÓxÓxˆØˆQ‰�‰˜˜NÑ+¨SÐ1EÑ-FÈ"ÐT]ˆÔ^ØˆQ‰×Ñœ˜V› s¨>Ñ':¸CÐ@TÑ<UÐ&VÐ_eð  sBÐõ  	Cð ð 	ˆ�G×ÑÐ8Ô9Øˆ�G×ÑÐ1Ô2Øˆ�G×ÑÐ0Ô1ÛˆØ
�‰�eÔ˜bŸm™mÐ,@ÔAÀ2Ç7Á7ÐQTÀ7ÕCUð à�2�A‹hˆ�r—}‘}Ð%?Õ@ˆhØˆ�G×ÑÐ=Ô>Øˆ�G‡N�N˜A 6€NÔ*Ø‡K�K”Ð&Ñ&¨C€KÔ0´#·)±)¸Cµ.ùò%iùâ>ùÒ@bùòYùâ>ùÒ@bs#   ³IÁ$IÁ6IÂIÃIÃI c                óð  ‡— | D �cg c]!  }|d   dk(  s|d   j                  d«      sŒ |‘Œ# }}dj                  d„ |D «       «      }d|v rdn|d   }g }|D ]ª  }dD ]£  }	| D �cg c]  }|d	   |k(  sŒ|d
   |k(  sŒ|d   |	k(  r|‘Œ  c}Šˆfd„}
 |
d|	› �«       |
d«       |
d|	› �«      }}}t        d„ ‰D «       d «      }|j                  |�d|d›d|	› d|d›d|d›d|d›d|d›d�nd|d›d|	› d|d›d|d›d|d›d�«       Œ¥ Œ¬ t        dz  j                  «       rdnd}dt        |«      › dt        |«      › d|› ddj                  |«      › d|› d|› d�}t        dz  j                  |d¬ «       y c c}w c c}w )!Nr:  r0  r1  r7   c              3  óð   K  — | ]n  }d |d   d›dt        j                  |d   «      › dt        j                  |d   «      › dt        j                  |d   «      › d|d   d›d|d	   d›d|d
   d›d�–— Œp y­w)ú<tr><td>rm   r-  ú	</td><td>rÄ   r:  r;  r  ú.4fr  r?  ú
</td></tr>N)ÚhtmlÚescape©r‚  rƒ  s     r0   r„  zmake_html.<locals>.<genexpr>5  s§   è ø€ ð Vñ MUÀqð ˜q ™{¨1˜o¨Y´t·{±{À1ÀVÁ9Ó7MÐ6Nð OÜŸ;™; q¨¡zÓ2Ð3°9¼T¿[¹[ÈÈ:ÉÓ=WÐ<Xð YØ˜[™>¨#Ð.¨i¸¸,¹ÈÐ7Lð MØÐ1Ñ2°3Ð7°zôCñ MUùs   ‚A4A6rÀ   r   )r   r   r   rm   rÄ   r;  c                ó0   •‡ — t        ˆ fd„‰D «       d «      S )Nc              3  ó:   •K  — | ]  }|d    ‰k(  sŒ|d   –— Œ y­w)r:  r  Nr.   )r‚  rƒ  r:  s     €r0   r„  z.make_html.<locals>.<lambda>.<locals>.<genexpr>?  s"   øè ø€ Ð&[¹t¸!ÀqÈÁzÐUZÓGZ q¨¥~¹tùs   ƒ‘
)r–  )r:  Úbases   `€r0   Ú<lambda>zmake_html.<locals>.<lambda>?  s   ù€ ¤Ó&[¹tÓ&[Ð]aÔ!br/   r2  c              3  óP   K  — | ]  }|d    j                  d«      sŒ|d   –— Œ  y­w)r:  ÚAC28_only_holdoutr  N)Ú
startswithr®  s     r0   r„  zmake_html.<locals>.<genexpr>A  s'   è ø€ Ðg±D¨q¸A¸g¹J×<QÑ<QÐReÕ<f˜A˜k�N±Dùs   ‚&œ
&r¨  r-  r©  rª  r«  u   </td><td>â€”</td></tr>zprediction_maps.pngz›<section><h2>Where the model predicts</h2><img src="prediction_maps.png" alt="Weak target versus individual, joint and held-out prediction maps"></section>aï  <!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Joint AC28 and ME1a GNN diagnostics</title><style>body{font:15px/1.5 system-ui,sans-serif;max-width:1380px;margin:auto;padding:24px;background:#f4f7fb;color:#172333}section{background:white;border:1px solid #dbe4ee;border-radius:10px;padding:18px;margin:16px 0}.warning{background:#fff0cb;border-left:5px solid #b87d00;padding:14px}img{max-width:100%}table{border-collapse:collapse;width:100%}td,th{padding:7px;border-bottom:1px solid #dce4eb;text-align:right}td:nth-child(2),td:nth-child(3),td:nth-child(4),th:nth-child(2),th:nth-child(3),th:nth-child(4){text-align:left}.scroll{overflow:auto}</style>
<h1>AC28 + ME1a: GNN and node-size experiment</h1><p class="warning">All labels are provisional CSV-seeded areas; registration is unvalidated. Same-run fit is separate from leave-one-run-out prediction. Three production runs cannot establish production accuracy.</p>
<section><h2>Architecture and graph size</h2><p>Mesh GNN uses the previous message processor. Residual Geo GNN adds short residual edge messages and position frequencies. Geo MLP has the same position and process input without graph messages. The experiment covers z graph budgets and zÕ model families, using per-run balanced weak loss.</p><img src="comparison.png" alt="Joint and leave-one-run-out AP by graph size"></section>
<section><h2>Does pooling AC28 and ME1a help?</h2><p>Values below show aÀ   average precision. Individual and joint values are evaluated on runs used for fitting. Held-out values evaluate an unseen run. The last column trains on the other AC28 run only, allowing a direct comparison with adding ME1a for AC28 holdouts.</p><div class="scroll"><table><thead><tr><th>Requested nodes</th><th>Evaluated run</th><th>Individual fit AP</th><th>Joint fit AP</th><th>Held-out AP</th><th>AC28-only held-out AP</th></tr></thead><tbody>a  </tbody></table></div></section>
<section><h2>Scores by run</h2><div class="scroll"><table><thead><tr><th>Requested nodes</th><th>Model</th><th>Training</th><th>Evaluated run</th><th>Mapped AP</th><th>Mapped IoU</th><th>Weak-label transfer IoU</th></tr></thead><tbody>z!</tbody></table></div></section>
u¹   
<p><a href="report.csv">Full fit and per-run metrics CSV</a> Â· <a href="report.json">Metrics and checkpoints JSON</a> Â· <a href="../index.html">Main AC28 + ME1a report</a></p></html>z
index.htmlrM  rN  )rµ  r_  r–  rl   rV  ÚexistsrA   rc  )rK  rY  ro  rƒ  r¤  ÚtableÚfocusÚeffect_rowsrm   rJ   ÚfindÚsingler0  ÚheldÚac_onlyÚimageÚpager±  s                    @r0   rl  rl  3  s   ø€ ÙÓ^™4�a 1 W¡:°Ò#8¸A¸g¹J×<QÑ<QÐR\Õ<]’˜4€HÐ^Ø�G‰Gñ Vñ MUóVó V€Eð -°Ñ5‰N¸5À¹8€EØ€KÛˆÛ;ˆCÙ#ó .™t˜! q¨¡{°fÓ'<ÀÀ6ÁÈeÓASØ˜*™¨Ò,ò ˜tñ .ˆDãbˆDÙ"&¨°° Ó"7¹¸g»ÉÈxÐX[ÐW\ÐM]ÓH^˜4�EˆFÜÑg±DÓgÐimÓnˆGØ×ÑàAHÐATð "*¨&°¨°9¸S¸EÀÈ6ÐRUÈ,ð W&Ø&+¨C [°	¸$¸s¸ð D&Ø&-¨c ]°*ñ >ð "*¨&°¨°9¸S¸EÀÈ6ÐRUÈ,ð W&Ø&+¨C [°	¸$¸s¸ÐCYð [õ\ñ <ð ô orð  uJñ  oJ÷  nRñ  nRô  nTñ  jð  Z\€EðJô KNð  OVó  KWð  JXð  Xkô  loð  puó  lvð  kwð wHØHMÀwð  OOð  PR÷  PWñ  PWð  Xcó  Pdð  Oeð elð mrð  lsð sØ€ð yð|€Dô 	ˆ<Ñ×#Ñ# D°7Ð#Õ;ùò9 _ùò.s   †!E.¨E.Á!E3Á/E3Á8E3Ú__main__)rI   r   rJ   r   rµ   r   )rm   r(   rµ   úlist[Sample])rÄ   r   rÅ   r   rµ   ú	nn.Module)rÎ   rÁ  rµ   z:tuple[Tensor, Tensor, Tensor, Tensor, Tensor, list[slice]])rØ   rÂ  r§   Útuplerµ   r   )rÛ   )
râ   r   rÎ   rÁ  rÒ   zlist[slice]rã   r   rµ   r   )rÄ   r   rÎ   rÁ  r  r(   r  r(   r  r   rµ   ztuple[nn.Module, dict])rØ   rÂ  rÅ   r   rµ   Údict)rµ   ÚNone)rK  z
list[dict]rY  z	list[int]ro  z	list[str]rµ   rÅ  )<r·   Ú
__future__r   rS  rg  r¬  rd  rø   Údataclassesr   Úpathlibr   Ú
matplotlibÚuseÚmatplotlib.pyplotÚpyplotr”  r!  r:   Úscipy.spatialr   rF   r   r	   Útorch.nn.functionalÚ
functionalrÞ   Úmodels.architecturesr
   Úmodels.compare_cad_predictionsr   Úmodels.datar   r   Úmodels.trainingr   ô   ì „ì²˜ë¦¬.match_targetsr   Ú__file__rX  r.  ra  rV  ra   r   rR   rx   ÚModulerz   r»   rÇ   rÔ   r²   rë   rú   r%  r{  rk  rl  r*   r.   r/   r0   Ú<module>r×     s?  ðñõ
 #ã Û 
Û Û Û Ý !Ý ã Ø €
‡�ˆuÔ Ý Û Ý !Û ß ß Ð å 3Ý 2ß FÝ +Ý 5á
ˆx‹.×
 Ñ
 Ó
"×
*Ñ
*¨1Ñ
-€ØÐ6Ñ6€Ø	�V˜W eÐ,Ø	�v˜w¨Ð0Ø	�y 'Ð,AÑ"AÀ7ÐKðM€ð
 ÷ð ó ðó	RóôB@�R—Y‘Yô @ô<dˆR�Y‰Yô dó ó
(ó8ô

&ôBó2
Kó8$óvAó4<ð@ ˆzÒ™4�6Ðr/   