pub fn encode_portfolio_f32(
x: &[f32],
dims: &[usize],
cfg: &WavConfig,
screen: bool,
) -> (Vec<u8>, AutoReport)Expand description
Portfolio encode: encode with every candidate the pre-screen keeps (all
applicable ones when screen is false) and keep the smallest stream. The
output is one tag byte (counted in the rate) followed by the stream.
Examples found in repository?
examples/tc.rs (line 106)
34fn main() {
35 let args: Vec<String> = std::env::args().skip(1).collect();
36 match args.first().map(String::as_str) {
37 Some("encode") if args.len() >= 3 => {
38 let x = read_f32(&args[1]);
39 let range = {
40 let (a, b) = x
41 .iter()
42 .fold((f32::INFINITY, f32::NEG_INFINITY), |(a, b), &v| {
43 (a.min(v), b.max(v))
44 });
45 (b - a) as f64
46 };
47 let mut dims = vec![x.len()];
48 let mut bound = None;
49 let mut codec = "wavelet".to_string();
50 let mut rho = None;
51 let mut model = "hand".to_string();
52 let mut i = 3;
53 while i < args.len() {
54 if args[i] == "--fast" {
55 codec = "fast".to_string();
56 i += 1;
57 continue;
58 }
59 let v = args.get(i + 1).cloned().unwrap_or_else(|| usage());
60 match args[i].as_str() {
61 "--dims" => dims = v.split('x').map(|s| s.parse().unwrap()).collect(),
62 "--psnr" => bound = Some(ErrorBound::Psnr(v.parse().unwrap())),
63 "--rmse" => bound = Some(ErrorBound::Rmse(v.parse().unwrap())),
64 "--max-abs" => bound = Some(ErrorBound::MaxAbs(v.parse().unwrap())),
65 "--max-rel" => {
66 bound = Some(ErrorBound::MaxAbs(v.parse::<f64>().unwrap() * range))
67 }
68 "--codec" => codec = v,
69 "--rho" => rho = Some(v.parse().unwrap()),
70 "--model" => model = v,
71 _ => usage(),
72 }
73 i += 2;
74 }
75 let bound = bound.unwrap_or_else(|| usage());
76 let t = Instant::now();
77 let (bytes, json) = match codec.as_str() {
78 "wavelet" => {
79 let mut cfg = wavcodec::WavConfig::new(bound);
80 if let Some(r) = rho {
81 cfg.rho = r;
82 }
83 cfg.model = cram_codec::learned::parse_model_arg(&model);
84 let (b, s) = wavcodec::encode_f32(&x, &dims, &cfg);
85 let j = format!(
86 "\"coef_bytes\":{},\"model_bytes\":{},\"outlier_bytes\":{},\"n_outliers\":{},\"delta\":{},\"rmse\":{},\"max_abs\":{},\"passes\":{}",
87 s.coef_bytes, s.model_bytes, s.outlier_bytes, s.n_outliers, s.delta, s.rmse, s.max_abs, s.passes
88 );
89 (b, j)
90 }
91 "tucker" => {
92 let (b, s) = cram_codec::tucker::encode_f32(&x, &dims, bound);
93 let j = format!(
94 "\"core_bytes\":{},\"factor_bytes\":{},\"ranks\":{:?},\"delta\":{},\"rmse\":{},\"max_abs\":{}",
95 s.core_bytes, s.factor_bytes, s.ranks, s.delta, s.rmse, s.max_abs
96 );
97 (b, j)
98 }
99 "auto" | "portfolio-all" => {
100 let mut cfg = wavcodec::WavConfig::new(bound);
101 if let Some(r) = rho {
102 cfg.rho = r;
103 }
104 cfg.model = cram_codec::learned::parse_model_arg(&model);
105 let (b, rep) =
106 cram_codec::encode_portfolio_f32(&x, &dims, &cfg, codec == "auto");
107 let tried: Vec<String> = rep
108 .tried
109 .iter()
110 .map(|(c, n, t)| format!("\"{}:{n}:{t:.3}\"", c.name()))
111 .collect();
112 (
113 b,
114 format!(
115 "\"chose\":\"{}\",\"probe_rank\":{},\"tried\":[{}]",
116 rep.pick.name(),
117 rep.probe_rank,
118 tried.join(",")
119 ),
120 )
121 }
122 "fast" => {
123 let mut cfg = wavcodec::WavConfig::new(bound);
124 cfg.model = cram_codec::learned::parse_model_arg(&model);
125 let (b, c) = cram_codec::encode_fast_f32(&x, &dims, &cfg);
126 (b, format!("\"chose\":\"{}\"", c.name()))
127 }
128 "qtt-probe" => {
129 let env = |k: &str, d: usize| {
130 std::env::var(k)
131 .ok()
132 .and_then(|v| v.parse().ok())
133 .unwrap_or(d)
134 };
135 let (n, r, t) = cram_codec::qtt_probe(
136 &x,
137 &dims,
138 bound,
139 env("PROBE_STRIDE", 2),
140 env("PROBE_CAP", 32),
141 );
142 (
143 vec![0u8; n],
144 format!("\"probe_bytes\":{n},\"probe_rank\":{r},\"probe_s\":{t}"),
145 )
146 }
147 "interp" | "lorenzo" | "qtt" | "qtt-sparse" => {
148 let cfg = wavcodec::WavConfig::new(bound);
149 let c = match codec.as_str() {
150 "qtt" => cram_codec::Candidate::Qtt,
151 "qtt-sparse" => cram_codec::Candidate::QttSparse,
152 "lorenzo" => cram_codec::Candidate::Lorenzo,
153 _ => cram_codec::Candidate::Interp,
154 };
155 let mut b = vec![c.tag()];
156 b.extend(cram_codec::encode_candidate_f32(c, &x, &dims, &cfg));
157 (b, format!("\"chose\":\"{codec}\""))
158 }
159 _ => usage(),
160 };
161 let enc = t.elapsed().as_secs_f64();
162 std::fs::write(&args[2], &bytes).unwrap();
163 println!(
164 "{{\"bytes\":{},\"bpv\":{},\"encode_s\":{enc},{json}}}",
165 bytes.len(),
166 8.0 * bytes.len() as f64 / x.len() as f64
167 );
168 }
169 Some("decode") if args.len() == 3 || (args.len() == 5 && args[3] == "--model") => {
170 if args.len() == 5 {
171 // registers a pretrained network so the decoder can resolve it
172 let _ = cram_codec::learned::parse_model_arg(&args[4]);
173 }
174 let bytes = std::fs::read(&args[1]).unwrap();
175 let t = Instant::now();
176 let Decoded::F32 { data, .. } = decode_any(&bytes).expect("decode") else {
177 panic!("not an f32 stream")
178 };
179 let dec = t.elapsed().as_secs_f64();
180 let out: Vec<u8> = data.iter().flat_map(|v| v.to_le_bytes()).collect();
181 std::fs::write(&args[2], out).unwrap();
182 println!("{{\"decode_s\":{dec}}}");
183 }
184 _ => usage(),
185 }
186}