1use serde::{Deserialize, Serialize};
2
3use crate::{
4 codebook::CODEBOOK_SCHEMA,
5 codec::CODE_SCHEMA,
6 profile::{FibQuantProfileV1, NormFormat, PROFILE_SCHEMA},
7 rotation::ROTATION_ALGORITHM_VERSION,
8};
9
10pub const RECEIPT_SCHEMA: &str = "fib_quant_compression_receipt_v1";
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct FibQuantCompressionReceiptV1 {
15 pub schema_version: String,
17 pub profile_digest: String,
19 pub codebook_digest: String,
21 pub rotation_digest: String,
23 pub source_vector_digest: String,
25 pub encoded_digest: String,
27 pub norm_format: NormFormat,
29 pub code_schema_version: String,
31 pub profile_schema_version: String,
33 pub codebook_schema_version: String,
35 pub ambient_dim: u32,
37 pub block_dim: u32,
39 pub codebook_size: u32,
41 pub paper_rate_bits_per_coord: f64,
43 pub wire_index_bits: u8,
45 pub wire_bits_per_coord: f64,
47 pub rotation_seed: u64,
49 pub rotation_algorithm_version: String,
51 pub codebook_seed: u64,
53 pub mse: Option<f64>,
55 pub cosine_similarity: Option<f64>,
57 pub fallback_available: bool,
59 pub recorded_unix_seconds: i64,
61 pub original_bytes: usize,
63 pub encoded_bytes: usize,
65 pub compression_ratio: f64,
67 pub wire_bits_per_coord_actual: f64,
69 pub lloyd_refined: bool,
71}
72
73impl FibQuantCompressionReceiptV1 {
74 #[allow(clippy::too_many_arguments)]
75 pub(crate) fn new(
76 profile: &FibQuantProfileV1,
77 profile_digest: String,
78 codebook_digest: String,
79 rotation_digest: String,
80 source_vector_digest: String,
81 encoded_digest: String,
82 original_bytes: usize,
83 encoded_bytes: usize,
84 lloyd_refined: bool,
85 ) -> Self {
86 let compression_ratio = if encoded_bytes > 0 {
87 original_bytes as f64 / encoded_bytes as f64
88 } else {
89 f64::INFINITY
90 };
91 Self {
92 schema_version: RECEIPT_SCHEMA.into(),
93 profile_digest,
94 codebook_digest,
95 rotation_digest,
96 source_vector_digest,
97 encoded_digest,
98 norm_format: profile.norm_format.clone(),
99 code_schema_version: CODE_SCHEMA.into(),
100 profile_schema_version: PROFILE_SCHEMA.into(),
101 codebook_schema_version: CODEBOOK_SCHEMA.into(),
102 ambient_dim: profile.ambient_dim,
103 block_dim: profile.block_dim,
104 codebook_size: profile.codebook_size,
105 paper_rate_bits_per_coord: profile.paper_rate_bits_per_coord,
106 wire_index_bits: profile.wire_index_bits,
107 wire_bits_per_coord: profile.wire_bits_per_coord,
108 rotation_seed: profile.rotation_seed,
109 rotation_algorithm_version: ROTATION_ALGORITHM_VERSION.into(),
110 codebook_seed: profile.codebook_seed,
111 mse: None,
112 cosine_similarity: None,
113 fallback_available: false,
114 recorded_unix_seconds: current_unix_seconds(),
115 original_bytes,
116 encoded_bytes,
117 compression_ratio,
118 wire_bits_per_coord_actual: profile.wire_bits_per_coord,
119 lloyd_refined,
120 }
121 }
122}
123
124fn current_unix_seconds() -> i64 {
125 std::time::SystemTime::now()
126 .duration_since(std::time::UNIX_EPOCH)
127 .map(|duration| duration.as_secs() as i64)
128 .unwrap_or(0)
129}