diff --git a/poulpy-core/src/external_product/gglwe_atk.rs b/poulpy-core/src/external_product/gglwe_atk.rs index 0eba897..871eab8 100644 --- a/poulpy-core/src/external_product/gglwe_atk.rs +++ b/poulpy-core/src/external_product/gglwe_atk.rs @@ -1,82 +1,46 @@ -use poulpy_hal::{ - api::{ - ScratchAvailable, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, - }, - layouts::{Backend, DataMut, DataRef, Module, Scratch}, +use poulpy_hal::layouts::{Backend, DataMut, Scratch}; + +use crate::{ + ScratchTakeCore, + external_product::gglwe_ksk::GGLWEExternalProduct, + layouts::{AutomorphismKey, AutomorphismKeyToRef, GGLWEInfos, GGSWInfos, prepared::GGSWPreparedToRef}, }; -use crate::layouts::{AutomorphismKey, GGLWEInfos, GGSWInfos, GLWESwitchingKey, prepared::GGSWPrepared}; - impl AutomorphismKey> { - pub fn external_product_scratch_space( - module: &Module, - out_infos: &OUT, - in_infos: &IN, - ggsw_infos: &GGSW, + pub fn external_product_tmp_bytes( + &self, + module: &M, + res_infos: &R, + a_infos: &A, + b_infos: &B, ) -> usize where - OUT: GGLWEInfos, - IN: GGLWEInfos, - GGSW: GGSWInfos, - Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, + M: GGLWEExternalProduct, { - GLWESwitchingKey::external_product_scratch_space(module, out_infos, in_infos, ggsw_infos) - } - - pub fn external_product_inplace_scratch_space( - module: &Module, - out_infos: &OUT, - ggsw_infos: &GGSW, - ) -> usize - where - OUT: GGLWEInfos, - GGSW: GGSWInfos, - Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, - { - GLWESwitchingKey::external_product_inplace_scratch_space(module, out_infos, ggsw_infos) + module.gglwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) } } impl AutomorphismKey { - pub fn external_product( - &mut self, - module: &Module, - lhs: &AutomorphismKey, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) where - Module: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: ScratchAvailable, + pub fn external_product(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch) + where + M: GGLWEExternalProduct, + A: AutomorphismKeyToRef, + B: GGSWPreparedToRef, + Scratch: ScratchTakeCore, { - self.key.external_product(module, &lhs.key, rhs, scratch); + module.gglwe_external_product(&mut self.key.key, &a.to_ref().key.key, b, scratch); } - pub fn external_product_inplace( - &mut self, - module: &Module, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) where - Module: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: ScratchAvailable, + pub fn external_product_inplace(&mut self, module: &M, a: &A, scratch: &mut Scratch) + where + M: GGLWEExternalProduct, + A: GGSWPreparedToRef, + Scratch: ScratchTakeCore, { - self.key.external_product_inplace(module, rhs, scratch); + module.gglwe_external_product_inplace(&mut self.key.key, a, scratch); } } diff --git a/poulpy-core/src/external_product/gglwe_ksk.rs b/poulpy-core/src/external_product/gglwe_ksk.rs index c9b7299..b7bd4af 100644 --- a/poulpy-core/src/external_product/gglwe_ksk.rs +++ b/poulpy-core/src/external_product/gglwe_ksk.rs @@ -1,143 +1,134 @@ -use poulpy_hal::{ - api::{ - ScratchAvailable, VecZnxBigNormalize, VecZnxDftApply, VecZnxDftBytesOf, VecZnxIdftApplyConsume, VecZnxNormalize, - VecZnxNormalizeTmpBytes, VmpApplyDftToDft, VmpApplyDftToDftAdd, VmpApplyDftToDftTmpBytes, +use poulpy_hal::layouts::{Backend, DataMut, Module, Scratch, ZnxZero}; + +use crate::{ + GLWEExternalProduct, ScratchTakeCore, + layouts::{ + GGLWE, GGLWEInfos, GGLWEToMut, GGLWEToRef, GGSWInfos, GLWEInfos, GLWESwitchingKey, GLWESwitchingKeyToRef, + prepared::{GGSWPrepared, GGSWPreparedToRef}, }, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, }; -use crate::layouts::{GGLWEInfos, GGSWInfos, GLWE, GLWESwitchingKey, prepared::GGSWPrepared}; - -impl GLWESwitchingKey> { - pub fn external_product_scratch_space( - module: &Module, - out_infos: &OUT, - in_infos: &IN, - ggsw_infos: &GGSW, - ) -> usize +pub trait GGLWEExternalProduct +where + Self: GLWEExternalProduct, +{ + fn gglwe_external_product_tmp_bytes(&self, res_infos: &R, a_infos: &A, b_infos: &B) -> usize where - OUT: GGLWEInfos, - IN: GGLWEInfos, - GGSW: GGSWInfos, - Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, { - GLWE::external_product_scratch_space( - module, - &out_infos.glwe_layout(), - &in_infos.glwe_layout(), - ggsw_infos, - ) + self.glwe_external_product_scratch_space(res_infos, a_infos, b_infos) } - pub fn external_product_inplace_scratch_space( - module: &Module, - out_infos: &OUT, - ggsw_infos: &GGSW, + fn gglwe_external_product(&self, res: &mut R, a: &A, b: &B, scratch: &mut Scratch) + where + R: GGLWEToMut, + A: GGLWEToRef, + B: GGSWPreparedToRef, + Scratch: ScratchTakeCore, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGLWE<&[u8]> = &a.to_ref(); + let b: &GGSWPrepared<&[u8], BE> = &b.to_ref(); + + assert_eq!( + res.rank_in(), + a.rank_in(), + "res input rank_in: {} != a input rank_in: {}", + res.rank_in(), + a.rank_in() + ); + assert_eq!( + a.rank_out(), + b.rank(), + "a output rank_out: {} != b rank: {}", + a.rank_out(), + b.rank() + ); + assert_eq!( + res.rank_out(), + b.rank(), + "res output rank_out: {} != b rank: {}", + res.rank_out(), + b.rank() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_external_product(&mut res.at_mut(row, col), &a.at(row, col), b, scratch); + } + } + + for row in res.dnum().min(a.dnum()).into()..res.dnum().into() { + for col in 0..res.rank_in().into() { + res.at_mut(row, col).data_mut().zero(); + } + } + } + + fn gglwe_external_product_inplace(&self, res: &mut R, a: &A, scratch: &mut Scratch) + where + R: GGLWEToMut, + A: GGSWPreparedToRef, + Scratch: ScratchTakeCore, + { + let res: &mut GGLWE<&mut [u8]> = &mut res.to_mut(); + let a: &GGSWPrepared<&[u8], BE> = &a.to_ref(); + + assert_eq!( + res.rank_out(), + a.rank(), + "res output rank: {} != a rank: {}", + res.rank_out(), + a.rank() + ); + + for row in 0..res.dnum().into() { + for col in 0..res.rank_in().into() { + self.glwe_external_product_inplace(&mut res.at_mut(row, col), a, scratch); + } + } + } +} + +impl GGLWEExternalProduct for Module where Self: GLWEExternalProduct {} + +impl GLWESwitchingKey> { + pub fn external_product_tmp_bytes( + &self, + module: &M, + res_infos: &R, + a_infos: &A, + b_infos: &B, ) -> usize where - OUT: GGLWEInfos, - GGSW: GGSWInfos, - Module: VecZnxDftBytesOf + VmpApplyDftToDftTmpBytes + VecZnxNormalizeTmpBytes, + R: GGLWEInfos, + A: GGLWEInfos, + B: GGSWInfos, + M: GGLWEExternalProduct, { - GLWE::external_product_inplace_scratch_space(module, &out_infos.glwe_layout(), ggsw_infos) + module.gglwe_external_product_tmp_bytes(res_infos, a_infos, b_infos) } } impl GLWESwitchingKey { - pub fn external_product( - &mut self, - module: &Module, - lhs: &GLWESwitchingKey, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) where - Module: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: ScratchAvailable, + pub fn external_product(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch) + where + M: GGLWEExternalProduct, + A: GLWESwitchingKeyToRef, + B: GGSWPreparedToRef, + Scratch: ScratchTakeCore, { - #[cfg(debug_assertions)] - { - use crate::layouts::GLWEInfos; - - assert_eq!( - self.rank_in(), - lhs.rank_in(), - "ksk_out input rank: {} != ksk_in input rank: {}", - self.rank_in(), - lhs.rank_in() - ); - assert_eq!( - lhs.rank_out(), - rhs.rank(), - "ksk_in output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - assert_eq!( - self.rank_out(), - rhs.rank(), - "ksk_out output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product(module, &lhs.at(row_j, col_i), rhs, scratch); - }); - }); - - (self.dnum().min(lhs.dnum()).into()..self.dnum().into()).for_each(|row_i| { - (0..self.rank_in().into()).for_each(|col_j| { - self.at_mut(row_i, col_j).data.zero(); - }); - }); + module.gglwe_external_product(&mut self.key, &a.to_ref().key, b, scratch); } - pub fn external_product_inplace( - &mut self, - module: &Module, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) where - Module: VecZnxDftBytesOf - + VmpApplyDftToDftTmpBytes - + VecZnxNormalizeTmpBytes - + VecZnxDftApply - + VmpApplyDftToDft - + VmpApplyDftToDftAdd - + VecZnxIdftApplyConsume - + VecZnxBigNormalize - + VecZnxNormalize, - Scratch: ScratchAvailable, + pub fn external_product_inplace(&mut self, module: &M, a: &A, scratch: &mut Scratch) + where + M: GGLWEExternalProduct, + A: GGSWPreparedToRef, + Scratch: ScratchTakeCore, { - #[cfg(debug_assertions)] - { - use crate::layouts::GLWEInfos; - - assert_eq!( - self.rank_out(), - rhs.rank(), - "ksk_out output rank: {} != ggsw rank: {}", - self.rank_out(), - rhs.rank() - ); - } - - (0..self.rank_in().into()).for_each(|col_i| { - (0..self.dnum().into()).for_each(|row_j| { - self.at_mut(row_j, col_i) - .external_product_inplace(module, rhs, scratch); - }); - }); + module.gglwe_external_product_inplace(&mut self.key, a, scratch); } } diff --git a/poulpy-core/src/external_product/ggsw_ct.rs b/poulpy-core/src/external_product/ggsw_ct.rs index 5257a49..0b38ebf 100644 --- a/poulpy-core/src/external_product/ggsw_ct.rs +++ b/poulpy-core/src/external_product/ggsw_ct.rs @@ -1,6 +1,6 @@ use poulpy_hal::{ api::ScratchAvailable, - layouts::{Backend, DataMut, DataRef, Module, Scratch, ZnxZero}, + layouts::{Backend, DataMut, Module, Scratch, ZnxZero}, }; use crate::{ @@ -115,20 +115,22 @@ impl GGSW> { } impl GGSW { - pub fn external_product( - &mut self, - module: &Module, - lhs: &GGSW, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) { + pub fn external_product(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch) + where + M: GGSWExternalProduct, + A: GGSWToRef, + B: GGSWPreparedToRef, + Scratch: ScratchTakeCore, + { + module.ggsw_external_product(self, a, b, scratch); } - pub fn external_product_inplace( - &mut self, - module: &Module, - rhs: &GGSWPrepared, - scratch: &mut Scratch, - ) { + pub fn external_product_inplace(&mut self, module: &M, a: &A, scratch: &mut Scratch) + where + M: GGSWExternalProduct, + A: GGSWPreparedToRef, + Scratch: ScratchTakeCore, + { + module.ggsw_external_product_inplace(self, a, scratch); } } diff --git a/poulpy-core/src/external_product/glwe_ct.rs b/poulpy-core/src/external_product/glwe_ct.rs index 06de868..4abac52 100644 --- a/poulpy-core/src/external_product/glwe_ct.rs +++ b/poulpy-core/src/external_product/glwe_ct.rs @@ -15,35 +15,30 @@ use crate::{ }; impl GLWE { - pub fn external_product_scratch_space( - module: Module, - res_infos: &R, - a_infos: &A, - b_infos: &B, - ) -> usize + pub fn external_product_scratch_space(module: &M, res_infos: &R, a_infos: &A, b_infos: &B) -> usize where R: GLWEInfos, A: GLWEInfos, B: GGSWInfos, - Module: GLWEExternalProduct, + M: GLWEExternalProduct, { module.glwe_external_product_scratch_space(res_infos, a_infos, b_infos) } - pub fn external_product(&mut self, module: &Module, a: &A, b: &B, scratch: &mut Scratch) + pub fn external_product(&mut self, module: &M, a: &A, b: &B, scratch: &mut Scratch) where A: GLWEToRef, B: GGSWPreparedToRef, - Module: GLWEExternalProduct, + M: GLWEExternalProduct, Scratch: ScratchTakeCore, { module.glwe_external_product(self, a, b, scratch); } - pub fn external_product_inplace(&mut self, module: &Module, a: &A, scratch: &mut Scratch) + pub fn external_product_inplace(&mut self, module: &M, a: &A, scratch: &mut Scratch) where A: GGSWPreparedToRef, - Module: GLWEExternalProduct, + M: GLWEExternalProduct, Scratch: ScratchTakeCore, { module.glwe_external_product_inplace(self, a, scratch); diff --git a/poulpy-core/src/layouts/compressed/gglwe_atk.rs b/poulpy-core/src/layouts/compressed/gglwe_atk.rs index 5b675a5..629e3f3 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_atk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_atk.rs @@ -161,14 +161,7 @@ impl AutomorphismKeyCompressed> { module.bytes_of_automorphism_key_compressed_from_infos(infos) } - pub fn bytes_of( - module: &M, - base2k: Base2K, - k: TorusPrecision, - rank: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize + pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where M: AutomorphismKeyCompressedAlloc, { diff --git a/poulpy-core/src/layouts/compressed/gglwe_ct.rs b/poulpy-core/src/layouts/compressed/gglwe_ct.rs index 4accd8f..f54f759 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_ct.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_ct.rs @@ -217,14 +217,7 @@ impl GGLWECompressed> { module.bytes_of_gglwe_compressed_from_infos(infos) } - pub fn byte_of( - module: &M, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize + pub fn byte_of(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize where M: GGLWECompressedAlloc, { diff --git a/poulpy-core/src/layouts/compressed/gglwe_ksk.rs b/poulpy-core/src/layouts/compressed/gglwe_ksk.rs index 53f57e2..f59587b 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_ksk.rs @@ -166,14 +166,7 @@ impl GLWESwitchingKeyCompressed> { module.bytes_of_glwe_switching_key_compressed_from_infos(infos) } - pub fn bytes_of( - module: &M, - base2k: Base2K, - k: TorusPrecision, - rank_in: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize + pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, dnum: Dnum, dsize: Dsize) -> usize where M: GLWESwitchingKeyCompressedAlloc, { diff --git a/poulpy-core/src/layouts/compressed/gglwe_tsk.rs b/poulpy-core/src/layouts/compressed/gglwe_tsk.rs index 173d065..7c20bba 100644 --- a/poulpy-core/src/layouts/compressed/gglwe_tsk.rs +++ b/poulpy-core/src/layouts/compressed/gglwe_tsk.rs @@ -163,14 +163,7 @@ impl TensorKeyCompressed> { module.bytes_of_tensor_key_compressed_from_infos(infos) } - pub fn bytes_of( - module: &M, - base2k: Base2K, - k: TorusPrecision, - rank: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize + pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where M: TensorKeyCompressedAlloc, { diff --git a/poulpy-core/src/layouts/compressed/ggsw_ct.rs b/poulpy-core/src/layouts/compressed/ggsw_ct.rs index aba734f..fa1c46b 100644 --- a/poulpy-core/src/layouts/compressed/ggsw_ct.rs +++ b/poulpy-core/src/layouts/compressed/ggsw_ct.rs @@ -193,14 +193,7 @@ impl GGSWCompressed> { module.bytes_of_ggsw_compressed_key_from_infos(infos) } - pub fn bytes_of( - module: &M, - base2k: Base2K, - k: TorusPrecision, - rank: Rank, - dnum: Dnum, - dsize: Dsize, - ) -> usize + pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank: Rank, dnum: Dnum, dsize: Dsize) -> usize where M: GGSWCompressedAlloc, { diff --git a/poulpy-core/src/layouts/compressed/lwe_ct.rs b/poulpy-core/src/layouts/compressed/lwe_ct.rs index c1d613e..c21a6dd 100644 --- a/poulpy-core/src/layouts/compressed/lwe_ct.rs +++ b/poulpy-core/src/layouts/compressed/lwe_ct.rs @@ -91,7 +91,7 @@ pub trait LWECompressedAlloc { } } -impl LWECompressedAlloc for Module{} +impl LWECompressedAlloc for Module {} impl LWECompressed> { pub fn alloc_from_infos(module: &M, infos: &A) -> Self diff --git a/poulpy-core/src/layouts/compressed/lwe_ksk.rs b/poulpy-core/src/layouts/compressed/lwe_ksk.rs index 1f5a50a..7e1b0cf 100644 --- a/poulpy-core/src/layouts/compressed/lwe_ksk.rs +++ b/poulpy-core/src/layouts/compressed/lwe_ksk.rs @@ -147,7 +147,7 @@ where } } -impl LWESwitchingKeyCompressedAlloc for Module where Self: GLWESwitchingKeyCompressedAlloc{} +impl LWESwitchingKeyCompressedAlloc for Module where Self: GLWESwitchingKeyCompressedAlloc {} impl LWESwitchingKeyCompressed> { pub fn alloc_from_infos(module: &M, infos: &A) -> Self diff --git a/poulpy-core/src/layouts/gglwe_ct.rs b/poulpy-core/src/layouts/gglwe_ct.rs index 9c49c43..3ef1758 100644 --- a/poulpy-core/src/layouts/gglwe_ct.rs +++ b/poulpy-core/src/layouts/gglwe_ct.rs @@ -304,7 +304,15 @@ impl GGLWE> { module.alloc_glwe_from_infos(infos) } - pub fn alloc(module: &M, base2k: Base2K, k: TorusPrecision, rank_in: Rank, rank_out: Rank, dnum: Dnum, dsize: Dsize) -> Self + pub fn alloc( + module: &M, + base2k: Base2K, + k: TorusPrecision, + rank_in: Rank, + rank_out: Rank, + dnum: Dnum, + dsize: Dsize, + ) -> Self where M: GGLWEAlloc, { diff --git a/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs b/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs index e7922dc..44b5af5 100644 --- a/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs +++ b/poulpy-core/src/layouts/prepared/lwe_to_glwe_ksk.rs @@ -114,7 +114,7 @@ where impl LWEToGLWESwitchingKeyPreparedAlloc for Module where Self: GLWESwitchingKeyPreparedAlloc {} -impl LWEToGLWESwitchingKeyPrepared, B>{ +impl LWEToGLWESwitchingKeyPrepared, B> { pub fn alloc_from_infos(module: &M, infos: &A) -> Self where A: GGLWEInfos, @@ -123,7 +123,10 @@ impl LWEToGLWESwitchingKeyPrepared, B>{ module.alloc_lwe_to_glwe_switching_key_prepared_from_infos(infos) } - pub fn alloc(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self where M: LWEToGLWESwitchingKeyPreparedAlloc, { + pub fn alloc(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> Self + where + M: LWEToGLWESwitchingKeyPreparedAlloc, + { module.alloc_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum) } @@ -135,7 +138,10 @@ impl LWEToGLWESwitchingKeyPrepared, B>{ module.bytes_of_lwe_to_glwe_switching_key_prepared_from_infos(infos) } - pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize where M: LWEToGLWESwitchingKeyPreparedAlloc,{ + pub fn bytes_of(module: &M, base2k: Base2K, k: TorusPrecision, rank_out: Rank, dnum: Dnum) -> usize + where + M: LWEToGLWESwitchingKeyPreparedAlloc, + { module.bytes_of_lwe_to_glwe_switching_key_prepared(base2k, k, rank_out, dnum) } }