
     j?                        d Z ddlZddlmZ ddlmZmZmZm	Z	 dej                  dededej                  fd	Z G d
 d      Z G d d      Zdej                  dej                  deeef   fdZedk(  r ed        ed        ed       d\  ZZej,                  dedef   \  ZZdd ej2                  dej4                  z  dz  ez  ez        z   ej6                  dej4                  z  dz  ez  ez        z  z   d ej8                  eedz  z
  dz  eedz  z
  dz  z    dz        z  z   d ej:                  eedz  z
        dk  z  z   d ej:                  eedz  z
        dk  z  z   Z ej>                  edd      jA                  ejB                        Z ede de         ed !      Z"e"jG                  e      Z$e"jK                  d"       ejM                  d"      Z' ee'      Z(e(jS                         Z* eee*      Z+ ed#e+         ejX                  ded$z
  edz        d%z   Z- ejX                  ded$z
  edz        d%z   Z. ej^                  e.e-d&'      \  Z0Z1e(je                  e1e0      Z3 ed(e3jh                   d)       e(jk                  d*d+d*d+d,d,-      Z6 ed.e6jh                   d/        ed0       d1D ]|  Z7 ee7!      Z8e8jG                  ed23      Z9 ee9      Z:e:jS                         Z; eee;      Z<e<d4   d5kD  rd6ne<d4   d7kD  rd8nd9Z= ed:e7d;d<e9d=   j|                  d>d?e<d4   d@dAe=        ~  edB       yy)Cu]  
skiss_fourier_codec.py
================================================================================
2D Skiss-Fourier Image Manifold Encoder / Decoder

Theory:
    - Explicit pixel grids are skiss-violations (massive, inert, unstoreable).
    - Images are retro-compressed into a finite parametric Fourier surface:
        I(x,y; θ) = Σ_p Σ_q θ_pq · u_p(y) · v_q(x)
    - The pixel-coordinate path is erased; only the spectral residue θ survives.
    - Generation is performed on demand at any real-valued (x,y).
================================================================================
    N)Path)UnionTupleDictOptionalcoordsKperiodreturnc                     t        j                  | t         j                        } t        j                  d|dz   t         j                        }t        j                  | j
                  d   dft         j                        }|dk(  r|S t        j                  dt         j                  z  |z  | dddf   z  |z        }t        j                  dt         j                  z  |z  | dddf   z  |z        }t        j                  |||gd      S )u  
    Build the real 1D Fourier basis matrix on coordinate vector `coords`.
    
    Columns: [1,
              cos(2π·1·c/p), ..., cos(2π·K·c/p),
              sin(2π·1·c/p), ..., sin(2π·K·c/p)]
    
    Returns:
        B: ndarray of shape (len(coords), 2*K+1)
    dtype   r          @Naxis)
npasarrayfloat64arangeonesshapecospisinconcatenate)r   r	   r
   kr   cos_partsin_parts          A/home/per/Documents/General Fourier Series/skiss_fourier_codec.py_build_real_fourier_basis_1dr!      s     ZZbjj1F
		!QU"**-A77FLLOQ'rzz:DAvvvcBEEkAoq$w7&@AHvvcBEEkAoq$w7&@AH>>4841==    c                       e Zd ZdZ	 	 ddee   dee   defdZede	j                  dedefd	       Zdde	j                  d
edefdZdeeef   fdZedeeef   defd       Zy)SkissEncoderu  
    Retro-compresses an explicit H×W image into a finite parameter tensor θ.
    
    The fitting exploits the separable Kronecker structure:
        min_Θ || I - U Θ Vᵀ ||_F²
    solved via the normal equations:
        A Θ Bᵀ = Uᵀ I V,   where A = UᵀU, B = VᵀV.
    Nr	   epsilon
reg_lambdac                 Z    ||t        d      || _        || _        || _        d| _        y)aq  
        Args:
            K: Manual critical rank (number of Fourier modes per axis).
               If None, epsilon must be provided.
            epsilon: Fraction of spectral energy to retain (0 < epsilon < 1).
                     Used to auto-estimate K if K is not given.
            reg_lambda: Tiny ridge for numerical stability near degenerate modes.
        NzSpecify either K or epsilon.)
