@@ -772,4 +772,77 @@ mod tests {
772772 ) ;
773773 Ok ( ( ) )
774774 }
775+
776+ /// Verify serde roundtrip for QJL: serialize metadata + children, then rebuild.
777+ #[ test]
778+ fn qjl_serde_roundtrip ( ) -> VortexResult < ( ) > {
779+ use vortex_array:: DynArray ;
780+ use vortex_array:: vtable:: VTable ;
781+
782+ let fsl = make_fsl ( 10 , 128 , 42 ) ;
783+ let config = TurboQuantConfig {
784+ bit_width : 4 ,
785+ seed : Some ( 456 ) ,
786+ } ;
787+ let encoded = turboquant_encode_qjl ( & fsl, & config) ?;
788+ let encoded = TurboQuant :: try_match ( & * encoded) . unwrap ( ) ;
789+
790+ // Serialize metadata.
791+ let metadata = <TurboQuant as VTable >:: metadata ( encoded) ?;
792+ let serialized =
793+ <TurboQuant as VTable >:: serialize ( metadata) ?. expect ( "metadata should serialize" ) ;
794+
795+ // Collect children — QJL has 7 (4 MSE + 3 QJL).
796+ let nchildren = <TurboQuant as VTable >:: nchildren ( encoded) ;
797+ assert_eq ! ( nchildren, 7 ) ;
798+ let children: Vec < ArrayRef > = ( 0 ..nchildren)
799+ . map ( |i| <TurboQuant as VTable >:: child ( encoded, i) )
800+ . collect ( ) ;
801+
802+ // Deserialize metadata.
803+ let deserialized = <TurboQuant as VTable >:: deserialize (
804+ & serialized,
805+ encoded. dtype ( ) ,
806+ encoded. len ( ) ,
807+ & [ ] ,
808+ & SESSION ,
809+ ) ?;
810+
811+ assert ! ( deserialized. has_qjl) ;
812+ assert_eq ! ( deserialized. dimension, encoded. dimension( ) ) ;
813+
814+ // Verify decode: original vs rebuilt from children.
815+ let mut ctx = SESSION . create_execution_ctx ( ) ;
816+ let decoded_original = encoded
817+ . clone ( )
818+ . into_array ( )
819+ . execute :: < FixedSizeListArray > ( & mut ctx) ?;
820+ let original_elements = decoded_original. elements ( ) . to_canonical ( ) ?. into_primitive ( ) ;
821+
822+ // Rebuild with QJL children.
823+ let rebuilt = crate :: array:: TurboQuantArray :: try_new_qjl (
824+ encoded. dtype ( ) . clone ( ) ,
825+ children[ 0 ] . clone ( ) ,
826+ children[ 1 ] . clone ( ) ,
827+ children[ 2 ] . clone ( ) ,
828+ children[ 3 ] . clone ( ) ,
829+ crate :: array:: QjlCorrection {
830+ signs : children[ 4 ] . clone ( ) ,
831+ residual_norms : children[ 5 ] . clone ( ) ,
832+ rotation_signs : children[ 6 ] . clone ( ) ,
833+ } ,
834+ deserialized. dimension ,
835+ deserialized. bit_width as u8 ,
836+ ) ?;
837+ let decoded_rebuilt = rebuilt
838+ . into_array ( )
839+ . execute :: < FixedSizeListArray > ( & mut ctx) ?;
840+ let rebuilt_elements = decoded_rebuilt. elements ( ) . to_canonical ( ) ?. into_primitive ( ) ;
841+
842+ assert_eq ! (
843+ original_elements. as_slice:: <f32 >( ) ,
844+ rebuilt_elements. as_slice:: <f32 >( )
845+ ) ;
846+ Ok ( ( ) )
847+ }
775848}
0 commit comments