From 85f0a187606d64716de7717a4c6371d712947a2b Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 18:47:05 +0900 Subject: [PATCH 1/8] use Box<[f64]> instead of Vec in vocoder --- src/vocoder/buffer.rs | 4 ++-- src/vocoder/cepstrum.rs | 16 ++++++++-------- src/vocoder/coefficients.rs | 12 ++++++------ src/vocoder/lsp.rs | 6 +++--- src/vocoder/mglsa.rs | 4 ++-- src/vocoder/mlsa.rs | 4 ++-- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/vocoder/buffer.rs b/src/vocoder/buffer.rs index 9be8632..34e5bc5 100644 --- a/src/vocoder/buffer.rs +++ b/src/vocoder/buffer.rs @@ -1,11 +1,11 @@ pub use std::ops::{Deref, DerefMut}; -pub trait Buffer: Deref> + DerefMut {} +pub trait Buffer: Deref + DerefMut {} macro_rules! deref_buffer { ($t:ty) => { impl Deref for $t { - type Target = Vec; + type Target = [f64]; fn deref(&self) -> &Self::Target { &self.buffer diff --git a/src/vocoder/cepstrum.rs b/src/vocoder/cepstrum.rs index efa0592..6f68553 100644 --- a/src/vocoder/cepstrum.rs +++ b/src/vocoder/cepstrum.rs @@ -6,7 +6,7 @@ use super::{ #[derive(Debug, Clone)] pub struct MelCepstrum { - pub(super) buffer: Vec, + pub(super) buffer: Box<[f64]>, pub(super) alpha: f64, } @@ -15,7 +15,7 @@ deref_buffer!(MelCepstrum); impl MelCepstrum { pub fn new(c: &[f64], alpha: f64) -> Self { Self { - buffer: c.to_vec(), + buffer: c.into(), alpha, } } @@ -50,7 +50,7 @@ impl CepstrumT for MelCepstrum { fn clone_with_size(&self, size: usize) -> Self { Self { - buffer: vec![0.0; size], + buffer: vec![0.0; size].into(), alpha: self.alpha, } } @@ -58,7 +58,7 @@ impl CepstrumT for MelCepstrum { #[derive(Debug, Clone)] pub struct MelGeneralizedCepstrum { - pub(super) buffer: Vec, + pub(super) buffer: Box<[f64]>, pub(super) alpha: f64, pub(super) gamma: f64, } @@ -68,7 +68,7 @@ deref_buffer!(MelGeneralizedCepstrum); impl MelGeneralizedCepstrum { fn gc2gc(&self, m2: usize, gamma: f64) -> Self { let mut cepstrum = Self { - buffer: vec![0.0; m2 + 1], + buffer: vec![0.0; m2 + 1].into(), alpha: self.alpha, gamma, }; @@ -116,7 +116,7 @@ impl CepstrumT for MelGeneralizedCepstrum { fn clone_with_size(&self, size: usize) -> Self { Self { - buffer: vec![0.0; size], + buffer: vec![0.0; size].into(), alpha: self.alpha, gamma: self.gamma, } @@ -172,8 +172,8 @@ pub trait CepstrumT: Buffer + Sized { cepstrum } - fn c2ir(&self, len: usize) -> Vec { - let mut ir = vec![0.0; len]; + fn c2ir(&self, len: usize) -> Box<[f64]> { + let mut ir = vec![0.0; len].into_boxed_slice(); ir[0] = self[0].exp(); for n in 1..len { let mut d = 0.0; diff --git a/src/vocoder/coefficients.rs b/src/vocoder/coefficients.rs index 22c130c..f0ba3cc 100644 --- a/src/vocoder/coefficients.rs +++ b/src/vocoder/coefficients.rs @@ -6,14 +6,14 @@ use super::{ #[derive(Debug, Clone)] pub struct Coefficients { - buffer: Vec, + buffer: Box<[f64]>, } deref_buffer!(Coefficients); impl Coefficients { pub fn new(c: &[f64]) -> Self { - Self { buffer: c.to_vec() } + Self { buffer: c.into() } } } @@ -22,7 +22,7 @@ impl CoefficientsT for Coefficients { fn to_cep(&self, alpha: f64) -> Self::Cep { Self::Cep { - buffer: vec![0.0; self.len()], + buffer: vec![0.0; self.len()].into(), alpha, } } @@ -30,7 +30,7 @@ impl CoefficientsT for Coefficients { #[derive(Debug, Clone)] pub struct GeneralizedCoefficients { - buffer: Vec, + buffer: Box<[f64]>, gamma: f64, } @@ -39,7 +39,7 @@ deref_buffer!(GeneralizedCoefficients); impl GeneralizedCoefficients { pub fn new(c: &[f64], gamma: f64) -> Self { Self { - buffer: c.to_vec(), + buffer: c.into(), gamma, } } @@ -50,7 +50,7 @@ impl CoefficientsT for GeneralizedCoefficients { fn to_cep(&self, alpha: f64) -> Self::Cep { Self::Cep { - buffer: vec![0.0; self.len()], + buffer: vec![0.0; self.len()].into(), alpha, gamma: self.gamma, } diff --git a/src/vocoder/lsp.rs b/src/vocoder/lsp.rs index 590233c..8d47c27 100644 --- a/src/vocoder/lsp.rs +++ b/src/vocoder/lsp.rs @@ -4,7 +4,7 @@ use super::{buffer::*, cepstrum::MelGeneralizedCepstrum, generalized::Generalize #[derive(Debug, Clone)] pub struct LineSpectralPairs { - buffer: Vec, + buffer: Box<[f64]>, alpha: f64, use_log_gain: bool, stage: usize, @@ -16,7 +16,7 @@ deref_buffer!(LineSpectralPairs); impl LineSpectralPairs { pub fn new(lsp: &[f64], alpha: f64, use_log_gain: bool, stage: usize, gamma: f64) -> Self { Self { - buffer: lsp.to_vec(), + buffer: lsp.into(), alpha, use_log_gain, stage, @@ -51,7 +51,7 @@ impl LineSpectralPairs { let mut xf = 0.0; let mut cepstrum = MelGeneralizedCepstrum { - buffer: vec![0.0; m + 1], + buffer: vec![0.0; m + 1].into(), alpha: self.alpha, gamma: self.gamma, }; diff --git a/src/vocoder/mglsa.rs b/src/vocoder/mglsa.rs index 67ed4ac..95e16f5 100644 --- a/src/vocoder/mglsa.rs +++ b/src/vocoder/mglsa.rs @@ -2,13 +2,13 @@ use super::coefficients::GeneralizedCoefficients; #[derive(Debug, Clone)] pub struct MelGeneralizedLogSpectrumApproximation { - d: Vec>, + d: Box<[Box<[f64]>]>, } impl MelGeneralizedLogSpectrumApproximation { pub fn new(n: usize, c_len: usize) -> Self { Self { - d: vec![vec![0.0; c_len]; n], + d: vec![vec![0.0; c_len].into(); n].into(), } } diff --git a/src/vocoder/mlsa.rs b/src/vocoder/mlsa.rs index e12f826..8426806 100644 --- a/src/vocoder/mlsa.rs +++ b/src/vocoder/mlsa.rs @@ -5,7 +5,7 @@ use super::coefficients::Coefficients; pub struct MelLogSpectrumApproximation { d11: [f64; N], d12: [f64; N], - d21: [Vec; N], + d21: [Box<[f64]>; N], d22: [f64; N], } @@ -39,7 +39,7 @@ where Self { d11: [0.0; N], d12: [0.0; N], - d21: std::array::from_fn(|_| vec![0.0; nmcp]), + d21: std::array::from_fn(|_| vec![0.0; nmcp].into()), d22: [0.0; N], } } From 649168e8b2cbbe769fa97aa82113dc682db7eb0c Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 18:59:00 +0900 Subject: [PATCH 2/8] use Box<[f64]> instead of Vec elsewhere --- src/engine.rs | 2 +- src/mlpg_adjust/mlpg.rs | 32 ++++++++++++++++---------------- src/mlpg_adjust/mod.rs | 6 ++++-- src/model/voice/window.rs | 6 ++++-- src/speech.rs | 2 +- 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index d089d0c..23a7ffd 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -353,7 +353,7 @@ impl Engine { ) .create(&durations) } else { - vec![vec![0.0; 0]; lf0.len()] + vec![vec![0.0; 0].into(); lf0.len()].into() }; Ok(SpeechGenerator::new( diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index 5b1d2fa..c4809fd 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -15,8 +15,8 @@ pub struct MlpgMatrix { win_size: usize, length: usize, width: usize, - wuw: Vec>, - wum: Vec, + wuw: Box<[Box<[f64]>]>, + wum: Box<[f64]>, } impl MlpgMatrix { @@ -29,7 +29,7 @@ impl MlpgMatrix { let mut wuw = Vec::with_capacity(length); for t in 0..length { - wuw.push(vec![0.0; width]); + wuw.push(vec![0.0; width].into_boxed_slice()); wum.push(0.0); for (i, window) in windows.iter().enumerate() { @@ -64,13 +64,13 @@ impl MlpgMatrix { win_size: windows.size(), length, width, - wuw, - wum, + wuw: wuw.into_boxed_slice(), + wum: wum.into_boxed_slice(), } } /// Solve equation $W^T U^{-1} W c = W^T U^{-1} \mu$ and return the vector $c$. - pub fn solve(&mut self) -> Vec { + pub fn solve(&mut self) -> Box<[f64]> { self.ldl_factorization(); self.substitutions() } @@ -92,7 +92,7 @@ impl MlpgMatrix { } /// Forward & backward substitution. - fn substitutions(&self) -> Vec { + fn substitutions(&self) -> Box<[f64]> { let mut g = vec![0.0; self.length]; // forward for t in 0..self.length { @@ -102,7 +102,7 @@ impl MlpgMatrix { } } - let mut par = vec![0.0; self.length]; + let mut par = vec![0.0; self.length].into_boxed_slice(); // backward for t in (0..self.length).rev() { par[t] = g[t] / self.wuw[t][0]; @@ -122,7 +122,7 @@ impl MlpgMatrix { gv_weight: f64, durations: &[usize], msd_flag: &Mask, - ) -> Vec { + ) -> Box<[f64]> { if let Some((gv_param, gv_switch)) = gv { let mtx_before = self.clone(); let par = self.solve(); @@ -145,7 +145,7 @@ impl MlpgMatrix { /// MLPG global variance (GV) calculator. #[derive(Debug, Clone)] pub struct MlpgGlobalVariance<'a> { - par: Vec, + par: Box<[f64]>, gv_switch: &'a [bool], gv_length: usize, @@ -154,7 +154,7 @@ pub struct MlpgGlobalVariance<'a> { impl<'a> MlpgGlobalVariance<'a> { /// Create a new GV structure. - pub fn new(mtx: MlpgMatrix, par: Vec, gv_switch: &'a [bool]) -> Self { + pub fn new(mtx: MlpgMatrix, par: Box<[f64]>, gv_switch: &'a [bool]) -> Self { let gv_length = gv_switch.iter().filter(|b| **b).count(); Self { par, @@ -165,7 +165,7 @@ impl<'a> MlpgGlobalVariance<'a> { } /// Apply GV to the current parameter and returns it. - pub fn apply_gv(mut self, gv_mean: f64, gv_vari: f64) -> Vec { + pub fn apply_gv(mut self, gv_mean: f64, gv_vari: f64) -> Box<[f64]> { self.parmgen(gv_mean, gv_vari); self.par } @@ -201,8 +201,8 @@ impl<'a> MlpgGlobalVariance<'a> { .filter(|(_, sw)| **sw) .for_each(|(p, _)| *p = ratio * (*p - mean) + mean); } - fn calc_hmmobj_derivative(&self) -> (f64, Vec) { - let mut g = vec![0.0; self.mtx.length]; + fn calc_hmmobj_derivative(&self) -> (f64, Box<[f64]>) { + let mut g = vec![0.0; self.mtx.length].into_boxed_slice(); #[allow(clippy::needless_range_loop)] for t in 0..self.mtx.length { @@ -229,7 +229,7 @@ impl<'a> MlpgGlobalVariance<'a> { } fn next_step( &mut self, - g: Vec, + g: &[f64], step: f64, mean: f64, vari: f64, @@ -285,7 +285,7 @@ impl<'a> MlpgGlobalVariance<'a> { } } - self.next_step(g, step, mean, vari, gv_mean, gv_vari); + self.next_step(&g, step, mean, vari, gv_mean, gv_vari); prev = obj; } diff --git a/src/mlpg_adjust/mod.rs b/src/mlpg_adjust/mod.rs index 017fe66..df74d5e 100644 --- a/src/mlpg_adjust/mod.rs +++ b/src/mlpg_adjust/mod.rs @@ -48,10 +48,12 @@ impl<'a> MlpgAdjust<'a> { } } /// Parameter generation using GV weight - pub fn create(&self, durations: &[usize]) -> Vec> { + pub fn create(&self, durations: &[usize]) -> Box<[Box<[f64]>]> { let msd_flag = Mask::create(&self.stream, self.msd_threshold, durations); let msd_boundaries = msd_flag.boundary_distances(); - let mut pars = vec![vec![0.0; self.vector_length]; msd_flag.mask().len()]; + let mut pars = + vec![vec![0.0; self.vector_length].into_boxed_slice(); msd_flag.mask().len()] + .into_boxed_slice(); for vector_index in 0..self.vector_length { let parameters: Vec> = self diff --git a/src/model/voice/window.rs b/src/model/voice/window.rs index 78af8d0..fff6cf8 100644 --- a/src/model/voice/window.rs +++ b/src/model/voice/window.rs @@ -23,12 +23,14 @@ impl Windows { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Window { - coefficients: Vec, + coefficients: Box<[f64]>, } impl Window { pub fn new(coefficients: Vec) -> Self { - Self { coefficients } + Self { + coefficients: coefficients.into(), + } } pub fn iter_rev(&self, start: usize) -> impl '_ + Iterator { diff --git a/src/speech.rs b/src/speech.rs index b7b13aa..bbf6dd5 100644 --- a/src/speech.rs +++ b/src/speech.rs @@ -2,7 +2,7 @@ use crate::vocoder::Vocoder; -type Parameter = Vec>; +type Parameter = Box<[Box<[f64]>]>; /// A structure that contains all parameters necessary to generate speech waveform. pub struct SpeechGenerator { From 3abc371260f209932fcdaf8de94cf05a029541eb Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 19:19:51 +0900 Subject: [PATCH 3/8] use boxed_slice![] --- src/engine.rs | 2 +- src/lib.rs | 6 ++++++ src/mlpg_adjust/mlpg.rs | 8 ++++---- src/mlpg_adjust/mod.rs | 4 +--- src/vocoder/cepstrum.rs | 10 +++++----- src/vocoder/coefficients.rs | 4 ++-- src/vocoder/lsp.rs | 2 +- src/vocoder/mglsa.rs | 2 +- src/vocoder/mlsa.rs | 2 +- 9 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 23a7ffd..ffca054 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -353,7 +353,7 @@ impl Engine { ) .create(&durations) } else { - vec![vec![0.0; 0].into(); lf0.len()].into() + boxed_slice![boxed_slice![0.0; 0]; lf0.len()] }; Ok(SpeechGenerator::new( diff --git a/src/lib.rs b/src/lib.rs index 89aec0e..c1799a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,12 @@ mod constants; +macro_rules! boxed_slice { + ($e:expr; $n:expr) => { + vec![$e; $n].into_boxed_slice() + }; +} + pub mod duration; pub mod engine; pub mod label; diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index c4809fd..e9e4173 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -29,7 +29,7 @@ impl MlpgMatrix { let mut wuw = Vec::with_capacity(length); for t in 0..length { - wuw.push(vec![0.0; width].into_boxed_slice()); + wuw.push(boxed_slice![0.0; width]); wum.push(0.0); for (i, window) in windows.iter().enumerate() { @@ -93,7 +93,7 @@ impl MlpgMatrix { /// Forward & backward substitution. fn substitutions(&self) -> Box<[f64]> { - let mut g = vec![0.0; self.length]; + let mut g = boxed_slice![0.0; self.length]; // forward for t in 0..self.length { g[t] = self.wum[t]; @@ -102,7 +102,7 @@ impl MlpgMatrix { } } - let mut par = vec![0.0; self.length].into_boxed_slice(); + let mut par = boxed_slice![0.0; self.length]; // backward for t in (0..self.length).rev() { par[t] = g[t] / self.wuw[t][0]; @@ -202,7 +202,7 @@ impl<'a> MlpgGlobalVariance<'a> { .for_each(|(p, _)| *p = ratio * (*p - mean) + mean); } fn calc_hmmobj_derivative(&self) -> (f64, Box<[f64]>) { - let mut g = vec![0.0; self.mtx.length].into_boxed_slice(); + let mut g = boxed_slice![0.0; self.mtx.length]; #[allow(clippy::needless_range_loop)] for t in 0..self.mtx.length { diff --git a/src/mlpg_adjust/mod.rs b/src/mlpg_adjust/mod.rs index df74d5e..7f0348f 100644 --- a/src/mlpg_adjust/mod.rs +++ b/src/mlpg_adjust/mod.rs @@ -51,9 +51,7 @@ impl<'a> MlpgAdjust<'a> { pub fn create(&self, durations: &[usize]) -> Box<[Box<[f64]>]> { let msd_flag = Mask::create(&self.stream, self.msd_threshold, durations); let msd_boundaries = msd_flag.boundary_distances(); - let mut pars = - vec![vec![0.0; self.vector_length].into_boxed_slice(); msd_flag.mask().len()] - .into_boxed_slice(); + let mut pars = boxed_slice![boxed_slice![0.0; self.vector_length]; msd_flag.mask().len()]; for vector_index in 0..self.vector_length { let parameters: Vec> = self diff --git a/src/vocoder/cepstrum.rs b/src/vocoder/cepstrum.rs index 6f68553..63933fe 100644 --- a/src/vocoder/cepstrum.rs +++ b/src/vocoder/cepstrum.rs @@ -50,7 +50,7 @@ impl CepstrumT for MelCepstrum { fn clone_with_size(&self, size: usize) -> Self { Self { - buffer: vec![0.0; size].into(), + buffer: boxed_slice![0.0; size], alpha: self.alpha, } } @@ -68,7 +68,7 @@ deref_buffer!(MelGeneralizedCepstrum); impl MelGeneralizedCepstrum { fn gc2gc(&self, m2: usize, gamma: f64) -> Self { let mut cepstrum = Self { - buffer: vec![0.0; m2 + 1].into(), + buffer: boxed_slice![0.0; m2 + 1], alpha: self.alpha, gamma, }; @@ -116,7 +116,7 @@ impl CepstrumT for MelGeneralizedCepstrum { fn clone_with_size(&self, size: usize) -> Self { Self { - buffer: vec![0.0; size].into(), + buffer: boxed_slice![0.0; size], alpha: self.alpha, gamma: self.gamma, } @@ -154,7 +154,7 @@ pub trait CepstrumT: Buffer + Sized { let aa = 1.0 - alpha * alpha; let mut cepstrum = self.clone_with_size(m2 + 1); - let mut f = vec![0.0; cepstrum.len()]; + let mut f = boxed_slice![0.0; cepstrum.len()]; for i in 0..self.len() { f[0] = cepstrum[0]; @@ -173,7 +173,7 @@ pub trait CepstrumT: Buffer + Sized { } fn c2ir(&self, len: usize) -> Box<[f64]> { - let mut ir = vec![0.0; len].into_boxed_slice(); + let mut ir = boxed_slice![0.0; len]; ir[0] = self[0].exp(); for n in 1..len { let mut d = 0.0; diff --git a/src/vocoder/coefficients.rs b/src/vocoder/coefficients.rs index f0ba3cc..8d51141 100644 --- a/src/vocoder/coefficients.rs +++ b/src/vocoder/coefficients.rs @@ -22,7 +22,7 @@ impl CoefficientsT for Coefficients { fn to_cep(&self, alpha: f64) -> Self::Cep { Self::Cep { - buffer: vec![0.0; self.len()].into(), + buffer: boxed_slice![0.0; self.len()], alpha, } } @@ -50,7 +50,7 @@ impl CoefficientsT for GeneralizedCoefficients { fn to_cep(&self, alpha: f64) -> Self::Cep { Self::Cep { - buffer: vec![0.0; self.len()].into(), + buffer: boxed_slice![0.0; self.len()], alpha, gamma: self.gamma, } diff --git a/src/vocoder/lsp.rs b/src/vocoder/lsp.rs index 8d47c27..85685ce 100644 --- a/src/vocoder/lsp.rs +++ b/src/vocoder/lsp.rs @@ -51,7 +51,7 @@ impl LineSpectralPairs { let mut xf = 0.0; let mut cepstrum = MelGeneralizedCepstrum { - buffer: vec![0.0; m + 1].into(), + buffer: boxed_slice![0.0; m + 1], alpha: self.alpha, gamma: self.gamma, }; diff --git a/src/vocoder/mglsa.rs b/src/vocoder/mglsa.rs index 95e16f5..981527c 100644 --- a/src/vocoder/mglsa.rs +++ b/src/vocoder/mglsa.rs @@ -8,7 +8,7 @@ pub struct MelGeneralizedLogSpectrumApproximation { impl MelGeneralizedLogSpectrumApproximation { pub fn new(n: usize, c_len: usize) -> Self { Self { - d: vec![vec![0.0; c_len].into(); n].into(), + d: boxed_slice![boxed_slice![0.0; c_len]; n], } } diff --git a/src/vocoder/mlsa.rs b/src/vocoder/mlsa.rs index 8426806..465ac45 100644 --- a/src/vocoder/mlsa.rs +++ b/src/vocoder/mlsa.rs @@ -39,7 +39,7 @@ where Self { d11: [0.0; N], d12: [0.0; N], - d21: std::array::from_fn(|_| vec![0.0; nmcp].into()), + d21: std::array::from_fn(|_| boxed_slice![0.0; nmcp]), d22: [0.0; N], } } From b67bdbf1dbb3061557950579d87fca01d393f423 Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 19:28:17 +0900 Subject: [PATCH 4/8] flatten wuw --- src/mlpg_adjust/mlpg.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index e9e4173..932f253 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -15,7 +15,7 @@ pub struct MlpgMatrix { win_size: usize, length: usize, width: usize, - wuw: Box<[Box<[f64]>]>, + wuw: Box<[f64]>, wum: Box<[f64]>, } @@ -25,13 +25,10 @@ impl MlpgMatrix { pub fn calc_wuw_and_wum(windows: &Windows, parameters: Vec>) -> Self { let length = parameters[0].len(); let width = windows.max_width() * 2 + 1; - let mut wum = Vec::with_capacity(length); - let mut wuw = Vec::with_capacity(length); + let mut wum = boxed_slice!(0.0; length); + let mut wuw = boxed_slice!(0.0; width * length); for t in 0..length { - wuw.push(boxed_slice![0.0; width]); - wum.push(0.0); - for (i, window) in windows.iter().enumerate() { for (index, coef) in window.iter_rev(0) { if coef == 0.0 { @@ -54,7 +51,7 @@ impl MlpgMatrix { break; } - wuw[t][j] += wu * coef; + wuw[width * t + j] += wu * coef; } } } @@ -64,8 +61,8 @@ impl MlpgMatrix { win_size: windows.size(), length, width, - wuw: wuw.into_boxed_slice(), - wum: wum.into_boxed_slice(), + wuw, + wum, } } @@ -79,14 +76,17 @@ impl MlpgMatrix { fn ldl_factorization(&mut self) { for t in 0..self.length { for i in 1..self.width.min(t + 1) { - self.wuw[t][0] -= self.wuw[t - i][i] * self.wuw[t - i][i] * self.wuw[t - i][0]; + self.wuw[self.width * t] -= self.wuw[self.width * (t - i) + i] + * self.wuw[self.width * (t - i) + i] + * self.wuw[self.width * (t - i)]; } for i in 1..self.width { for j in 1..(self.width - i).min(t + 1) { - self.wuw[t][i] -= - self.wuw[t - j][j] * self.wuw[t - j][i + j] * self.wuw[t - j][0]; + self.wuw[self.width * t + i] -= self.wuw[self.width * (t - j) + j] + * self.wuw[self.width * (t - j) + i + j] + * self.wuw[self.width * (t - j)]; } - self.wuw[t][i] /= self.wuw[t][0]; + self.wuw[self.width * t + i] /= self.wuw[self.width * t]; } } } @@ -98,16 +98,16 @@ impl MlpgMatrix { for t in 0..self.length { g[t] = self.wum[t]; for i in 1..self.width.min(t + 1) { - g[t] -= self.wuw[t - i][i] * g[t - i]; + g[t] -= self.wuw[self.width * (t - i) + i] * g[t - i]; } } let mut par = boxed_slice![0.0; self.length]; // backward for t in (0..self.length).rev() { - par[t] = g[t] / self.wuw[t][0]; + par[t] = g[t] / self.wuw[self.width * t]; for i in 1..self.width.min(self.length - t) { - par[t] -= self.wuw[t][i] * par[t + i]; + par[t] -= self.wuw[self.width * t + i] * par[t + i]; } } @@ -206,13 +206,13 @@ impl<'a> MlpgGlobalVariance<'a> { #[allow(clippy::needless_range_loop)] for t in 0..self.mtx.length { - g[t] = self.mtx.wuw[t][0] * self.par[t]; + g[t] = self.mtx.wuw[self.mtx.width * t] * self.par[t]; for i in 1..self.mtx.width { if t + i < self.mtx.length { - g[t] += self.mtx.wuw[t][i] * self.par[t + i]; + g[t] += self.mtx.wuw[self.mtx.width * t + i] * self.par[t + i]; } if t + 1 > i { - g[t] += self.mtx.wuw[t - i][i] * self.par[t - i]; + g[t] += self.mtx.wuw[self.mtx.width * (t - i) + i] * self.par[t - i]; } } } @@ -243,7 +243,7 @@ impl<'a> MlpgGlobalVariance<'a> { #[allow(clippy::needless_range_loop)] for t in 0..length { - let h = -W1 * w * self.mtx.wuw[t][0] + let h = -W1 * w * self.mtx.wuw[self.mtx.width * t] - W2 * 2.0 / (length * length) as f64 * ((length - 1) as f64 * gv_vari * (vari - gv_mean) + 2.0 * gv_vari * (self.par[t] - mean) * (self.par[t] - mean)); From 59fde010dbe8b32cdf2ea054aee04f0027169b5e Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 19:36:19 +0900 Subject: [PATCH 5/8] pre-index slices --- src/mlpg_adjust/mlpg.rs | 108 ++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index 932f253..7e587bf 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -74,40 +74,45 @@ impl MlpgMatrix { /// Perform Cholesky decomposition. fn ldl_factorization(&mut self) { - for t in 0..self.length { - for i in 1..self.width.min(t + 1) { - self.wuw[self.width * t] -= self.wuw[self.width * (t - i) + i] - * self.wuw[self.width * (t - i) + i] - * self.wuw[self.width * (t - i)]; + let Self { length, width, .. } = *self; + let wuw = &mut self.wuw[..width * length]; + + for t in 0..length { + for i in 1..width.min(t + 1) { + wuw[width * t] -= + wuw[width * (t - i) + i] * wuw[width * (t - i) + i] * wuw[width * (t - i)]; } - for i in 1..self.width { - for j in 1..(self.width - i).min(t + 1) { - self.wuw[self.width * t + i] -= self.wuw[self.width * (t - j) + j] - * self.wuw[self.width * (t - j) + i + j] - * self.wuw[self.width * (t - j)]; + for i in 1..width { + for j in 1..(width - i).min(t + 1) { + wuw[width * t + i] -= wuw[width * (t - j) + j] + * wuw[width * (t - j) + i + j] + * wuw[width * (t - j)]; } - self.wuw[self.width * t + i] /= self.wuw[self.width * t]; + wuw[width * t + i] /= wuw[width * t]; } } } /// Forward & backward substitution. fn substitutions(&self) -> Box<[f64]> { - let mut g = boxed_slice![0.0; self.length]; + let Self { length, width, .. } = *self; + let wuw = &self.wuw[..width * length]; + let wum = &self.wum[..length]; + let mut g = boxed_slice![0.0; length]; // forward - for t in 0..self.length { - g[t] = self.wum[t]; - for i in 1..self.width.min(t + 1) { - g[t] -= self.wuw[self.width * (t - i) + i] * g[t - i]; + for t in 0..length { + g[t] = wum[t]; + for i in 1..width.min(t + 1) { + g[t] -= wuw[width * (t - i) + i] * g[t - i]; } } - let mut par = boxed_slice![0.0; self.length]; + let mut par = boxed_slice![0.0; length]; // backward - for t in (0..self.length).rev() { - par[t] = g[t] / self.wuw[self.width * t]; - for i in 1..self.width.min(self.length - t) { - par[t] -= self.wuw[self.width * t + i] * par[t + i]; + for t in (0..length).rev() { + par[t] = g[t] / wuw[width * t]; + for i in 1..width.min(length - t) { + par[t] -= wuw[width * t + i] * par[t + i]; } } @@ -202,27 +207,34 @@ impl<'a> MlpgGlobalVariance<'a> { .for_each(|(p, _)| *p = ratio * (*p - mean) + mean); } fn calc_hmmobj_derivative(&self) -> (f64, Box<[f64]>) { - let mut g = boxed_slice![0.0; self.mtx.length]; - - #[allow(clippy::needless_range_loop)] - for t in 0..self.mtx.length { - g[t] = self.mtx.wuw[self.mtx.width * t] * self.par[t]; - for i in 1..self.mtx.width { - if t + i < self.mtx.length { - g[t] += self.mtx.wuw[self.mtx.width * t + i] * self.par[t + i]; + let MlpgMatrix { + win_size, + length, + width, + .. + } = self.mtx; + let wuw = &self.mtx.wuw[..width * length]; + let wum = &self.mtx.wum[..length]; + let par = &self.par[..length]; + let mut g = boxed_slice![0.0; length]; + + for t in 0..length { + g[t] = wuw[width * t] * par[t]; + for i in 1..width { + if t + i < length { + g[t] += wuw[width * t + i] * par[t + i]; } if t + 1 > i { - g[t] += self.mtx.wuw[self.mtx.width * (t - i) + i] * self.par[t - i]; + g[t] += wuw[width * (t - i) + i] * par[t - i]; } } } - let w = 1.0 / ((self.mtx.win_size * self.mtx.length) as f64); + let w = 1.0 / ((win_size * length) as f64); let mut hmmobj = 0.0; - #[allow(clippy::needless_range_loop)] - for t in 0..self.mtx.length { - hmmobj += W1 * w * self.par[t] * (self.mtx.wum[t] - 0.5 * g[t]); + for t in 0..length { + hmmobj += W1 * w * par[t] * (wum[t] - 0.5 * g[t]); } (hmmobj, g) @@ -236,24 +248,32 @@ impl<'a> MlpgGlobalVariance<'a> { gv_mean: f64, gv_vari: f64, ) { - let length = self.mtx.length; + let MlpgMatrix { + win_size, + length, + width, + .. + } = self.mtx; + let wuw = &self.mtx.wuw[..width * length]; + let wum = &self.mtx.wum[..length]; + let par = &mut self.par[..length]; + let gv_switch = &self.gv_switch[..length]; - let w = 1.0 / ((self.mtx.win_size * length) as f64); - let dv = -2.0 * gv_vari * (vari - gv_mean) / self.mtx.length as f64; + let w = 1.0 / ((win_size * length) as f64); + let dv = -2.0 * gv_vari * (vari - gv_mean) / length as f64; - #[allow(clippy::needless_range_loop)] for t in 0..length { - let h = -W1 * w * self.mtx.wuw[self.mtx.width * t] + let h = -W1 * w * wuw[width * t] - W2 * 2.0 / (length * length) as f64 * ((length - 1) as f64 * gv_vari * (vari - gv_mean) - + 2.0 * gv_vari * (self.par[t] - mean) * (self.par[t] - mean)); - let next_g = if self.gv_switch[t] { - 1.0 / h * (W1 * w * (-g[t] + self.mtx.wum[t]) + W2 * dv * (self.par[t] - mean)) + + 2.0 * gv_vari * (par[t] - mean) * (par[t] - mean)); + let next_g = if gv_switch[t] { + 1.0 / h * (W1 * w * (-g[t] + wum[t]) + W2 * dv * (par[t] - mean)) } else { - 1.0 / h * (W1 * w * (-g[t] + self.mtx.wum[t])) + 1.0 / h * (W1 * w * (-g[t] + wum[t])) }; - self.par[t] += step * next_g; + par[t] += step * next_g; } } From 7bf2682688bc6b8cc266eb43cbb86166a5f77690 Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Mon, 17 Nov 2025 16:36:44 +0900 Subject: [PATCH 6/8] mean_quad - mean^2 --- src/lib.rs | 2 +- src/mlpg_adjust/mlpg.rs | 27 +++++++++++---------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1799a6..f7850bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,7 +133,7 @@ mod tests { assert_eq!(speech.len(), 100800); approx::assert_abs_diff_eq!(speech[2000], 17.15977345625943, epsilon = 1.0e-10); - approx::assert_abs_diff_eq!(speech[30000], 2566.2058730889985, epsilon = 1.0e-10); + approx::assert_abs_diff_eq!(speech[30000], 2566.205873089253, epsilon = 1.0e-10); approx::assert_abs_diff_eq!(speech[70000], -1898.2890228814217, epsilon = 1.0e-10); approx::assert_abs_diff_eq!(speech[100799], -13.514971382534956, epsilon = 1.0e-10); } diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index 7e587bf..ff2ac5c 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -176,23 +176,18 @@ impl<'a> MlpgGlobalVariance<'a> { } fn calc_gv(&self) -> (f64, f64) { - let mean = self - .par - .iter() - .zip(self.gv_switch.iter()) - .filter(|(_, sw)| **sw) - .map(|(p, _)| *p) - .sum::() - / self.gv_length as f64; - let vari = self - .par - .iter() - .zip(self.gv_switch.iter()) - .filter(|(_, sw)| **sw) - .map(|(p, _)| (*p - mean) * (*p - mean)) - .sum::() - / self.gv_length as f64; + let mut sum = 0.0; + let mut sum_quad = 0.0; + + for (par, sw) in std::iter::zip(&self.par, self.gv_switch) { + if *sw { + sum += *par; + sum_quad += *par * *par; + } + } + let mean = sum / self.gv_length as f64; + let vari = (sum_quad / self.gv_length as f64) - (mean * mean); (mean, vari) } From ec613e72555d724b0b20dc1d4203f41fb062ef13 Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 20:00:04 +0900 Subject: [PATCH 7/8] optimize calc_hmmobj_derivative https://github.com/jpreprocess/jbonsai/pull/116/files/1a6db34bfefa2a0432869f429903d661c75c8e34..4becea0dfe02546c6881efc5eb897063c1086d12 --- src/mlpg_adjust/mlpg.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index ff2ac5c..e621604 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -208,19 +208,19 @@ impl<'a> MlpgGlobalVariance<'a> { width, .. } = self.mtx; - let wuw = &self.mtx.wuw[..width * length]; + assert!(width >= 1); // required for `wuw[0]` access + let wuw = self.mtx.wuw.chunks_exact(width); let wum = &self.mtx.wum[..length]; let par = &self.par[..length]; let mut g = boxed_slice![0.0; length]; - for t in 0..length { - g[t] = wuw[width * t] * par[t]; + // .zip(0..length) to help optimizer recognize t < length + for (wuw, t) in wuw.zip(0..length) { + g[t] += wuw[0] * par[t]; for i in 1..width { if t + i < length { - g[t] += wuw[width * t + i] * par[t + i]; - } - if t + 1 > i { - g[t] += wuw[width * (t - i) + i] * par[t - i]; + g[t] += wuw[i] * par[t + i]; + g[t + i] += wuw[i] * par[t]; } } } From d101dfdcc4f859d1bbe27bfd7070a7a623629acc Mon Sep 17 00:00:00 2001 From: cm-ayf Date: Sat, 29 Nov 2025 20:11:36 +0900 Subject: [PATCH 8/8] optimize calc_wuw_and_wum https://github.com/jpreprocess/jbonsai/pull/116/files/2387e399ab2ed7e3099702f4bd293b2eb895a327..cca257c656fc21e5cd6a7688cb172741e35e3c14 --- src/lib.rs | 4 ++-- src/mlpg_adjust/mlpg.rs | 28 +++++++++-------------- src/mlpg_adjust/mod.rs | 5 +++-- src/model/voice/window.rs | 47 +++++++++++++++++++++------------------ 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f7850bf..a0d56fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,7 +93,7 @@ mod tests { assert_eq!(speech.len(), 74880); approx::assert_abs_diff_eq!(speech[2000], 2.3158134981607754e-5, epsilon = 1.0e-10); - approx::assert_abs_diff_eq!(speech[30000], 6459.375032316974, epsilon = 1.0e-10); + approx::assert_abs_diff_eq!(speech[30000], 6459.375032318177, epsilon = 1.0e-10); } // これ,名詞,代名詞,一般,*,*,*,これ,コレ,コレ,0/2,C3,-1 @@ -133,7 +133,7 @@ mod tests { assert_eq!(speech.len(), 100800); approx::assert_abs_diff_eq!(speech[2000], 17.15977345625943, epsilon = 1.0e-10); - approx::assert_abs_diff_eq!(speech[30000], 2566.205873089253, epsilon = 1.0e-10); + approx::assert_abs_diff_eq!(speech[30000], 2566.205873089126, epsilon = 1.0e-10); approx::assert_abs_diff_eq!(speech[70000], -1898.2890228814217, epsilon = 1.0e-10); approx::assert_abs_diff_eq!(speech[100799], -13.514971382534956, epsilon = 1.0e-10); } diff --git a/src/mlpg_adjust/mlpg.rs b/src/mlpg_adjust/mlpg.rs index e621604..3d4e322 100644 --- a/src/mlpg_adjust/mlpg.rs +++ b/src/mlpg_adjust/mlpg.rs @@ -28,35 +28,29 @@ impl MlpgMatrix { let mut wum = boxed_slice!(0.0; length); let mut wuw = boxed_slice!(0.0; width * length); - for t in 0..length { - for (i, window) in windows.iter().enumerate() { - for (index, coef) in window.iter_rev(0) { + for (window, parameter) in std::iter::zip(windows, ¶meters) { + let parameter = ¶meter[..length]; + for t in 0..length { + for (index, coef) in window.iter(window.left_width()) { if coef == 0.0 { continue; } - - let idx = (t as isize) - index.position(); + let idx = (t as isize) - index; if idx < 0 || idx >= length as isize { continue; } - let wu = coef * parameters[i][idx as usize].1; - wum[t] += wu * parameters[i][idx as usize].0; - - for (inner_index, coef) in window.iter_rev(index.index()) { - if coef == 0.0 { + let MeanVari(mean, vari) = parameter[idx as usize]; + wum[t] += coef * vari * mean; + for (inner_index, inner_coef) in window.iter(index) { + if inner_coef == 0.0 { continue; } - let j = inner_index.index() - index.index(); - if t + j >= length { - break; - } - - wuw[width * t + j] += wu * coef; + let j = (inner_index - index) as usize; + wuw[t * width + j] += coef * inner_coef * vari; } } } } - Self { win_size: windows.size(), length, diff --git a/src/mlpg_adjust/mod.rs b/src/mlpg_adjust/mod.rs index 7f0348f..384c010 100644 --- a/src/mlpg_adjust/mod.rs +++ b/src/mlpg_adjust/mod.rs @@ -67,8 +67,9 @@ impl<'a> MlpgAdjust<'a> { .duration(durations) .zip(&msd_boundaries) .map(|(mean_ivar, (left, right))| { - let is_left_msd_boundary = *left < window.left_width(); - let is_right_msd_boundary = *right < window.right_width(); + // TODO: migrate msd_boundaries to isize + let is_left_msd_boundary = *left < (-window.left_width()) as usize; + let is_right_msd_boundary = *right < window.right_width() as usize; // If the window includes non-msd frames, set the ivar to 0.0 if (is_left_msd_boundary || is_right_msd_boundary) && window_index != 0 diff --git a/src/model/voice/window.rs b/src/model/voice/window.rs index fff6cf8..5d02adc 100644 --- a/src/model/voice/window.rs +++ b/src/model/voice/window.rs @@ -11,7 +11,7 @@ impl Windows { } pub fn iter(&self) -> impl '_ + Iterator { - self.windows.iter() + self.into_iter() } pub fn size(&self) -> usize { self.windows.len() @@ -21,6 +21,15 @@ impl Windows { } } +impl<'a> IntoIterator for &'a Windows { + type Item = &'a Window; + type IntoIter = std::slice::Iter<'a, Window>; + + fn into_iter(self) -> Self::IntoIter { + self.windows.iter() + } +} + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Window { coefficients: Box<[f64]>, @@ -33,14 +42,12 @@ impl Window { } } - pub fn iter_rev(&self, start: usize) -> impl '_ + Iterator { - let width = self.width(); - self.coefficients[start..] + #[inline(always)] + pub fn iter(&self, start: isize) -> impl '_ + Iterator { + self.coefficients[(start - self.left_width()) as usize..] .iter() .enumerate() - .rev() - .zip(std::iter::repeat((start, width))) - .map(|((idx, coef), (start, width))| (WindowIndex::new(start + idx, width), *coef)) + .map(move |(idx, coef)| (idx as isize + start, *coef)) } #[inline] @@ -48,12 +55,12 @@ impl Window { self.coefficients.len() } #[inline] - pub fn left_width(&self) -> usize { - self.width() / 2 + pub fn left_width(&self) -> isize { + -(self.width() as isize / 2) } #[inline] - pub fn right_width(&self) -> usize { - self.width() - self.left_width() - 1 + pub fn right_width(&self) -> isize { + self.width() as isize + self.left_width() - 1 } } @@ -94,25 +101,21 @@ mod tests { fn width_3() { let window = Window::new(vec![-1.0, 0.0, 1.0]); assert_eq!(window.width(), 3); - assert_eq!(window.left_width(), 1); + assert_eq!(window.left_width(), -1); assert_eq!(window.right_width(), 1); } #[test] fn iterator() { let window = Window::new(vec![-1.0, 0.0, 1.0]); - let iterated = window.iter_rev(0).collect::>(); + let iterated = window.iter(window.left_width()).collect::>(); - assert_eq!(iterated[2].1, -1.0); + assert_eq!(iterated[0].1, -1.0); assert_eq!(iterated[1].1, 0.0); - assert_eq!(iterated[0].1, 1.0); - - assert_eq!(iterated[2].0.index(), 0); - assert_eq!(iterated[1].0.index(), 1); - assert_eq!(iterated[0].0.index(), 2); + assert_eq!(iterated[2].1, 1.0); - assert_eq!(iterated[2].0.position(), -1); - assert_eq!(iterated[1].0.position(), 0); - assert_eq!(iterated[0].0.position(), 1); + assert_eq!(iterated[0].0, -1); + assert_eq!(iterated[1].0, 0); + assert_eq!(iterated[2].0, 1); } }