ValueErrorK_manualr%   r&   theta)selfr	   r%   r&   s       r    __init__zSkissEncoder.__init__;   s5     9;<<$%)
r"   imager   c                 l   | j                   dk(  r| j                  d      }n| }|j                  \  }}t        j                  j                  |j                  t        j                              }t        j                  |      j                         }t        j                  |      ddd   }t        j                  |      }|d   dz   }	t        t        j                  |d|z
  |	z              dz   }
t        t        j                  t        j                  |
      dz
  d	z              }t!        |d      S )
z6Auto-estimate critical rank from FFT energy retention.      r   Ng-q=      ?r   r   )ndimmeanr   r   fftfft2astyper   absflattensortcumsumintsearchsortedceilsqrtmax)r-   r%   grayHWFmagvalsr;   totaln_keepK_ests               r    _estimate_KzSkissEncoder._estimate_KL   s     ::?::1:%DDzz1FFKKBJJ/0ffQi!wws|DbD!4r
U"R__VcGmu-DEFJBGGRWWV_s2c9:;5!}r"   verbosec                    |j                   dk(  r|dddddf   }|j                  \  }}}|j                  t        j                        }| j
                  | j
                  n| j                  || j                        }t        |t        ||      dz  dz
        }t        |d      }t        j                  |t        j                        }t        j                  |t        j                        }	t        ||t        |            }
t        |	|t        |            }|
j                  |
z  }|j                  |z  }| j                  dkD  rd|| j                  t        j                  |j                  d         z  z  }|| j                  t        j                  |j                  d         z  z  }t        j                   |d|z  dz   d|z  dz   ft        j                        }t#        |      D ]w  }|
j                  |dddd|f   z  |z  }t        j$                  j'                  ||      }t        j$                  j'                  ||j                        j                  }|||<   y ||||f|t        |      t        |      dt        | j                        d| _        |rF||z  |z  }|j*                  }||z  }t-        d| d	| d	|        t-        d
| d| d| d|dd		       | j(                  S )u=  
        Compress an image into the skiss residue θ.
        
        Args:
            image: ndarray, shape (H, W) or (H, W, C). Values typically in [0, 255].
            verbose: Print compression statistics.
        
        Returns:
            theta: Serializable dict containing the spectral residue.
        r0   Nr   r   r   real_fourier_separable)coefficientsr	   r   channelsperiod_yperiod_xbasisr&   z[SkissEncoder] Image:    ×z[SkissEncoder] K=z  |  Params: z  |  Pixels: z  |  Compression: z.1f)r3   r   r7   r   r   r)   rJ   r%   minr@   r   r!   floatTr&   eyezerosrangelinalgsolver*   sizeprint)r+   r-   rK   rB   rC   CIr	   y_coordsx_coordsUVABcoeffscRHSZTheta_c	orig_size
param_sizeratios                         r    encodezSkissEncoder.encode_   s    ::?!Q*%E++1aLL$!]]6DMMD<L<LQPTP\P\<]3q!9>A%&1I 99Qbjj199Qbjj1 )1eAh?(1eAh?
 CC!GCC!G??Q266!''!*#555A266!''!*#555A
 1a!eaiQ32::Fq 	 A##!Q'
"Q&C		3'Aiiooa-//GF1I		  #Vaa-0	

 A	IJ
*E*1#Rs"QC89%aSj\ B&K'9%BH I zzr"   pathc                     | j                   t        d      t        j                  t	        |      fi | j                    y)z(Save theta as a compressed .npz archive.Nz%Nothing to save. Call encode() first.)r*   RuntimeErrorr   savez_compressedstr)r+   ro   s     r    savezSkissEncoder.save   s3    ::FGG
CI44r"   c                     t        j                  t        |       d      }|j                         D ci c]'  \  }}||j                  dk(  r|j                         n|) }}}|S c c}}w )zLoad a theta dict from disk.F)allow_pickler   )r   loadrs   itemsr3   item)ro   datar   vr*   s        r    
load_thetazSkissEncoder.load_theta   sW     wws4yu5AENA1QVVX!3NN Os   ,A%)NNgư>)T)__name__
__module____qualname____doc__r   r<   rU   r,   staticmethodr   ndarrayrJ   boolr   rn   r   rs   r   rt   r|    r"   r    r$   r$   1   s     LP%)*(3- *% *"*" 2::  #  $FBJJ F F FP5sDy) 5 sDy) d  r"   r$   c                   L   e Zd ZdZdefdZ	 	 ddej                  dej                  dee	   de	d	ej                  f
d
Z
	 ddej                  dej                  dee	   d	ej                  fdZddeee	e	f      d	ej                  fdZdedededede	de	d	ej                  fdZy)SkissDecoderu   
    Generates pixels from the skiss residue θ at arbitrary coordinates.
    The explicit pixel path is never reconstructed unless explicitly requested.
    r*   c                     || _         t        |d         | _        |d   | _        t        |d         | _        t        |d         | _        t        |d         | _        |d   \  | _        | _	        y )Nr	   rN   rO   rP   rQ   r   )
