use crate::codec::compressed::fenwick::context_switching::FenwickModel;
use crate::codec::compressed::fenwick::Weights;
use crate::{AbsoluteT, DeltaT, EventCoordless, Intensity, D, D_SHIFT};
use arithmetic_coding_adder_dep::Encoder;
use bitstream_io::{BigEndian, BitWrite, BitWriter};
pub struct Contexts {
pub(crate) d_context: usize,
pub(crate) t_context: usize,
t_residual_max: i64,
pub(crate) eof_context: usize,
pub(crate) bitshift_context: usize,
}
pub const D_RESIDUAL_OFFSET: i16 = 255;
pub const BITSHIFT_ENCODE_FULL: u8 = 15;
impl Contexts {
pub fn new(source_model: &mut FenwickModel, dt_ref: DeltaT) -> Self {
let d_context = source_model.push_context_with_weights(d_residual_default_weights());
let t_weights = t_residual_default_weights(dt_ref);
let t_residual_max = (t_weights.len() as i64 - 2) / 2;
let t_context = source_model.push_context_with_weights(t_weights);
let eof_context = source_model.push_context_with_weights(Weights::new_with_counts(1, &[1]));
let bitshift_context =
source_model.push_context_with_weights(Weights::new_with_counts(16, &[1; 16]));
Self {
d_context,
t_context,
t_residual_max,
eof_context,
bitshift_context,
}
}
pub(crate) fn residual_to_bitshift(&self, t_residual_i64: i64) -> (u8, i64) {
if t_residual_i64.abs() < self.t_residual_max {
(0, t_residual_i64)
} else {
(BITSHIFT_ENCODE_FULL, t_residual_i64)
}
}
fn event_to_intensity(&self, d: D, delta_t: DeltaT, dt_ref: DeltaT) -> f64 {
let intensity = match d as usize {
a if a >= D_SHIFT.len() => f64::from(0),
_ => match delta_t {
0 => D_SHIFT[d as usize] as Intensity, _ => D_SHIFT[d as usize] as Intensity / f64::from(delta_t),
},
};
intensity * dt_ref as f64
}
pub(crate) fn residual_to_bitshift2(
&self,
t_prediction: i64,
t_residual_i64: i64,
event: &mut EventCoordless,
prev_event: &EventCoordless,
dt_ref: DeltaT,
c_thresh_max: f64,
) -> (u8, i64) {
if t_residual_i64.abs() < self.t_residual_max {
(0, t_residual_i64)
} else {
if event.t < prev_event.t {
}
let actual_dt = event.t.saturating_sub(prev_event.t);
let actual_intensity = self.event_to_intensity(event.d, actual_dt, dt_ref);
let mut recon_intensity = actual_intensity;
let mut bitshift: u8 = 0;
let mut t_residual = t_residual_i64.abs();
loop {
if t_residual > self.t_residual_max
&& actual_intensity - c_thresh_max < recon_intensity
&& actual_intensity + c_thresh_max > recon_intensity
{
t_residual >>= 1;
bitshift += 1;
let recon_predicted_t = (t_prediction + t_residual) as AbsoluteT;
if recon_predicted_t < prev_event.t {
break;
}
let recon_predicted_dt = recon_predicted_t - prev_event.t;
recon_intensity = self.event_to_intensity(event.d, recon_predicted_dt, dt_ref);
} else {
break;
}
}
bitshift = bitshift.saturating_sub(1);
t_residual = t_residual_i64.abs() >> bitshift;
if t_residual.abs() < self.t_residual_max {
if t_residual_i64 < 0 {
(bitshift, -t_residual)
} else {
(bitshift, t_residual)
}
} else {
(BITSHIFT_ENCODE_FULL, t_residual_i64)
}
}
}
}
pub fn t_residual_default_weights(_dt_ref: DeltaT) -> Weights {
let mut counts: Vec<u64> = vec![1; u8::MAX as usize + 1];
counts[0] = 100;
for item in counts.iter_mut().take(10) {
*item = 10;
}
Weights::new_with_counts(counts.len(), &counts)
}
pub fn d_residual_default_weights() -> Weights {
let mut counts: [u64; 513] = [1; 513];
let mut idx = 0;
loop {
match idx {
245..=265 => {
counts[idx] = 20;
}
235..=275 | 490..=510 | 0..=20 => {
counts[idx] = 10;
}
511 => {
counts[idx] = 20;
}
512 => {
counts[idx] = 10;
}
_ => {}
}
if idx == counts.len() - 1 {
break;
}
idx += 1;
}
Weights::new_with_counts(counts.len(), &Vec::from(counts))
}
pub fn eof_context(
contexts: &Contexts,
encoder: &mut Encoder<FenwickModel, BitWriter<Vec<u8>, BigEndian>>,
stream: &mut BitWriter<Vec<u8>, BigEndian>,
) {
let eof_context = contexts.eof_context;
encoder.model.set_context(eof_context);
encoder.encode(None, stream).unwrap();
encoder.flush(stream).unwrap();
stream.byte_align().unwrap();
stream.flush().unwrap();
}