r*   r<   r	   rf   r^   rU   rP   rQ   H_origW_orig)r+   r*   s     r    r,   zSkissDecoder.__init__   si    
U3ZN+U:&'eJ/0eJ/0#(> T[r"   Nxychannel
chunk_sizer   c                    t        j                  |t         j                        }t        j                  |t         j                        }|j                  |j                  k7  rt	        d      |j                  }|j                         }|j                         }|j                  }||n|| j                  fz   }	t        j                  ||n|| j                  ft         j                        }
t        d||      D ]  }t        ||z   |      }||| }||| }t        || j                  | j                        }t        || j                  | j                        }|0| j                  |   }t        j                   ||z  |z  d      |
|| t        | j                        D ]5  }| j                  |   }t        j                   ||z  |z  d      |
|||f<   7  |
j#                  |	      S )uU  
        Evaluate the parametric Fourier surface at arbitrary real coordinates.
        Uses chunked processing to remain memory-efficient for large query sets.
        
        Args:
            x: ndarray of arbitrary shape (float, in units of original pixel grid).
            y: ndarray, same shape as x.
            channel: None → return all channels (..., C). 
                     int → return single channel (same shape as x).
            chunk_size: Number of points to process per batch.
        
        Returns:
            values: ndarray of generated pixel intensities.
        r   z"x and y must have identical shape.r   r   r   )r   r   r   r   r(   ravelr\   r^   rX   rY   rT   r!   r	   rQ   rP   rf   sumreshape)r+   r   r   r   r   
orig_shapeflat_xflat_yn_pts	out_shapeoutiendbatch_xbatch_yV_batchU_batchThetarg   s                      r    generatezSkissDecoder.generate   s     JJq

+JJq

+77aggABBWW
")"5J:	;Q	hh 3u%PRPZPZ[q%, 	PAa*ne,CQsmGQsmG 37DFFDMMRG27DFFDMMRG"G,VVWu_$?aHAc
tvv PA KKNE$&FFGeOw+FQ$OC#qMP	P" {{9%%r"   ra   r`   c                 ~   t        j                  |t         j                        }t        j                  |t         j                        }t        || j                  | j
                        }t        || j                  | j                        }|!| j                  |   }||z  |j                  z  S t        |      t        |      }}t        j                  ||| j                  ft         j                        }	t        | j                        D ]-  }
| j                  |
   }||z  |j                  z  |	dddd|
f<   / |	S )a  
        Memory-efficient reconstruction for grid-aligned coordinates.
        Exploits the separable property: I = U @ Theta @ V.T
        
        Args:
            x_coords: 1D array of x-coordinates (width W').
            y_coords: 1D array of y-coordinates (height H').
            channel: None for all channels, or int for specific channel index.
            
        Returns:
            values: (H', W', C) or (H', W') array.
        r   N)r   r   r   r!   r	   rQ   rP   rf   rV   lenrX   r^   rY   )r+   ra   r`   r   rc   rb   r   H_primeW_primer   rg   s              r    generate_gridzSkissDecoder.generate_grid   s     ::hbjj9::hbjj9 )4664==I(4664==IKK(Eu9qss?""8}c(mWG((GWdff5RZZHC466] /A 5y133Aq!G/ Jr"   r   c                     || j                   | j                  f}|\  }}t        j                  |t        j                        }t        j                  |t        j                        }| j                  ||      S )z\
        Reconstruct a full pixel grid. If shape is None, uses original dimensions.
        r   )r   r   r   r   r   r   )r+   r   rB   rC   r`   ra   s         r    reconstructzSkissDecoder.reconstruct  s_     =[[$++.E199Qbjj199Qbjj1!!(H55r"   x_minx_maxy_miny_maxres_xres_yc                     t        j                  |||      }t        j                  |||      }| j                  ||      S )zO
        Generate a continuous viewport patch at arbitrary resolution.
        )r   linspacer   )	r+   r   r   r   r   r   r   ra   r`   s	            r    reconstruct_patchzSkissDecoder.reconstruct_patch%  s;     ;;ueU3;;ueU3!!(H55r"   )Ni )N)r}   r~   r   r   r   r,   r   r   r   r<   r   r   r   r   rU   r   r   r"   r    r   r      s    
2d 2 OS#*.&"** .& .&hsm .& .&/1zz.&b 04bjj BJJ '}8:

B	6%S/!: 	6bjj 	66u 6U 6!&6/46!$6-0657ZZ6r"   r   originalreconstructedc                    | j                  t        j                        } |j                  t        j                        }t        t        j                  | |z
  dz              }|dk(  rt        d      }nE| j                         dkD  rdnd}dt        j                  |t        j                  |      z        z  }|||dkD  dS )	zDReturn MSE and PSNR between original and skiss-reconstructed images.r0   r   infr2   g     o@g      4@g      >@)msepsnrskiss_complete)r7   r   r   rU   r4   r@   log10r?   )r   r   r   r   max_vals        r    skiss_metricsr   4  s    rzz*H!((4M
M1a78
9C
axU|#<<>C/%Sbhhw566tDDr"   __main__zF======================================================================u'   Skiss-Fourier Image Codec — Self-Test)   r   g      `@g      P@r0   r/   g      @@g      @g      0@      z
Synthetic test image: rS      )r	   zskiss_residue.npzz
Full reconstruction metrics: r   g      ?ij)indexingz 
Super-resolution sample shape: u3    (generated at 2× native resolution from θ alone)2   P   i,  )r   r   r   r   r   r   zViewport patch shape: z+ (arbitrary resolution from skiss manifold)z'
--- Progressive Skiss Transmission ---)r   r0         r   F)rK   r   #   u	   ✅ Solid   u   ⚠️ Liquidu   ❌ Gasz  K=2dz  |  Params=rN   5dz
  |  PSNR=z6.2fz dB  |  z*
Done. Residue saved to: skiss_residue.npz)?r   numpyr   pathlibr   typingr   r   r   r   r   r<   rU   r!   r$   r   rs   r   r}   r]   rB   rC   mgridr   r   r   r   r   expr8   test_imgclipr7   uint8encoderrn   r*   rt   r|   theta_loadeddecoderr   recmetricsr   fine_xfine_ymeshgridfine_y_gridfine_x_gridr   	super_resr   r   patchK_testenc_tmpth_tmpdec_tmprec_tmpmstatusr\   r   r"   r    <module>r      s     / /> > >U >rzz >2B BRs6 s6t
EBJJ 
Erzz 
Ed3PU:FV 
E" z	(O	
34	(O DAq88AaC1HDAq 	
BEE	A)A-.
.BEE	A8IA8M1N
N	O
1qs7Q,!ac'A56-HI
I	J &"&&QqS/A%
&	' &"&&QqS/A%
&		'  rwwxC(//9H	$QCr!
-. R GNN8$ELL$%  **+>?L<(G 


CHc*G	+G9
56 R[[AE1q5)C/FR[[AE1q5)C/F*r{{66DIK  k:I	-ioo-> ?? @ A %%Bb"-0 & =E	"5;;- 07 8 9 

45" ;(%8v&%%'(G, !&	B&	TV_\eVBK|F>,B,G,G+K L64(: 	;; 

78{ r"   