From 4540ea8ef60054333ca1eb8f8ec97b486e836ef6 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Mon, 28 Aug 2023 23:12:58 -0600 Subject: [PATCH 01/23] minor change to the logic of choosing between dyadic and wavelet_packets 3D wavelet transforms --- include/SPECK3D_INT.h | 10 +++++- include/SPECK3D_INT_ENC.h | 12 ++++++++ src/CDF97.cpp | 38 ++++++----------------- src/SPECK3D_INT.cpp | 64 +++++++++++++++++++++++++-------------- src/SPECK3D_INT_ENC.cpp | 11 +++++++ 5 files changed, 82 insertions(+), 53 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index f974f149..e8a7564e 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -16,7 +16,11 @@ class Set3D { uint32_t length_x = 0; uint32_t length_y = 0; uint32_t length_z = 0; - // which partition level is this set at (starting from zero, in all 3 directions). + + // What's the offset of this set in a morton organized storage? + uint64_t morton_offset = 0; + + // Which partition level is this set at (starting from zero, in all 3 directions). // This data member is the sum of all 3 partition levels. uint16_t part_level = 0; SetType type = SetType::TypeS; // Only used to indicate garbage status @@ -27,6 +31,7 @@ class Set3D { // auto is_pixel() const -> bool; auto is_empty() const -> bool; + auto num_elem() const -> size_t; }; // @@ -56,6 +61,9 @@ class SPECK3D_INT : public SPECK_INT { // SPECK3D_INT specific data members // std::vector> m_LIS; + + // Experiment with morton curves. + bool m_morton_valid = false; }; }; // namespace sperr diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index 7e6bcaab..eebc6092 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -13,6 +13,12 @@ namespace sperr { template class SPECK3D_INT_ENC : public SPECK3D_INT { private: + // + // Consistant with the base class. + // + using uint_type = T; + using vecui_type = std::vector; + // // Bring members from parent classes to this derived class. // @@ -25,6 +31,7 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { using SPECK_INT::m_sign_array; using SPECK3D_INT::m_LIS; using SPECK3D_INT::m_partition_S_XYZ; + using SPECK3D_INT::m_morton_valid; void m_sorting_pass() override; @@ -35,6 +42,11 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { // Decide if a set is significant or not. // If it is significant, also identify the point that makes it significant. auto m_decide_significance(const Set3D&) const -> std::optional>; + + // Data structures and functions testing morton data layout. + // Note: `m_morton_valid` was initialized to be false in `SPECk3D_INT::m_initialize_lists()`. + vecui_type m_morton_buf; + void m_construct_morton_buf(); }; }; // namespace sperr diff --git a/src/CDF97.cpp b/src/CDF97.cpp index e069cfa6..f95c2320 100644 --- a/src/CDF97.cpp +++ b/src/CDF97.cpp @@ -91,48 +91,28 @@ void sperr::CDF97::idwt2d() void sperr::CDF97::dwt3d() { - // Strategy to choose "dyadic" or "wavelet packet" 3D transform: - // 1) IF all 3 axes have 5 or more levels of transforms, THEN use dyadic; - // 2) ELSE IF XY and Z have different levels, THEN use wavelet packets; - // 3) ELSE use dyadic. - // - // clang-format off - const auto num_xforms = std::array{sperr::num_of_xforms(m_dims[0]), - sperr::num_of_xforms(m_dims[1]), - sperr::num_of_xforms(m_dims[2])}; - // clang-format on + auto num_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); + auto num_xforms_z = sperr::num_of_xforms(m_dims[2]); // Note: if some dimensions can do 5 levels of transforms and some can do 6, we use // dyanic scheme and do 5 levels on all of them. I.e., the benefit of dyanic // transforms exceeds one extra level of transform. - if (num_xforms[0] >= 5 && num_xforms[1] >= 5 && num_xforms[2] >= 5) { + // + if ((num_xforms_xy == num_xforms_z) || (num_xforms_xy >= 5 && num_xforms_xy >= 5)) m_dwt3d_dyadic(); - } - else if (std::min(num_xforms[0], num_xforms[1]) != num_xforms[2]) { + else m_dwt3d_wavelet_packet(); - } - else { - m_dwt3d_dyadic(); - } } void sperr::CDF97::idwt3d() { - // clang-format off - const auto num_xforms = std::array{sperr::num_of_xforms(m_dims[0]), - sperr::num_of_xforms(m_dims[1]), - sperr::num_of_xforms(m_dims[2])}; - // clang-format on + auto num_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); + auto num_xforms_z = sperr::num_of_xforms(m_dims[2]); - if (num_xforms[0] >= 5 && num_xforms[1] >= 5 && num_xforms[2] >= 5) { + if ((num_xforms_xy == num_xforms_z) || (num_xforms_xy >= 5 && num_xforms_xy >= 5)) m_idwt3d_dyadic(); - } - else if (std::min(num_xforms[0], num_xforms[1]) != num_xforms[2]) { + else m_idwt3d_wavelet_packet(); - } - else { - m_idwt3d_dyadic(); - } } void sperr::CDF97::m_dwt3d_wavelet_packet() diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 0b7a48e6..5d00d357 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -15,6 +15,11 @@ auto sperr::Set3D::is_empty() const -> bool return (length_z == 0 || length_y == 0 || length_x == 0); } +auto sperr::Set3D::num_elem() const -> size_t +{ + return (size_t{length_x} * size_t{length_y} * size_t{length_z}); +} + template void sperr::SPECK3D_INT::m_clean_LIS() { @@ -53,44 +58,57 @@ void sperr::SPECK3D_INT::m_initialize_lists() big.length_z = static_cast(m_dims[2]); // Truncate 64-bit int to 32-bit, but should be OK. - const auto num_of_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); - const auto num_of_xforms_z = sperr::num_of_xforms(m_dims[2]); - size_t xf = 0; - - while (xf < num_of_xforms_xy && xf < num_of_xforms_z) { - auto subsets = m_partition_S_XYZ(big); - big = subsets[0]; // Reference `m_partition_S_XYZ()` for subset ordering - // Also put the rest subsets in appropriate positions in `m_LIS`. - std::for_each(std::next(subsets.cbegin()), subsets.cend(), - [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); - xf++; - } + const auto num_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); + const auto num_xforms_z = sperr::num_of_xforms(m_dims[2]); - // One of these two conditions could happen if num_of_xforms_xy != num_of_xforms_z - if (xf < num_of_xforms_xy) { - while (xf < num_of_xforms_xy) { - auto subsets = m_partition_S_XY(big); + // Same logic as the choice of dyadic/wavelet_packet transform in CDF97.cpp. + if ((num_xforms_xy == num_xforms_z) || (num_xforms_xy >= 5 && num_xforms_xy >= 5)) { + auto num_xforms = std::min(num_xforms_xy, num_xforms_z); + for (size_t i = 0; i < num_xforms; i++) { + auto subsets = m_partition_S_XYZ(big); big = subsets[0]; - // Also put the rest subsets in appropriate positions in `m_LIS`. std::for_each(std::next(subsets.cbegin()), subsets.cend(), [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); - xf++; } } - else if (xf < num_of_xforms_z) { - while (xf < num_of_xforms_z) { - auto subsets = m_partition_S_Z(big); + else { + size_t xf = 0; + while (xf < num_xforms_xy && xf < num_xforms_z) { + auto subsets = m_partition_S_XYZ(big); big = subsets[0]; - const auto parts = subsets[1].part_level; - m_LIS[parts].emplace_back(subsets[1]); + std::for_each(std::next(subsets.cbegin()), subsets.cend(), + [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); xf++; } + + // One of these two conditions will happen. + if (xf < num_xforms_xy) { + while (xf < num_xforms_xy) { + auto subsets = m_partition_S_XY(big); + big = subsets[0]; + std::for_each(std::next(subsets.cbegin()), subsets.cend(), + [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); + xf++; + } + } + else if (xf < num_xforms_z) { + while (xf < num_xforms_z) { + auto subsets = m_partition_S_Z(big); + big = subsets[0]; + const auto parts = subsets[1].part_level; + m_LIS[parts].emplace_back(subsets[1]); + xf++; + } + } } // Right now big is the set that's most likely to be significant, so insert // it at the front of it's corresponding vector. One-time expense. const auto parts = big.part_level; m_LIS[parts].insert(m_LIS[parts].begin(), big); + + // Experiment with morton curves. + m_morton_valid = false; } template diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 40562058..18e62acc 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -5,9 +5,20 @@ #include // std::memcpy() #include +template +void sperr::SPECK3D_INT_ENC::m_construct_morton_buf() +{ +} + template void sperr::SPECK3D_INT_ENC::m_sorting_pass() { + // Experiment with morton curves. + if (!m_morton_valid) { + m_construct_morton_buf(); + m_morton_valid = true; + } + // Since we have a separate representation of LIP, let's process that list first! // const auto bits_x64 = m_LIP_mask.size() - m_LIP_mask.size() % 64; From 173d41102886f2364dbe857df0802a9ff35128e3 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Tue, 29 Aug 2023 11:37:12 -0600 Subject: [PATCH 02/23] working version! --- include/SPECK3D_INT.h | 17 +++-- include/SPECK3D_INT_ENC.h | 7 +- src/SPECK3D_INT.cpp | 32 ++++------ src/SPECK3D_INT_ENC.cpp | 130 +++++++++++++++++--------------------- 4 files changed, 87 insertions(+), 99 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index e8a7564e..606aa77a 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -27,11 +27,20 @@ class Set3D { public: // - // Member functions + // Member functions (intended to be inline) // - auto is_pixel() const -> bool; - auto is_empty() const -> bool; - auto num_elem() const -> size_t; + auto is_pixel() const -> bool + { + return (length_x == 1 && length_y == 1 && length_z == 1); + } + auto is_empty() const -> bool + { + return (length_z == 0 || length_y == 0 || length_x == 0); + } + auto num_elem() const -> size_t + { + return (size_t{length_x} * size_t{length_y} * size_t{length_z}); + } }; // diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index eebc6092..5a10d9e5 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -35,9 +35,9 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { void m_sorting_pass() override; - void m_process_S(size_t idx1, size_t idx2, SigType, size_t& counter, bool output); - void m_process_P(size_t idx, SigType, size_t& counter, bool output); - void m_code_S(size_t idx1, size_t idx2, std::array); + void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output); + void m_process_P(size_t idx, size_t& counter, bool output); + void m_code_S(size_t idx1, size_t idx2); // Decide if a set is significant or not. // If it is significant, also identify the point that makes it significant. @@ -47,6 +47,7 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { // Note: `m_morton_valid` was initialized to be false in `SPECk3D_INT::m_initialize_lists()`. vecui_type m_morton_buf; void m_construct_morton_buf(); + void m_deposit_set(const Set3D&); }; }; // namespace sperr diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 5d00d357..2d8915da 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -5,21 +5,6 @@ #include #include -auto sperr::Set3D::is_pixel() const -> bool -{ - return (length_x == 1 && length_y == 1 && length_z == 1); -} - -auto sperr::Set3D::is_empty() const -> bool -{ - return (length_z == 0 || length_y == 0 || length_x == 0); -} - -auto sperr::Set3D::num_elem() const -> size_t -{ - return (size_t{length_x} * size_t{length_y} * size_t{length_z}); -} - template void sperr::SPECK3D_INT::m_clean_LIS() { @@ -49,7 +34,7 @@ void sperr::SPECK3D_INT::m_initialize_lists() m_LIP_mask.reset(); // Starting from a set representing the whole volume, identify the smaller - // sets and put them in LIS accordingly. + // subsets and put them in the LIS accordingly. Set3D big; big.length_x = static_cast(m_dims[0]); // Truncate 64-bit int to 32-bit, but should be OK. @@ -138,6 +123,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub0.length_x = split_x[0]; sub0.length_y = split_y[0]; sub0.length_z = split_z[0]; + sub0.morton_offset = set.morton_offset; sub0.part_level = next_part_lev; // subset (1, 0, 0) @@ -149,6 +135,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub1.length_x = split_x[1]; sub1.length_y = split_y[0]; sub1.length_z = split_z[0]; + sub1.morton_offset = sub0.morton_offset + sub0.num_elem(); sub1.part_level = next_part_lev; // subset (0, 1, 0) @@ -160,6 +147,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub2.length_x = split_x[0]; sub2.length_y = split_y[1]; sub2.length_z = split_z[0]; + sub2.morton_offset = sub1.morton_offset + sub1.num_elem(); sub2.part_level = next_part_lev; // subset (1, 1, 0) @@ -171,6 +159,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub3.length_x = split_x[1]; sub3.length_y = split_y[1]; sub3.length_z = split_z[0]; + sub3.morton_offset = sub2.morton_offset + sub2.num_elem(); sub3.part_level = next_part_lev; // subset (0, 0, 1) @@ -182,6 +171,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub4.length_x = split_x[0]; sub4.length_y = split_y[0]; sub4.length_z = split_z[1]; + sub4.morton_offset = sub3.morton_offset + sub3.num_elem(); sub4.part_level = next_part_lev; // subset (1, 0, 1) @@ -193,6 +183,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub5.length_x = split_x[1]; sub5.length_y = split_y[0]; sub5.length_z = split_z[1]; + sub5.morton_offset = sub4.morton_offset + sub4.num_elem(); sub5.part_level = next_part_lev; // subset (0, 1, 1) @@ -204,6 +195,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub6.length_x = split_x[0]; sub6.length_y = split_y[1]; sub6.length_z = split_z[1]; + sub6.morton_offset = sub5.morton_offset + sub5.num_elem(); sub6.part_level = next_part_lev; // subset (1, 1, 1) @@ -215,6 +207,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub7.length_x = split_x[1]; sub7.length_y = split_y[1]; sub7.length_z = split_z[1]; + sub7.morton_offset = sub6.morton_offset + sub6.num_elem(); sub7.part_level = next_part_lev; return subsets; @@ -223,11 +216,12 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar template auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::array { - std::array subsets; + // This partition scheme is only used during initialization; no need to calculate morton offset. const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; + std::array subsets; for (auto& s : subsets) { s.part_level = set.part_level; if (split_x[1] > 0) @@ -238,7 +232,6 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr const auto offsets = std::array{1, 2, 4}; - // // The actual figuring out where it starts/ends part... // // subset (0, 0, 0) @@ -287,10 +280,11 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr template auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set) const -> std::array { - std::array subsets; + // This partition scheme is only used during initialization; no need to calculate morton offset. const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; + std::array subsets; for (auto& s : subsets) { s.part_level = set.part_level; if (split_z[1] > 0) diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 18e62acc..742dbb44 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -5,15 +5,46 @@ #include // std::memcpy() #include +template +void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) +{ + switch (set.num_elem()) { + case 0: + break; + case 1: { + auto idx = set.start_z * m_dims[0] * m_dims[1] + set.start_y * m_dims[0] + set.start_x; + m_morton_buf[set.morton_offset] = m_coeff_buf[idx]; + break; + } + default: { + auto subsets = m_partition_S_XYZ(set); + for (auto& sub : subsets) + m_deposit_set(sub); + } + } +} + template void sperr::SPECK3D_INT_ENC::m_construct_morton_buf() { + m_morton_buf.resize(m_dims[0] * m_dims[1] * m_dims[2]); + + // The same traversing order as in `m_sorting_pass()` + size_t morton_offset = 0; + for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { + auto idx1 = m_LIS.size() - tmp; + for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { + auto& set = m_LIS[idx1][idx2]; + set.morton_offset = morton_offset; + m_deposit_set(set); + morton_offset += set.num_elem(); + } + } } template void sperr::SPECK3D_INT_ENC::m_sorting_pass() { - // Experiment with morton curves. if (!m_morton_valid) { m_construct_morton_buf(); m_morton_valid = true; @@ -29,7 +60,7 @@ void sperr::SPECK3D_INT_ENC::m_sorting_pass() for (size_t j = 0; j < 64; j++) { if ((value >> j) & uint64_t{1}) { size_t dummy = 0; - m_process_P(i + j, SigType::Dunno, dummy, true); + m_process_P(i + j, dummy, true); } } } @@ -37,18 +68,18 @@ void sperr::SPECK3D_INT_ENC::m_sorting_pass() for (auto i = bits_x64; i < m_LIP_mask.size(); i++) { if (m_LIP_mask.read_bit(i)) { size_t dummy = 0; - m_process_P(i, SigType::Dunno, dummy, true); + m_process_P(i, dummy, true); } } // Then we process regular sets in LIS. + // (From the end of m_LIS to its front.) // for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { - // From the end of m_LIS to its front - size_t idx1 = m_LIS.size() - tmp; + auto idx1 = m_LIS.size() - tmp; for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { size_t dummy = 0; - m_process_S(idx1, idx2, SigType::Dunno, dummy, true); + m_process_S(idx1, idx2, dummy, true); } } } @@ -56,73 +87,37 @@ void sperr::SPECK3D_INT_ENC::m_sorting_pass() template void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, - SigType sig, size_t& counter, bool output) { - // Significance type cannot be NewlySig! - assert(sig != SigType::NewlySig); - auto& set = m_LIS[idx1][idx2]; - - // Strategy to decide the significance of this set; - // 1) If sig == dunno, then find the significance of this set. We do it in a - // way that some of its 8 subsets' significance become known as well. - // 2) If sig is significant, then we directly proceed to `m_code_s()`, with its - // subsets' significance is unknown. - // 3) if sig is insignificant, then this set is not processed. - - std::array subset_sigs; - subset_sigs.fill(SigType::Dunno); - - if (sig == SigType::Dunno) { - auto set_sig = m_decide_significance(set); - sig = set_sig ? SigType::Sig : SigType::Insig; - if (set_sig) { - // Try to deduce the significance of some of its subsets. - // Step 1: which one of the 8 subsets makes it significant? - // (Refer to m_partition_S_XYZ() for subset ordering.) - auto xyz = *set_sig; - size_t sub_i = 0; - sub_i += (xyz[0] < (set.length_x - set.length_x / 2)) ? 0 : 1; - sub_i += (xyz[1] < (set.length_y - set.length_y / 2)) ? 0 : 2; - sub_i += (xyz[2] < (set.length_z - set.length_z / 2)) ? 0 : 4; - subset_sigs[sub_i] = SigType::Sig; - - // Step 2: if it's the 5th, 6th, 7th, or 8th subset significant, then - // the first four subsets must be insignificant. Again, this is - // based on the ordering of subsets. - // In a cube there is 30% - 40% chance this condition meets. - if (sub_i >= 4) { - for (size_t i = 0; i < 4; i++) - subset_sigs[i] = SigType::Insig; - } - } + auto is_sig = true; + + // If need to output, it means the current set has unknown significance. + if (output) { + auto first = m_morton_buf.cbegin() + set.morton_offset; + auto last = first + set.num_elem(); + auto found = std::find_if(first, last, [thld = m_threshold](auto v) { return v >= thld; }); + is_sig = (found != last); + m_bit_buffer.wbit(is_sig); } - if (output) - m_bit_buffer.wbit(sig == SigType::Sig); - - if (sig == SigType::Sig) { + if (is_sig) { counter++; // Let's increment the counter first! - m_code_S(idx1, idx2, subset_sigs); + m_code_S(idx1, idx2); set.type = SetType::Garbage; // this current set is gonna be discarded. } } template -void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, SigType sig, size_t& counter, bool output) +void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t& counter, bool output) { - // Decide the significance of this pixel - assert(sig != SigType::NewlySig); - bool is_sig = false; - if (sig == SigType::Dunno) - is_sig = (m_coeff_buf[idx] >= m_threshold); - else - is_sig = (sig == SigType::Sig); + bool is_sig = true; - if (output) + if (output) { + is_sig = (m_coeff_buf[idx] >= m_threshold); m_bit_buffer.wbit(is_sig); + } if (is_sig) { counter++; // Let's increment the counter first! @@ -136,46 +131,35 @@ void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, SigType sig, size_t& cou } template -void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, - size_t idx2, - std::array subset_sigs) +void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) { auto subsets = m_partition_S_XYZ(m_LIS[idx1][idx2]); // Since some subsets could be empty, let's put empty sets at the end. // - for (size_t i = 0; i < subsets.size(); i++) { - if (subsets[i].is_empty()) - subset_sigs[i] = SigType::Garbage; // SigType::Garbage is only used locally here. - } - auto sig_end = std::remove(subset_sigs.begin(), subset_sigs.end(), SigType::Garbage); const auto set_end = std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); const auto set_end_m1 = set_end - 1; - auto sig_it = subset_sigs.begin(); size_t sig_counter = 0; for (auto it = subsets.begin(); it != set_end; ++it) { // If we're looking at the last subset, and no prior subset is found to be // significant, then we know that this last one *is* significant. bool output = true; - if (it == set_end_m1 && sig_counter == 0) { + if (it == set_end_m1 && sig_counter == 0) output = false; - *sig_it = SigType::Sig; - } if (it->is_pixel()) { auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; m_LIP_mask.write_true(idx); - m_process_P(idx, *sig_it, sig_counter, output); + m_process_P(idx, sig_counter, output); } else { const auto newidx1 = it->part_level; m_LIS[newidx1].emplace_back(*it); const auto newidx2 = m_LIS[newidx1].size() - 1; - m_process_S(newidx1, newidx2, *sig_it, sig_counter, output); + m_process_S(newidx1, newidx2, sig_counter, output); } - ++sig_it; } } From 84558f383f863e4717160db81f586a124da905c8 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Tue, 29 Aug 2023 11:40:19 -0600 Subject: [PATCH 03/23] remove unused function: decide_significance --- include/SPECK3D_INT_ENC.h | 6 +----- src/SPECK3D_INT_ENC.cpp | 26 -------------------------- 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index 5a10d9e5..d66b0086 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -39,11 +39,7 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { void m_process_P(size_t idx, size_t& counter, bool output); void m_code_S(size_t idx1, size_t idx2); - // Decide if a set is significant or not. - // If it is significant, also identify the point that makes it significant. - auto m_decide_significance(const Set3D&) const -> std::optional>; - - // Data structures and functions testing morton data layout. + // Data structures and functions for morton data layout. // Note: `m_morton_valid` was initialized to be false in `SPECk3D_INT::m_initialize_lists()`. vecui_type m_morton_buf; void m_construct_morton_buf(); diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 742dbb44..3e2bd0b1 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -163,32 +163,6 @@ void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) } } -template -auto sperr::SPECK3D_INT_ENC::m_decide_significance(const Set3D& set) const - -> std::optional> -{ - assert(!set.is_empty()); - - const size_t slice_size = m_dims[0] * m_dims[1]; - - const auto gtr = [thld = m_threshold](auto v) { return v >= thld; }; - - for (auto z = set.start_z; z < (set.start_z + set.length_z); z++) { - const size_t slice_offset = z * slice_size; - for (auto y = set.start_y; y < (set.start_y + set.length_y); y++) { - auto first = m_coeff_buf.cbegin() + (slice_offset + y * m_dims[0] + set.start_x); - auto last = first + set.length_x; - auto found = std::find_if(first, last, gtr); - if (found != last) { - auto x = static_cast(std::distance(first, found)); - return std::optional>({x, y - set.start_y, z - set.start_z}); - } - } - } - - return std::optional>(); -} - template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; From 61f5bec7f28a002e9bf65ce52116ae316ba5f367 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Tue, 29 Aug 2023 15:49:08 -0600 Subject: [PATCH 04/23] minor improvement --- src/SPECK3D_INT_ENC.cpp | 25 ++++++++++++++++++++----- src/SPECK_INT.cpp | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 3e2bd0b1..4e604520 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -16,6 +16,24 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) m_morton_buf[set.morton_offset] = m_coeff_buf[idx]; break; } + case 2: { + // We directly deposit the 2 elements in `set` instead of performing another partition. + // + // Deposit the 1st element. + auto idx = set.start_z * m_dims[0] * m_dims[1] + set.start_y * m_dims[0] + set.start_x; + m_morton_buf[set.morton_offset] = m_coeff_buf[idx]; + + // Deposit the 2nd element. + if (set.length_x == 2) + idx++; + else if (set.length_y == 2) + idx += m_dims[0]; + else + idx += m_dims[0] * m_dims[1]; + m_morton_buf[set.morton_offset + 1] = m_coeff_buf[idx]; + + break; + } default: { auto subsets = m_partition_S_XYZ(set); for (auto& sub : subsets) @@ -85,10 +103,7 @@ void sperr::SPECK3D_INT_ENC::m_sorting_pass() } template -void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, - size_t idx2, - size_t& counter, - bool output) +void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output) { auto& set = m_LIS[idx1][idx2]; auto is_sig = true; @@ -96,7 +111,7 @@ void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, // If need to output, it means the current set has unknown significance. if (output) { auto first = m_morton_buf.cbegin() + set.morton_offset; - auto last = first + set.num_elem(); + auto last = m_morton_buf.cbegin() + set.morton_offset + set.num_elem(); auto found = std::find_if(first, last, [thld = m_threshold](auto v) { return v >= thld; }); is_sig = (found != last); m_bit_buffer.wbit(is_sig); diff --git a/src/SPECK_INT.cpp b/src/SPECK_INT.cpp index 6e70ca5e..ad33fc1d 100644 --- a/src/SPECK_INT.cpp +++ b/src/SPECK_INT.cpp @@ -403,7 +403,7 @@ void sperr::SPECK_INT::m_refinement_pass_decode() // value at the middle of the interval specified by `m_threshold`. Note that given the integer // nature of these coefficients, there are actually two values equally "in the middle." // For example, with `m_threshold == 4`, the interval is [4, 8), and both 5 and 6 are "in the - // middle." I choose the smaller one (5 in this example) here. My experiments show that + // middle." I choose the smaller one (5 in this example) here. My experiments show that // choosing the smaller value rather than the bigger one does not hurt, and sometimes bring a // little extra PSNR gain (<0.5). Also note that the formula calculating `init_val` // makes sure that when `m_threshold == 1`, significant points are initialized as 1. From cee93cf19b2f4e9ec41319e1bda9dd24e6ba7c81 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Wed, 30 Aug 2023 11:04:49 -0600 Subject: [PATCH 05/23] Set3D uses 16-bit integers to record integers --- include/SPECK3D_INT.h | 12 ++++++------ src/SPECK3D_INT.cpp | 35 +++++++++++++++++++---------------- src/SPECK3D_INT_ENC.cpp | 3 +-- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 606aa77a..10530d3e 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -10,12 +10,12 @@ class Set3D { // // Member data // - uint32_t start_x = 0; - uint32_t start_y = 0; - uint32_t start_z = 0; - uint32_t length_x = 0; - uint32_t length_y = 0; - uint32_t length_z = 0; + uint16_t start_x = 0; + uint16_t start_y = 0; + uint16_t start_z = 0; + uint16_t length_x = 0; + uint16_t length_y = 0; + uint16_t length_z = 0; // What's the offset of this set in a morton organized storage? uint64_t morton_offset = 0; diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 2d8915da..12ef942e 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -34,14 +34,12 @@ void sperr::SPECK3D_INT::m_initialize_lists() m_LIP_mask.reset(); // Starting from a set representing the whole volume, identify the smaller - // subsets and put them in the LIS accordingly. + // subsets and put them in the LIS accordingly. + // Note that it truncates 64-bit ints to 16-bit ints here, but should be OK. Set3D big; - big.length_x = - static_cast(m_dims[0]); // Truncate 64-bit int to 32-bit, but should be OK. - big.length_y = - static_cast(m_dims[1]); // Truncate 64-bit int to 32-bit, but should be OK. - big.length_z = - static_cast(m_dims[2]); // Truncate 64-bit int to 32-bit, but should be OK. + big.length_x = static_cast(m_dims[0]); + big.length_y = static_cast(m_dims[1]); + big.length_z = static_cast(m_dims[2]); const auto num_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); const auto num_xforms_z = sperr::num_of_xforms(m_dims[2]); @@ -99,14 +97,19 @@ void sperr::SPECK3D_INT::m_initialize_lists() template auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::array { - const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; - const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; - const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; + // Integer promotion rules (https://en.cppreference.com/w/c/language/conversion) say that types + // shorter than `int` are implicitly promoted to be `int` to perform calculations, so just + // keep them as `int` here because they'll involve in calculations later. + // + const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; + const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; + const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; auto next_part_lev = set.part_level; - next_part_lev += split_x[1] > 0 ? 1 : 0; - next_part_lev += split_y[1] > 0 ? 1 : 0; - next_part_lev += split_z[1] > 0 ? 1 : 0; + const auto tmp = std::array{0, 1}; + next_part_lev += tmp[split_x[1] != 0]; + next_part_lev += tmp[split_y[1] != 0]; + next_part_lev += tmp[split_z[1] != 0]; std::array subsets; constexpr auto offsets = std::array{1, 2, 4}; @@ -218,8 +221,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr { // This partition scheme is only used during initialization; no need to calculate morton offset. - const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; - const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; + const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; + const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; std::array subsets; for (auto& s : subsets) { @@ -282,7 +285,7 @@ auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set) const -> std::arra { // This partition scheme is only used during initialization; no need to calculate morton offset. - const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; + const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; std::array subsets; for (auto& s : subsets) { diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 4e604520..02a1621c 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -112,8 +112,7 @@ void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, size_t& co if (output) { auto first = m_morton_buf.cbegin() + set.morton_offset; auto last = m_morton_buf.cbegin() + set.morton_offset + set.num_elem(); - auto found = std::find_if(first, last, [thld = m_threshold](auto v) { return v >= thld; }); - is_sig = (found != last); + is_sig = std::any_of(first, last, [thld = m_threshold](auto v) { return v >= thld; }); m_bit_buffer.wbit(is_sig); } From 5a7938732c690bed754f31fe3893e3430547ff37 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Thu, 31 Aug 2023 11:41:53 -0600 Subject: [PATCH 06/23] use a more compact representation of morton offset, and also remove the use of SetType --- include/SPECK3D_INT.h | 32 ++++++++++++++++++++++++-------- src/SPECK3D_INT.cpp | 23 +++++++++++------------ src/SPECK3D_INT_DEC.cpp | 6 +++--- src/SPECK3D_INT_ENC.cpp | 19 ++++++++++--------- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 10530d3e..9d0707d3 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -3,13 +3,17 @@ #include "SPECK_INT.h" +#include // std::memcpy + namespace sperr { class Set3D { + private: + // The first 6 bytes of the morton offset in uint64_t. Because each set dimension is + // stored using 16-bit integers, these 48 bits are big enough too! + std::array m_morton = {0, 0, 0, 0, 0, 0}; + public: - // - // Member data - // uint16_t start_x = 0; uint16_t start_y = 0; uint16_t start_z = 0; @@ -17,18 +21,24 @@ class Set3D { uint16_t length_y = 0; uint16_t length_z = 0; - // What's the offset of this set in a morton organized storage? - uint64_t morton_offset = 0; - // Which partition level is this set at (starting from zero, in all 3 directions). // This data member is the sum of all 3 partition levels. - uint16_t part_level = 0; - SetType type = SetType::TypeS; // Only used to indicate garbage status + uint8_t part_level = 0; public: // // Member functions (intended to be inline) // + auto get_morton() const -> uint64_t + { + auto tmp = uint64_t{0}; + std::memcpy(&tmp, m_morton.data(), sizeof(m_morton)); + return tmp; + } + void set_morton(uint64_t val) + { + std::memcpy(m_morton.data(), &val, sizeof(m_morton)); + } auto is_pixel() const -> bool { return (length_x == 1 && length_y == 1 && length_z == 1); @@ -37,6 +47,12 @@ class Set3D { { return (length_z == 0 || length_y == 0 || length_x == 0); } + void make_empty() + { + length_x = 0; + length_y = 0; + length_z = 0; + } auto num_elem() const -> size_t { return (size_t{length_x} * size_t{length_y} * size_t{length_z}); diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 12ef942e..c4f5ad71 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -9,8 +9,7 @@ template void sperr::SPECK3D_INT::m_clean_LIS() { for (auto& list : m_LIS) { - auto it = std::remove_if(list.begin(), list.end(), - [](const auto& s) { return s.type == SetType::Garbage; }); + auto it = std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.is_empty(); }); list.erase(it, list.end()); } } @@ -90,7 +89,7 @@ void sperr::SPECK3D_INT::m_initialize_lists() const auto parts = big.part_level; m_LIS[parts].insert(m_LIS[parts].begin(), big); - // Experiment with morton curves. + // The morton curves are not constructed yet! m_morton_valid = false; } @@ -106,7 +105,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; auto next_part_lev = set.part_level; - const auto tmp = std::array{0, 1}; + const auto tmp = std::array{0, 1}; next_part_lev += tmp[split_x[1] != 0]; next_part_lev += tmp[split_y[1] != 0]; next_part_lev += tmp[split_z[1] != 0]; @@ -120,97 +119,97 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar // subset (0, 0, 0) constexpr auto idx0 = 0 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; auto& sub0 = subsets[idx0]; + sub0.set_morton(set.get_morton()); sub0.start_x = set.start_x; sub0.start_y = set.start_y; sub0.start_z = set.start_z; sub0.length_x = split_x[0]; sub0.length_y = split_y[0]; sub0.length_z = split_z[0]; - sub0.morton_offset = set.morton_offset; sub0.part_level = next_part_lev; // subset (1, 0, 0) constexpr auto idx1 = 1 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; auto& sub1 = subsets[idx1]; + sub1.set_morton(sub0.get_morton() + sub0.num_elem()); sub1.start_x = set.start_x + split_x[0]; sub1.start_y = set.start_y; sub1.start_z = set.start_z; sub1.length_x = split_x[1]; sub1.length_y = split_y[0]; sub1.length_z = split_z[0]; - sub1.morton_offset = sub0.morton_offset + sub0.num_elem(); sub1.part_level = next_part_lev; // subset (0, 1, 0) constexpr auto idx2 = 0 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; auto& sub2 = subsets[idx2]; + sub2.set_morton(sub1.get_morton() + sub1.num_elem()); sub2.start_x = set.start_x; sub2.start_y = set.start_y + split_y[0]; sub2.start_z = set.start_z; sub2.length_x = split_x[0]; sub2.length_y = split_y[1]; sub2.length_z = split_z[0]; - sub2.morton_offset = sub1.morton_offset + sub1.num_elem(); sub2.part_level = next_part_lev; // subset (1, 1, 0) constexpr auto idx3 = 1 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; auto& sub3 = subsets[idx3]; + sub3.set_morton(sub2.get_morton() + sub2.num_elem()); sub3.start_x = set.start_x + split_x[0]; sub3.start_y = set.start_y + split_y[0]; sub3.start_z = set.start_z; sub3.length_x = split_x[1]; sub3.length_y = split_y[1]; sub3.length_z = split_z[0]; - sub3.morton_offset = sub2.morton_offset + sub2.num_elem(); sub3.part_level = next_part_lev; // subset (0, 0, 1) constexpr auto idx4 = 0 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; auto& sub4 = subsets[idx4]; + sub4.set_morton(sub3.get_morton() + sub3.num_elem()); sub4.start_x = set.start_x; sub4.start_y = set.start_y; sub4.start_z = set.start_z + split_z[0]; sub4.length_x = split_x[0]; sub4.length_y = split_y[0]; sub4.length_z = split_z[1]; - sub4.morton_offset = sub3.morton_offset + sub3.num_elem(); sub4.part_level = next_part_lev; // subset (1, 0, 1) constexpr auto idx5 = 1 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; auto& sub5 = subsets[idx5]; + sub5.set_morton(sub4.get_morton() + sub4.num_elem()); sub5.start_x = set.start_x + split_x[0]; sub5.start_y = set.start_y; sub5.start_z = set.start_z + split_z[0]; sub5.length_x = split_x[1]; sub5.length_y = split_y[0]; sub5.length_z = split_z[1]; - sub5.morton_offset = sub4.morton_offset + sub4.num_elem(); sub5.part_level = next_part_lev; // subset (0, 1, 1) constexpr auto idx6 = 0 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; auto& sub6 = subsets[idx6]; + sub6.set_morton(sub5.get_morton() + sub5.num_elem()); sub6.start_x = set.start_x; sub6.start_y = set.start_y + split_y[0]; sub6.start_z = set.start_z + split_z[0]; sub6.length_x = split_x[0]; sub6.length_y = split_y[1]; sub6.length_z = split_z[1]; - sub6.morton_offset = sub5.morton_offset + sub5.num_elem(); sub6.part_level = next_part_lev; // subset (1, 1, 1) constexpr auto idx7 = 1 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; auto& sub7 = subsets[idx7]; + sub7.set_morton(sub6.get_morton() + sub6.num_elem()); sub7.start_x = set.start_x + split_x[0]; sub7.start_y = set.start_y + split_y[0]; sub7.start_z = set.start_z + split_z[0]; sub7.length_x = split_x[1]; sub7.length_y = split_y[1]; sub7.length_z = split_z[1]; - sub7.morton_offset = sub6.morton_offset + sub6.num_elem(); sub7.part_level = next_part_lev; return subsets; diff --git a/src/SPECK3D_INT_DEC.cpp b/src/SPECK3D_INT_DEC.cpp index 35fca016..c08500ed 100644 --- a/src/SPECK3D_INT_DEC.cpp +++ b/src/SPECK3D_INT_DEC.cpp @@ -53,9 +53,9 @@ void sperr::SPECK3D_INT_DEC::m_process_S(size_t idx1, size_t idx2, size_t& co is_sig = m_bit_buffer.rbit(); if (is_sig) { - counter++; // Let's increment the counter first! + counter++; m_code_S(idx1, idx2); - set.type = SetType::Garbage; // this current set is gonna be discarded. + set.make_empty(); // this current set is gonna be discarded. } } @@ -98,7 +98,7 @@ void sperr::SPECK3D_INT_DEC::m_code_S(size_t idx1, size_t idx2) m_process_P(idx, sig_counter, read); } else { - const auto newidx1 = it->part_level; + const size_t newidx1 = it->part_level; m_LIS[newidx1].emplace_back(*it); const auto newidx2 = m_LIS[newidx1].size() - 1; m_process_S(newidx1, newidx2, sig_counter, read); diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 02a1621c..934b40c7 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -13,7 +13,7 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) break; case 1: { auto idx = set.start_z * m_dims[0] * m_dims[1] + set.start_y * m_dims[0] + set.start_x; - m_morton_buf[set.morton_offset] = m_coeff_buf[idx]; + m_morton_buf[set.get_morton()] = m_coeff_buf[idx]; break; } case 2: { @@ -21,7 +21,8 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) // // Deposit the 1st element. auto idx = set.start_z * m_dims[0] * m_dims[1] + set.start_y * m_dims[0] + set.start_x; - m_morton_buf[set.morton_offset] = m_coeff_buf[idx]; + auto idx_morton = set.get_morton(); + m_morton_buf[idx_morton] = m_coeff_buf[idx]; // Deposit the 2nd element. if (set.length_x == 2) @@ -30,7 +31,7 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) idx += m_dims[0]; else idx += m_dims[0] * m_dims[1]; - m_morton_buf[set.morton_offset + 1] = m_coeff_buf[idx]; + m_morton_buf[idx_morton + 1] = m_coeff_buf[idx]; break; } @@ -53,7 +54,7 @@ void sperr::SPECK3D_INT_ENC::m_construct_morton_buf() auto idx1 = m_LIS.size() - tmp; for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { auto& set = m_LIS[idx1][idx2]; - set.morton_offset = morton_offset; + set.set_morton(morton_offset); m_deposit_set(set); morton_offset += set.num_elem(); } @@ -110,16 +111,16 @@ void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, size_t& co // If need to output, it means the current set has unknown significance. if (output) { - auto first = m_morton_buf.cbegin() + set.morton_offset; - auto last = m_morton_buf.cbegin() + set.morton_offset + set.num_elem(); + auto first = m_morton_buf.cbegin() + set.get_morton(); + auto last = m_morton_buf.cbegin() + set.get_morton() + set.num_elem(); is_sig = std::any_of(first, last, [thld = m_threshold](auto v) { return v >= thld; }); m_bit_buffer.wbit(is_sig); } if (is_sig) { - counter++; // Let's increment the counter first! + counter++; m_code_S(idx1, idx2); - set.type = SetType::Garbage; // this current set is gonna be discarded. + set.make_empty(); // this current set is gonna be discarded. } } @@ -169,7 +170,7 @@ void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) m_process_P(idx, sig_counter, output); } else { - const auto newidx1 = it->part_level; + const size_t newidx1 = it->part_level; m_LIS[newidx1].emplace_back(*it); const auto newidx2 = m_LIS[newidx1].size() - 1; m_process_S(newidx1, newidx2, sig_counter, output); From 23a990f72ea5af20e9cfe3b9b507703763b02043 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Thu, 31 Aug 2023 13:51:35 -0600 Subject: [PATCH 07/23] bring the Set3D object size down to 18 bytes! --- include/SPECK3D_INT.h | 14 +++--- src/SPECK3D_INT.cpp | 109 +++++++++++++++++++--------------------- src/SPECK3D_INT_DEC.cpp | 9 ++-- src/SPECK3D_INT_ENC.cpp | 11 ++-- 4 files changed, 67 insertions(+), 76 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 9d0707d3..3b6c372f 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -4,6 +4,7 @@ #include "SPECK_INT.h" #include // std::memcpy +#include namespace sperr { @@ -14,6 +15,9 @@ class Set3D { std::array m_morton = {0, 0, 0, 0, 0, 0}; public: + // + // Publicly accessible public data members. + // uint16_t start_x = 0; uint16_t start_y = 0; uint16_t start_z = 0; @@ -21,10 +25,6 @@ class Set3D { uint16_t length_y = 0; uint16_t length_z = 0; - // Which partition level is this set at (starting from zero, in all 3 directions). - // This data member is the sum of all 3 partition levels. - uint8_t part_level = 0; - public: // // Member functions (intended to be inline) @@ -78,9 +78,9 @@ class SPECK3D_INT : public SPECK_INT { void m_initialize_lists() override; // Divide a Set3D into 8, 4, or 2 smaller subsets. - auto m_partition_S_XYZ(const Set3D&) const -> std::array; - auto m_partition_S_XY(const Set3D&) const -> std::array; - auto m_partition_S_Z(const Set3D&) const -> std::array; + auto m_partition_S_XYZ(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; + auto m_partition_S_XY(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; + auto m_partition_S_Z(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; // // SPECK3D_INT specific data members diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index c4f5ad71..314adc16 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -42,43 +42,47 @@ void sperr::SPECK3D_INT::m_initialize_lists() const auto num_xforms_xy = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); const auto num_xforms_z = sperr::num_of_xforms(m_dims[2]); + auto curr_lev = uint16_t{0}; // Same logic as the choice of dyadic/wavelet_packet transform in CDF97.cpp. if ((num_xforms_xy == num_xforms_z) || (num_xforms_xy >= 5 && num_xforms_xy >= 5)) { auto num_xforms = std::min(num_xforms_xy, num_xforms_z); for (size_t i = 0; i < num_xforms; i++) { - auto subsets = m_partition_S_XYZ(big); + auto [subsets, next_lev] = m_partition_S_XYZ(big, curr_lev); big = subsets[0]; - std::for_each(std::next(subsets.cbegin()), subsets.cend(), - [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); + for (auto it = std::next(subsets.cbegin()); it != subsets.cend(); ++it) + m_LIS[next_lev].emplace_back(*it); + curr_lev = next_lev; } } else { size_t xf = 0; while (xf < num_xforms_xy && xf < num_xforms_z) { - auto subsets = m_partition_S_XYZ(big); + auto [subsets, next_lev] = m_partition_S_XYZ(big, curr_lev); big = subsets[0]; - std::for_each(std::next(subsets.cbegin()), subsets.cend(), - [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); + for (auto it = std::next(subsets.cbegin()); it != subsets.cend(); ++it) + m_LIS[next_lev].emplace_back(*it); + curr_lev = next_lev; xf++; } // One of these two conditions will happen. if (xf < num_xforms_xy) { while (xf < num_xforms_xy) { - auto subsets = m_partition_S_XY(big); + auto [subsets, next_lev] = m_partition_S_XY(big, curr_lev); big = subsets[0]; - std::for_each(std::next(subsets.cbegin()), subsets.cend(), - [&](const auto& s) { m_LIS[s.part_level].emplace_back(s); }); + for (auto it = std::next(subsets.cbegin()); it != subsets.cend(); ++it) + m_LIS[next_lev].emplace_back(*it); + curr_lev = next_lev; xf++; } } else if (xf < num_xforms_z) { while (xf < num_xforms_z) { - auto subsets = m_partition_S_Z(big); + auto [subsets, next_lev] = m_partition_S_Z(big, curr_lev); big = subsets[0]; - const auto parts = subsets[1].part_level; - m_LIS[parts].emplace_back(subsets[1]); + m_LIS[next_lev].emplace_back(subsets[1]); + curr_lev = next_lev; xf++; } } @@ -86,15 +90,15 @@ void sperr::SPECK3D_INT::m_initialize_lists() // Right now big is the set that's most likely to be significant, so insert // it at the front of it's corresponding vector. One-time expense. - const auto parts = big.part_level; - m_LIS[parts].insert(m_LIS[parts].begin(), big); + m_LIS[curr_lev].insert(m_LIS[curr_lev].begin(), big); // The morton curves are not constructed yet! m_morton_valid = false; } template -auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::array +auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) const + -> std::tuple, uint16_t> { // Integer promotion rules (https://en.cppreference.com/w/c/language/conversion) say that types // shorter than `int` are implicitly promoted to be `int` to perform calculations, so just @@ -104,13 +108,13 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; - auto next_part_lev = set.part_level; const auto tmp = std::array{0, 1}; - next_part_lev += tmp[split_x[1] != 0]; - next_part_lev += tmp[split_y[1] != 0]; - next_part_lev += tmp[split_z[1] != 0]; + lev += tmp[split_x[1] != 0]; + lev += tmp[split_y[1] != 0]; + lev += tmp[split_z[1] != 0]; - std::array subsets; + auto subsets = std::tuple, uint16_t>(); + std::get<1>(subsets) = lev; constexpr auto offsets = std::array{1, 2, 4}; // @@ -118,7 +122,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar // // subset (0, 0, 0) constexpr auto idx0 = 0 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; - auto& sub0 = subsets[idx0]; + auto& sub0 = std::get<0>(subsets)[idx0]; sub0.set_morton(set.get_morton()); sub0.start_x = set.start_x; sub0.start_y = set.start_y; @@ -126,11 +130,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub0.length_x = split_x[0]; sub0.length_y = split_y[0]; sub0.length_z = split_z[0]; - sub0.part_level = next_part_lev; // subset (1, 0, 0) constexpr auto idx1 = 1 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; - auto& sub1 = subsets[idx1]; + auto& sub1 = std::get<0>(subsets)[idx1]; sub1.set_morton(sub0.get_morton() + sub0.num_elem()); sub1.start_x = set.start_x + split_x[0]; sub1.start_y = set.start_y; @@ -138,11 +141,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub1.length_x = split_x[1]; sub1.length_y = split_y[0]; sub1.length_z = split_z[0]; - sub1.part_level = next_part_lev; // subset (0, 1, 0) constexpr auto idx2 = 0 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; - auto& sub2 = subsets[idx2]; + auto& sub2 = std::get<0>(subsets)[idx2]; sub2.set_morton(sub1.get_morton() + sub1.num_elem()); sub2.start_x = set.start_x; sub2.start_y = set.start_y + split_y[0]; @@ -150,11 +152,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub2.length_x = split_x[0]; sub2.length_y = split_y[1]; sub2.length_z = split_z[0]; - sub2.part_level = next_part_lev; // subset (1, 1, 0) constexpr auto idx3 = 1 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; - auto& sub3 = subsets[idx3]; + auto& sub3 = std::get<0>(subsets)[idx3]; sub3.set_morton(sub2.get_morton() + sub2.num_elem()); sub3.start_x = set.start_x + split_x[0]; sub3.start_y = set.start_y + split_y[0]; @@ -162,11 +163,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub3.length_x = split_x[1]; sub3.length_y = split_y[1]; sub3.length_z = split_z[0]; - sub3.part_level = next_part_lev; // subset (0, 0, 1) constexpr auto idx4 = 0 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; - auto& sub4 = subsets[idx4]; + auto& sub4 = std::get<0>(subsets)[idx4]; sub4.set_morton(sub3.get_morton() + sub3.num_elem()); sub4.start_x = set.start_x; sub4.start_y = set.start_y; @@ -174,11 +174,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub4.length_x = split_x[0]; sub4.length_y = split_y[0]; sub4.length_z = split_z[1]; - sub4.part_level = next_part_lev; // subset (1, 0, 1) constexpr auto idx5 = 1 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; - auto& sub5 = subsets[idx5]; + auto& sub5 = std::get<0>(subsets)[idx5]; sub5.set_morton(sub4.get_morton() + sub4.num_elem()); sub5.start_x = set.start_x + split_x[0]; sub5.start_y = set.start_y; @@ -186,11 +185,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub5.length_x = split_x[1]; sub5.length_y = split_y[0]; sub5.length_z = split_z[1]; - sub5.part_level = next_part_lev; // subset (0, 1, 1) constexpr auto idx6 = 0 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; - auto& sub6 = subsets[idx6]; + auto& sub6 = std::get<0>(subsets)[idx6]; sub6.set_morton(sub5.get_morton() + sub5.num_elem()); sub6.start_x = set.start_x; sub6.start_y = set.start_y + split_y[0]; @@ -198,11 +196,10 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub6.length_x = split_x[0]; sub6.length_y = split_y[1]; sub6.length_z = split_z[1]; - sub6.part_level = next_part_lev; // subset (1, 1, 1) constexpr auto idx7 = 1 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; - auto& sub7 = subsets[idx7]; + auto& sub7 = std::get<0>(subsets)[idx7]; sub7.set_morton(sub6.get_morton() + sub6.num_elem()); sub7.start_x = set.start_x + split_x[0]; sub7.start_y = set.start_y + split_y[0]; @@ -210,35 +207,32 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set) const -> std::ar sub7.length_x = split_x[1]; sub7.length_y = split_y[1]; sub7.length_z = split_z[1]; - sub7.part_level = next_part_lev; return subsets; } template -auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::array +auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set, uint16_t lev) const + -> std::tuple, uint16_t> { // This partition scheme is only used during initialization; no need to calculate morton offset. const auto split_x = std::array{set.length_x - set.length_x / 2, set.length_x / 2}; const auto split_y = std::array{set.length_y - set.length_y / 2, set.length_y / 2}; - std::array subsets; - for (auto& s : subsets) { - s.part_level = set.part_level; - if (split_x[1] > 0) - s.part_level++; - if (split_y[1] > 0) - s.part_level++; - } + const auto tmp = std::array{0, 1}; + lev += tmp[split_x[1] != 0]; + lev += tmp[split_y[1] != 0]; + auto subsets = std::tuple, uint16_t>(); + std::get<1>(subsets) = lev; const auto offsets = std::array{1, 2, 4}; // The actual figuring out where it starts/ends part... // // subset (0, 0, 0) size_t sub_i = 0 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; - auto& sub0 = subsets[sub_i]; + auto& sub0 = std::get<0>(subsets)[sub_i]; sub0.start_x = set.start_x; sub0.start_y = set.start_y; sub0.start_z = set.start_z; @@ -248,7 +242,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr // subset (1, 0, 0) sub_i = 1 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; - auto& sub1 = subsets[sub_i]; + auto& sub1 = std::get<0>(subsets)[sub_i]; sub1.start_x = set.start_x + split_x[0]; sub1.start_y = set.start_y; sub1.start_z = set.start_z; @@ -258,7 +252,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr // subset (0, 1, 0) sub_i = 0 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; - auto& sub2 = subsets[sub_i]; + auto& sub2 = std::get<0>(subsets)[sub_i]; sub2.start_x = set.start_x; sub2.start_y = set.start_y + split_y[0]; sub2.start_z = set.start_z; @@ -268,7 +262,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr // subset (1, 1, 0) sub_i = 1 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; - auto& sub3 = subsets[sub_i]; + auto& sub3 = std::get<0>(subsets)[sub_i]; sub3.start_x = set.start_x + split_x[0]; sub3.start_y = set.start_y + split_y[0]; sub3.start_z = set.start_z; @@ -280,24 +274,23 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set) const -> std::arr } template -auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set) const -> std::array +auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set, uint16_t lev) const + -> std::tuple, uint16_t> { // This partition scheme is only used during initialization; no need to calculate morton offset. const auto split_z = std::array{set.length_z - set.length_z / 2, set.length_z / 2}; + if (split_z[1] != 0) + lev++; - std::array subsets; - for (auto& s : subsets) { - s.part_level = set.part_level; - if (split_z[1] > 0) - s.part_level++; - } + auto subsets = std::tuple, uint16_t>(); + std::get<1>(subsets) = lev; // // The actual figuring out where it starts/ends part... // // subset (0, 0, 0) - auto& sub0 = subsets[0]; + auto& sub0 = std::get<0>(subsets)[0]; sub0.start_x = set.start_x; sub0.length_x = set.length_x; sub0.start_y = set.start_y; @@ -306,7 +299,7 @@ auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set) const -> std::arra sub0.length_z = split_z[0]; // subset (0, 0, 1) - auto& sub1 = subsets[1]; + auto& sub1 = std::get<0>(subsets)[1]; sub1.start_x = set.start_x; sub1.length_x = set.length_x; sub1.start_y = set.start_y; diff --git a/src/SPECK3D_INT_DEC.cpp b/src/SPECK3D_INT_DEC.cpp index c08500ed..f6b38ea6 100644 --- a/src/SPECK3D_INT_DEC.cpp +++ b/src/SPECK3D_INT_DEC.cpp @@ -79,7 +79,7 @@ void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t& counter, bool re template void sperr::SPECK3D_INT_DEC::m_code_S(size_t idx1, size_t idx2) { - auto subsets = m_partition_S_XYZ(m_LIS[idx1][idx2]); + auto [subsets, next_lev] = m_partition_S_XYZ(m_LIS[idx1][idx2], uint16_t(idx1)); const auto set_end = std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); const auto set_end_m1 = set_end - 1; @@ -98,10 +98,9 @@ void sperr::SPECK3D_INT_DEC::m_code_S(size_t idx1, size_t idx2) m_process_P(idx, sig_counter, read); } else { - const size_t newidx1 = it->part_level; - m_LIS[newidx1].emplace_back(*it); - const auto newidx2 = m_LIS[newidx1].size() - 1; - m_process_S(newidx1, newidx2, sig_counter, read); + m_LIS[next_lev].emplace_back(*it); + const auto newidx2 = m_LIS[next_lev].size() - 1; + m_process_S(next_lev, newidx2, sig_counter, read); } } } diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 934b40c7..c58c547d 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -36,7 +36,7 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) break; } default: { - auto subsets = m_partition_S_XYZ(set); + auto [subsets, lev] = m_partition_S_XYZ(set, 0); for (auto& sub : subsets) m_deposit_set(sub); } @@ -148,7 +148,7 @@ void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t& counter, bool ou template void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) { - auto subsets = m_partition_S_XYZ(m_LIS[idx1][idx2]); + auto [subsets, next_lev] = m_partition_S_XYZ(m_LIS[idx1][idx2], uint16_t(idx1)); // Since some subsets could be empty, let's put empty sets at the end. // @@ -170,10 +170,9 @@ void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) m_process_P(idx, sig_counter, output); } else { - const size_t newidx1 = it->part_level; - m_LIS[newidx1].emplace_back(*it); - const auto newidx2 = m_LIS[newidx1].size() - 1; - m_process_S(newidx1, newidx2, sig_counter, output); + m_LIS[next_lev].emplace_back(*it); + const auto newidx2 = m_LIS[next_lev].size() - 1; + m_process_S(next_lev, newidx2, sig_counter, output); } } } From 02530d49ab76afdc444d0ef6f926d01a11baa8b2 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Thu, 31 Aug 2023 14:38:11 -0600 Subject: [PATCH 08/23] minor --- src/SPECK3D_INT.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 314adc16..604c9024 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -116,6 +116,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co auto subsets = std::tuple, uint16_t>(); std::get<1>(subsets) = lev; constexpr auto offsets = std::array{1, 2, 4}; + auto morton_offset = set.get_morton(); // // The actual figuring out where it starts/ends part... @@ -123,7 +124,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (0, 0, 0) constexpr auto idx0 = 0 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; auto& sub0 = std::get<0>(subsets)[idx0]; - sub0.set_morton(set.get_morton()); + sub0.set_morton(morton_offset); sub0.start_x = set.start_x; sub0.start_y = set.start_y; sub0.start_z = set.start_z; @@ -134,7 +135,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (1, 0, 0) constexpr auto idx1 = 1 * offsets[0] + 0 * offsets[1] + 0 * offsets[2]; auto& sub1 = std::get<0>(subsets)[idx1]; - sub1.set_morton(sub0.get_morton() + sub0.num_elem()); + morton_offset += sub0.num_elem(); + sub1.set_morton(morton_offset); sub1.start_x = set.start_x + split_x[0]; sub1.start_y = set.start_y; sub1.start_z = set.start_z; @@ -145,7 +147,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (0, 1, 0) constexpr auto idx2 = 0 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; auto& sub2 = std::get<0>(subsets)[idx2]; - sub2.set_morton(sub1.get_morton() + sub1.num_elem()); + morton_offset += sub1.num_elem(); + sub2.set_morton(morton_offset); sub2.start_x = set.start_x; sub2.start_y = set.start_y + split_y[0]; sub2.start_z = set.start_z; @@ -156,7 +159,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (1, 1, 0) constexpr auto idx3 = 1 * offsets[0] + 1 * offsets[1] + 0 * offsets[2]; auto& sub3 = std::get<0>(subsets)[idx3]; - sub3.set_morton(sub2.get_morton() + sub2.num_elem()); + morton_offset += sub2.num_elem(); + sub3.set_morton(morton_offset); sub3.start_x = set.start_x + split_x[0]; sub3.start_y = set.start_y + split_y[0]; sub3.start_z = set.start_z; @@ -167,7 +171,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (0, 0, 1) constexpr auto idx4 = 0 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; auto& sub4 = std::get<0>(subsets)[idx4]; - sub4.set_morton(sub3.get_morton() + sub3.num_elem()); + morton_offset += sub3.num_elem(); + sub4.set_morton(morton_offset); sub4.start_x = set.start_x; sub4.start_y = set.start_y; sub4.start_z = set.start_z + split_z[0]; @@ -178,7 +183,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (1, 0, 1) constexpr auto idx5 = 1 * offsets[0] + 0 * offsets[1] + 1 * offsets[2]; auto& sub5 = std::get<0>(subsets)[idx5]; - sub5.set_morton(sub4.get_morton() + sub4.num_elem()); + morton_offset += sub4.num_elem(); + sub5.set_morton(morton_offset); sub5.start_x = set.start_x + split_x[0]; sub5.start_y = set.start_y; sub5.start_z = set.start_z + split_z[0]; @@ -189,7 +195,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (0, 1, 1) constexpr auto idx6 = 0 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; auto& sub6 = std::get<0>(subsets)[idx6]; - sub6.set_morton(sub5.get_morton() + sub5.num_elem()); + morton_offset += sub5.num_elem(); + sub6.set_morton(morton_offset); sub6.start_x = set.start_x; sub6.start_y = set.start_y + split_y[0]; sub6.start_z = set.start_z + split_z[0]; @@ -200,7 +207,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co // subset (1, 1, 1) constexpr auto idx7 = 1 * offsets[0] + 1 * offsets[1] + 1 * offsets[2]; auto& sub7 = std::get<0>(subsets)[idx7]; - sub7.set_morton(sub6.get_morton() + sub6.num_elem()); + morton_offset += sub6.num_elem(); + sub7.set_morton(morton_offset); sub7.start_x = set.start_x + split_x[0]; sub7.start_y = set.start_y + split_y[0]; sub7.start_z = set.start_z + split_z[0]; From 2b469a11eee7ab4fcbd728cae96c2af9774eae73 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Thu, 31 Aug 2023 17:17:27 -0600 Subject: [PATCH 09/23] minor --- include/SPECK3D_INT.h | 6 ------ src/SPECK3D_INT_DEC.cpp | 2 +- src/SPECK3D_INT_ENC.cpp | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 3b6c372f..88548ecb 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -39,18 +39,12 @@ class Set3D { { std::memcpy(m_morton.data(), &val, sizeof(m_morton)); } - auto is_pixel() const -> bool - { - return (length_x == 1 && length_y == 1 && length_z == 1); - } auto is_empty() const -> bool { return (length_z == 0 || length_y == 0 || length_x == 0); } void make_empty() { - length_x = 0; - length_y = 0; length_z = 0; } auto num_elem() const -> size_t diff --git a/src/SPECK3D_INT_DEC.cpp b/src/SPECK3D_INT_DEC.cpp index f6b38ea6..d7f0149d 100644 --- a/src/SPECK3D_INT_DEC.cpp +++ b/src/SPECK3D_INT_DEC.cpp @@ -92,7 +92,7 @@ void sperr::SPECK3D_INT_DEC::m_code_S(size_t idx1, size_t idx2) if (it == set_end_m1 && sig_counter == 0) { read = false; } - if (it->is_pixel()) { + if (it->num_elem() == 1) { auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; m_LIP_mask.write_true(idx); m_process_P(idx, sig_counter, read); diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index c58c547d..d39c1241 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -164,7 +164,7 @@ void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) if (it == set_end_m1 && sig_counter == 0) output = false; - if (it->is_pixel()) { + if (it->num_elem() == 1) { auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; m_LIP_mask.write_true(idx); m_process_P(idx, sig_counter, output); From 7d4f1f61a5a0c67707ceb90d8d86c334a4bc747d Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Fri, 1 Sep 2023 15:34:26 -0600 Subject: [PATCH 10/23] minor --- include/SPECK3D_INT.h | 21 ++++++--------------- src/SPECK3D_INT.cpp | 14 +++++++------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 88548ecb..816c59c5 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -35,18 +35,9 @@ class Set3D { std::memcpy(&tmp, m_morton.data(), sizeof(m_morton)); return tmp; } - void set_morton(uint64_t val) - { - std::memcpy(m_morton.data(), &val, sizeof(m_morton)); - } - auto is_empty() const -> bool - { - return (length_z == 0 || length_y == 0 || length_x == 0); - } - void make_empty() - { - length_z = 0; - } + void set_morton(uint64_t val) { std::memcpy(m_morton.data(), &val, sizeof(m_morton)); } + auto is_empty() const -> bool { return (length_z == 0 || length_y == 0 || length_x == 0); } + void make_empty() { length_z = 0; } auto num_elem() const -> size_t { return (size_t{length_x} * size_t{length_y} * size_t{length_z}); @@ -72,9 +63,9 @@ class SPECK3D_INT : public SPECK_INT { void m_initialize_lists() override; // Divide a Set3D into 8, 4, or 2 smaller subsets. - auto m_partition_S_XYZ(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; - auto m_partition_S_XY(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; - auto m_partition_S_Z(const Set3D&, uint16_t) const -> std::tuple, uint16_t>; + auto m_partition_S_XYZ(Set3D, uint16_t) const -> std::tuple, uint16_t>; + auto m_partition_S_XY(Set3D, uint16_t) const -> std::tuple, uint16_t>; + auto m_partition_S_Z(Set3D, uint16_t) const -> std::tuple, uint16_t>; // // SPECK3D_INT specific data members diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 604c9024..f85edcf1 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -36,7 +36,7 @@ void sperr::SPECK3D_INT::m_initialize_lists() // subsets and put them in the LIS accordingly. // Note that it truncates 64-bit ints to 16-bit ints here, but should be OK. Set3D big; - big.length_x = static_cast(m_dims[0]); + big.length_x = static_cast(m_dims[0]); big.length_y = static_cast(m_dims[1]); big.length_z = static_cast(m_dims[2]); @@ -97,7 +97,7 @@ void sperr::SPECK3D_INT::m_initialize_lists() } template -auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) const +auto sperr::SPECK3D_INT::m_partition_S_XYZ(Set3D set, uint16_t lev) const -> std::tuple, uint16_t> { // Integer promotion rules (https://en.cppreference.com/w/c/language/conversion) say that types @@ -114,7 +114,7 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co lev += tmp[split_z[1] != 0]; auto subsets = std::tuple, uint16_t>(); - std::get<1>(subsets) = lev; + std::get<1>(subsets) = lev; constexpr auto offsets = std::array{1, 2, 4}; auto morton_offset = set.get_morton(); @@ -220,8 +220,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XYZ(const Set3D& set, uint16_t lev) co } template -auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set, uint16_t lev) const - -> std::tuple, uint16_t> +auto sperr::SPECK3D_INT::m_partition_S_XY(Set3D set, uint16_t lev) const + -> std::tuple, uint16_t> { // This partition scheme is only used during initialization; no need to calculate morton offset. @@ -282,8 +282,8 @@ auto sperr::SPECK3D_INT::m_partition_S_XY(const Set3D& set, uint16_t lev) con } template -auto sperr::SPECK3D_INT::m_partition_S_Z(const Set3D& set, uint16_t lev) const - -> std::tuple, uint16_t> +auto sperr::SPECK3D_INT::m_partition_S_Z(Set3D set, uint16_t lev) const + -> std::tuple, uint16_t> { // This partition scheme is only used during initialization; no need to calculate morton offset. From 2301a50b3e3b0b79ea2a8bb5451437ac45142f19 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Fri, 1 Sep 2023 15:45:16 -0600 Subject: [PATCH 11/23] minor --- include/SPECK3D_INT.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 816c59c5..8cc299b0 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -38,10 +38,7 @@ class Set3D { void set_morton(uint64_t val) { std::memcpy(m_morton.data(), &val, sizeof(m_morton)); } auto is_empty() const -> bool { return (length_z == 0 || length_y == 0 || length_x == 0); } void make_empty() { length_z = 0; } - auto num_elem() const -> size_t - { - return (size_t{length_x} * size_t{length_y} * size_t{length_z}); - } + auto num_elem() const -> size_t { return (size_t{length_x} * length_y * length_z); } }; // From ad61f9ef7ac3e4e50ef3f34c9940798ffcde2cf0 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sat, 2 Sep 2023 03:00:30 -0600 Subject: [PATCH 12/23] move 3 functions from 3D encoder/decoder to SPECK3D_INT; reduce code redundancy --- include/SPECK1D_INT_ENC.h | 4 +- include/SPECK3D_INT.h | 12 +++--- include/SPECK3D_INT_DEC.h | 10 ++--- include/SPECK3D_INT_ENC.h | 12 ++---- src/SPECK3D_INT.cpp | 71 +++++++++++++++++++++++++++++++++- src/SPECK3D_INT_DEC.cpp | 68 --------------------------------- src/SPECK3D_INT_ENC.cpp | 80 ++------------------------------------- 7 files changed, 91 insertions(+), 166 deletions(-) diff --git a/include/SPECK1D_INT_ENC.h b/include/SPECK1D_INT_ENC.h index ddc23e60..b55ae84e 100644 --- a/include/SPECK1D_INT_ENC.h +++ b/include/SPECK1D_INT_ENC.h @@ -27,8 +27,8 @@ class SPECK1D_INT_ENC : public SPECK1D_INT { void m_sorting_pass() override; - void m_process_S(size_t idx1, size_t idx2, SigType, size_t& counter, bool); - void m_process_P(size_t idx, SigType, size_t& counter, bool); + void m_process_S(size_t idx1, size_t idx2, SigType, size_t& counter, bool output); + void m_process_P(size_t idx, SigType, size_t& counter, bool output); void m_code_S(size_t idx1, size_t idx2, std::array); // Decide if a set is significant or not. diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 8cc299b0..51937455 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -56,10 +56,15 @@ class SPECK3D_INT : public SPECK_INT { using SPECK_INT::m_coeff_buf; using SPECK_INT::m_bit_buffer; - void m_clean_LIS() override; void m_initialize_lists() override; + void m_sorting_pass() override; + void m_clean_LIS() override; - // Divide a Set3D into 8, 4, or 2 smaller subsets. + virtual void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool) = 0; + virtual void m_process_P(size_t idx, size_t& counter, bool) = 0; + virtual void m_additional_initialization() = 0; + + void m_code_S(size_t idx1, size_t idx2); auto m_partition_S_XYZ(Set3D, uint16_t) const -> std::tuple, uint16_t>; auto m_partition_S_XY(Set3D, uint16_t) const -> std::tuple, uint16_t>; auto m_partition_S_Z(Set3D, uint16_t) const -> std::tuple, uint16_t>; @@ -68,9 +73,6 @@ class SPECK3D_INT : public SPECK_INT { // SPECK3D_INT specific data members // std::vector> m_LIS; - - // Experiment with morton curves. - bool m_morton_valid = false; }; }; // namespace sperr diff --git a/include/SPECK3D_INT_DEC.h b/include/SPECK3D_INT_DEC.h index d9122c7a..2b42ffa0 100644 --- a/include/SPECK3D_INT_DEC.h +++ b/include/SPECK3D_INT_DEC.h @@ -21,12 +21,12 @@ class SPECK3D_INT_DEC : public SPECK3D_INT { using SPECK_INT::m_sign_array; using SPECK3D_INT::m_LIS; using SPECK3D_INT::m_partition_S_XYZ; + using SPECK3D_INT::m_code_S; + ; - void m_sorting_pass() override; - - void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool); - void m_process_P(size_t idx, size_t& counter, bool); - void m_code_S(size_t idx1, size_t idx2); + void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool read) override; + void m_process_P(size_t idx, size_t& counter, bool read) override; + void m_additional_initialization() override{}; // empty function }; }; // namespace sperr diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index d66b0086..2a02eb37 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -31,18 +31,14 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { using SPECK_INT::m_sign_array; using SPECK3D_INT::m_LIS; using SPECK3D_INT::m_partition_S_XYZ; - using SPECK3D_INT::m_morton_valid; + using SPECK3D_INT::m_code_S; - void m_sorting_pass() override; - - void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output); - void m_process_P(size_t idx, size_t& counter, bool output); - void m_code_S(size_t idx1, size_t idx2); + void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output) override; + void m_process_P(size_t idx, size_t& counter, bool output) override; + void m_additional_initialization() override; // Data structures and functions for morton data layout. - // Note: `m_morton_valid` was initialized to be false in `SPECk3D_INT::m_initialize_lists()`. vecui_type m_morton_buf; - void m_construct_morton_buf(); void m_deposit_set(const Set3D&); }; diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index f85edcf1..51cac32e 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -92,8 +92,75 @@ void sperr::SPECK3D_INT::m_initialize_lists() // it at the front of it's corresponding vector. One-time expense. m_LIS[curr_lev].insert(m_LIS[curr_lev].begin(), big); - // The morton curves are not constructed yet! - m_morton_valid = false; + // Encoder and decoder might have different additional tasks. + m_additional_initialization(); +} + +template +void sperr::SPECK3D_INT::m_sorting_pass() +{ + // Since we have a separate representation of LIP, let's process that list first! + // + const auto bits_x64 = m_LIP_mask.size() - m_LIP_mask.size() % 64; + + for (size_t i = 0; i < bits_x64; i += 64) { + const auto value = m_LIP_mask.read_long(i); + if (value != 0) { + for (size_t j = 0; j < 64; j++) { + if ((value >> j) & uint64_t{1}) { + size_t dummy = 0; + m_process_P(i + j, dummy, true); + } + } + } + } + for (auto i = bits_x64; i < m_LIP_mask.size(); i++) { + if (m_LIP_mask.read_bit(i)) { + size_t dummy = 0; + m_process_P(i, dummy, true); + } + } + + // Then we process regular sets in LIS. + // + for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { + auto idx1 = m_LIS.size() - tmp; + for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { + size_t dummy = 0; + m_process_S(idx1, idx2, dummy, true); + } + } +} + +template +void sperr::SPECK3D_INT::m_code_S(size_t idx1, size_t idx2) +{ + auto [subsets, next_lev] = m_partition_S_XYZ(m_LIS[idx1][idx2], uint16_t(idx1)); + + // Since some subsets could be empty, let's put empty sets at the end. + const auto set_end = + std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); + const auto set_end_m1 = set_end - 1; + + size_t sig_counter = 0; + for (auto it = subsets.begin(); it != set_end; ++it) { + // If we're looking at the last subset, and no prior subset is found to be + // significant, then we know that this last one *is* significant. + bool need_decide = true; + if (it == set_end_m1 && sig_counter == 0) + need_decide = false; + + if (it->num_elem() == 1) { + auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; + m_LIP_mask.write_true(idx); + m_process_P(idx, sig_counter, need_decide); + } + else { + m_LIS[next_lev].emplace_back(*it); + const auto newidx2 = m_LIS[next_lev].size() - 1; + m_process_S(next_lev, newidx2, sig_counter, need_decide); + } + } } template diff --git a/src/SPECK3D_INT_DEC.cpp b/src/SPECK3D_INT_DEC.cpp index d7f0149d..aac02bb3 100644 --- a/src/SPECK3D_INT_DEC.cpp +++ b/src/SPECK3D_INT_DEC.cpp @@ -5,50 +5,12 @@ #include // std::memcpy() #include -template -void sperr::SPECK3D_INT_DEC::m_sorting_pass() -{ - // Since we have a separate representation of LIP, let's process that list first - // - const auto bits_x64 = m_LIP_mask.size() - m_LIP_mask.size() % 64; - - for (size_t i = 0; i < bits_x64; i += 64) { - const auto value = m_LIP_mask.read_long(i); - if (value != 0) { - for (size_t j = 0; j < 64; j++) { - if ((value >> j) & uint64_t{1}) { - size_t dummy = 0; - m_process_P(i + j, dummy, true); - } - } - } - } - for (auto i = bits_x64; i < m_LIP_mask.size(); i++) { - if (m_LIP_mask.read_bit(i)) { - size_t dummy = 0; - m_process_P(i, dummy, true); - } - } - - // Then we process regular sets in LIS. - // - for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { - // From the end of m_LIS to its front - size_t idx1 = m_LIS.size() - tmp; - for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { - size_t dummy = 0; - m_process_S(idx1, idx2, dummy, true); - } - } -} - template void sperr::SPECK3D_INT_DEC::m_process_S(size_t idx1, size_t idx2, size_t& counter, bool read) { auto& set = m_LIS[idx1][idx2]; bool is_sig = true; - if (read) is_sig = m_bit_buffer.rbit(); @@ -63,7 +25,6 @@ template void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t& counter, bool read) { bool is_sig = true; - if (read) is_sig = m_bit_buffer.rbit(); @@ -76,35 +37,6 @@ void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t& counter, bool re } } -template -void sperr::SPECK3D_INT_DEC::m_code_S(size_t idx1, size_t idx2) -{ - auto [subsets, next_lev] = m_partition_S_XYZ(m_LIS[idx1][idx2], uint16_t(idx1)); - const auto set_end = - std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); - const auto set_end_m1 = set_end - 1; - size_t sig_counter = 0; - - for (auto it = subsets.begin(); it != set_end; ++it) { - // If we're looking at the last subset, and no prior subset is found to be - // significant, then we know that this last one *is* significant. - bool read = true; - if (it == set_end_m1 && sig_counter == 0) { - read = false; - } - if (it->num_elem() == 1) { - auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; - m_LIP_mask.write_true(idx); - m_process_P(idx, sig_counter, read); - } - else { - m_LIS[next_lev].emplace_back(*it); - const auto newidx2 = m_LIS[next_lev].size() - 1; - m_process_S(next_lev, newidx2, sig_counter, read); - } - } -} - template class sperr::SPECK3D_INT_DEC; template class sperr::SPECK3D_INT_DEC; template class sperr::SPECK3D_INT_DEC; diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index d39c1241..ae61a5f9 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -44,11 +44,13 @@ void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) } template -void sperr::SPECK3D_INT_ENC::m_construct_morton_buf() +void sperr::SPECK3D_INT_ENC::m_additional_initialization() { + // For the encoder, this function re-organizes the coefficients in a morton order. + // m_morton_buf.resize(m_dims[0] * m_dims[1] * m_dims[2]); - // The same traversing order as in `m_sorting_pass()` + // The same traversing order as in `SPECK3D_INT::m_sorting_pass()` size_t morton_offset = 0; for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { auto idx1 = m_LIS.size() - tmp; @@ -61,48 +63,6 @@ void sperr::SPECK3D_INT_ENC::m_construct_morton_buf() } } -template -void sperr::SPECK3D_INT_ENC::m_sorting_pass() -{ - if (!m_morton_valid) { - m_construct_morton_buf(); - m_morton_valid = true; - } - - // Since we have a separate representation of LIP, let's process that list first! - // - const auto bits_x64 = m_LIP_mask.size() - m_LIP_mask.size() % 64; - - for (size_t i = 0; i < bits_x64; i += 64) { - const auto value = m_LIP_mask.read_long(i); - if (value != 0) { - for (size_t j = 0; j < 64; j++) { - if ((value >> j) & uint64_t{1}) { - size_t dummy = 0; - m_process_P(i + j, dummy, true); - } - } - } - } - for (auto i = bits_x64; i < m_LIP_mask.size(); i++) { - if (m_LIP_mask.read_bit(i)) { - size_t dummy = 0; - m_process_P(i, dummy, true); - } - } - - // Then we process regular sets in LIS. - // (From the end of m_LIS to its front.) - // - for (size_t tmp = 1; tmp <= m_LIS.size(); tmp++) { - auto idx1 = m_LIS.size() - tmp; - for (size_t idx2 = 0; idx2 < m_LIS[idx1].size(); idx2++) { - size_t dummy = 0; - m_process_S(idx1, idx2, dummy, true); - } - } -} - template void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output) { @@ -145,38 +105,6 @@ void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t& counter, bool ou } } -template -void sperr::SPECK3D_INT_ENC::m_code_S(size_t idx1, size_t idx2) -{ - auto [subsets, next_lev] = m_partition_S_XYZ(m_LIS[idx1][idx2], uint16_t(idx1)); - - // Since some subsets could be empty, let's put empty sets at the end. - // - const auto set_end = - std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); - const auto set_end_m1 = set_end - 1; - - size_t sig_counter = 0; - for (auto it = subsets.begin(); it != set_end; ++it) { - // If we're looking at the last subset, and no prior subset is found to be - // significant, then we know that this last one *is* significant. - bool output = true; - if (it == set_end_m1 && sig_counter == 0) - output = false; - - if (it->num_elem() == 1) { - auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; - m_LIP_mask.write_true(idx); - m_process_P(idx, sig_counter, output); - } - else { - m_LIS[next_lev].emplace_back(*it); - const auto newidx2 = m_LIS[next_lev].size() - 1; - m_process_S(next_lev, newidx2, sig_counter, output); - } - } -} - template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; From 4ae77498acdecdee84615f25634b9af678f160bb Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sat, 2 Sep 2023 03:12:59 -0600 Subject: [PATCH 13/23] minor --- include/SPECK3D_INT_DEC.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/SPECK3D_INT_DEC.h b/include/SPECK3D_INT_DEC.h index 2b42ffa0..1b139c67 100644 --- a/include/SPECK3D_INT_DEC.h +++ b/include/SPECK3D_INT_DEC.h @@ -15,14 +15,11 @@ class SPECK3D_INT_DEC : public SPECK3D_INT { // Bring members from parent classes to this derived class. // using SPECK_INT::m_LIP_mask; - using SPECK_INT::m_dims; using SPECK_INT::m_LSP_new; using SPECK_INT::m_bit_buffer; using SPECK_INT::m_sign_array; using SPECK3D_INT::m_LIS; - using SPECK3D_INT::m_partition_S_XYZ; using SPECK3D_INT::m_code_S; - ; void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool read) override; void m_process_P(size_t idx, size_t& counter, bool read) override; From d8ea20e9ffc2ebeafbd47782242b2081006a96be Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sun, 3 Sep 2023 14:50:46 -0600 Subject: [PATCH 14/23] remove the use of SetType in SPECK2D_INT --- include/SPECK1D_INT.h | 5 +++++ include/SPECK2D_INT.h | 18 +++++------------- include/SPECK2D_INT_ENC.h | 2 +- src/SPECK2D_INT.cpp | 19 +++---------------- src/SPECK2D_INT_DEC.cpp | 2 +- src/SPECK2D_INT_ENC.cpp | 4 ++-- 6 files changed, 17 insertions(+), 33 deletions(-) diff --git a/include/SPECK1D_INT.h b/include/SPECK1D_INT.h index 15587ac9..d9f484ba 100644 --- a/include/SPECK1D_INT.h +++ b/include/SPECK1D_INT.h @@ -27,6 +27,11 @@ class SPECK1D_INT : public SPECK_INT { using SPECK_INT::m_dims; using SPECK_INT::m_coeff_buf; + // The 1D case is different from 3D and 2D cases in that it implements additional logic that + // infers the significance of subsets by where the significant point is. With this + // consideration, functions such as m_process_S() and m_process_P() have different signatures + // during decoding/encoding, so they're implemented in their respective subclasses. + // void m_clean_LIS() override; void m_initialize_lists() override; auto m_partition_set(const Set1D&) const -> std::array; diff --git a/include/SPECK2D_INT.h b/include/SPECK2D_INT.h index a02a5531..b4de1933 100644 --- a/include/SPECK2D_INT.h +++ b/include/SPECK2D_INT.h @@ -12,11 +12,11 @@ class Set2D { uint32_t length_x = 0; uint32_t length_y = 0; uint16_t part_level = 0; - SetType type = SetType::TypeS; public: - auto is_pixel() const -> bool; - auto is_empty() const -> bool; + auto is_pixel() const -> bool { return (length_x == 1 && length_y == 1); }; + auto is_empty() const -> bool { return (length_x == 0 || length_y == 0); }; + void make_empty() { length_x = 0; }; }; // @@ -34,14 +34,6 @@ class SPECK2D_INT : public SPECK_INT { using SPECK_INT::m_coeff_buf; using SPECK_INT::m_bit_buffer; - // The 2D case is different from 3D and 1D cases in that it doesn't implement the logic that - // infers the significance of subsets by where the significant point is. I.e., the decide - // set significance functions return only true/false, but not the index of the first - // significant point. With this simplification, the m_process_S()/m_process_P()/m_process_I() - // functions have the same signature, so they can be virtual, and m_sorting_pass()/m_code_S/ - // m_code_I() are really the same when encoding and decoding, so they can be implemented - // here instead of in SPECK2D_INT_ENC/SPECK2D_INT_DEC. - // void m_sorting_pass() override; void m_code_S(size_t idx1, size_t idx2); void m_code_I(); @@ -51,7 +43,7 @@ class SPECK2D_INT : public SPECK_INT { virtual void m_process_I(bool need_decide) = 0; void m_clean_LIS() override; - auto m_partition_S(Set2D) const -> std::array; + auto m_partition_S(const Set2D&) const -> std::array; auto m_partition_I() -> std::array; void m_initialize_lists() override; @@ -59,7 +51,7 @@ class SPECK2D_INT : public SPECK_INT { // SPECK2D_INT specific data members // std::vector> m_LIS; - Set2D m_I = {0, 0, 0, 0, 0, SetType::TypeI}; + Set2D m_I; }; }; // namespace sperr diff --git a/include/SPECK2D_INT_ENC.h b/include/SPECK2D_INT_ENC.h index 0015bd4f..b2e25f57 100644 --- a/include/SPECK2D_INT_ENC.h +++ b/include/SPECK2D_INT_ENC.h @@ -30,7 +30,7 @@ class SPECK2D_INT_ENC : public SPECK2D_INT { void m_process_P(size_t idx, size_t& counter, bool need_decide) override; void m_process_I(bool need_decide) override; - auto m_decide_S_significance(Set2D) const -> bool; + auto m_decide_S_significance(const Set2D&) const -> bool; auto m_decide_I_significance() const -> bool; }; diff --git a/src/SPECK2D_INT.cpp b/src/SPECK2D_INT.cpp index e4ea5f01..beed8455 100644 --- a/src/SPECK2D_INT.cpp +++ b/src/SPECK2D_INT.cpp @@ -3,16 +3,6 @@ #include #include -auto sperr::Set2D::is_pixel() const -> bool -{ - return (length_x == 1 && length_y == 1); -} - -auto sperr::Set2D::is_empty() const -> bool -{ - return (length_x == 0 || length_y == 0); -} - template void sperr::SPECK2D_INT::m_sorting_pass() { @@ -99,13 +89,13 @@ void sperr::SPECK2D_INT::m_clean_LIS() { for (auto& list : m_LIS) { auto it = std::remove_if(list.begin(), list.end(), - [](auto& s) { return s.type == SetType::Garbage; }); + [](auto& s) { return s.is_empty(); }); list.erase(it, list.end()); } } template -auto sperr::SPECK2D_INT::m_partition_S(Set2D set) const -> std::array +auto sperr::SPECK2D_INT::m_partition_S(const Set2D& set) const -> std::array { auto subsets = std::array(); @@ -123,7 +113,6 @@ auto sperr::SPECK2D_INT::m_partition_S(Set2D set) const -> std::array::m_partition_S(Set2D set) const -> std::array::m_partition_S(Set2D set) const -> std::array::m_initialize_lists() auto num_of_xforms = sperr::num_of_xforms(std::min(m_dims[0], m_dims[1])); auto [approx_x, detail_x] = sperr::calc_approx_detail_len(m_dims[0], num_of_xforms); auto [approx_y, detail_y] = sperr::calc_approx_detail_len(m_dims[1], num_of_xforms); - auto root = Set2D{0, 0, 0, 0, 0, SetType::TypeS}; + auto root = Set2D(); root.length_x = approx_x; root.length_y = approx_y; root.part_level = num_of_xforms; diff --git a/src/SPECK2D_INT_DEC.cpp b/src/SPECK2D_INT_DEC.cpp index 304de96e..0b3f6798 100644 --- a/src/SPECK2D_INT_DEC.cpp +++ b/src/SPECK2D_INT_DEC.cpp @@ -18,7 +18,7 @@ void sperr::SPECK2D_INT_DEC::m_process_S(size_t idx1, if (is_sig) { counter++; m_code_S(idx1, idx2); - set.type = SetType::Garbage; + set.make_empty(); } } diff --git a/src/SPECK2D_INT_ENC.cpp b/src/SPECK2D_INT_ENC.cpp index dbd8a7ee..a1df49a6 100644 --- a/src/SPECK2D_INT_ENC.cpp +++ b/src/SPECK2D_INT_ENC.cpp @@ -21,7 +21,7 @@ void sperr::SPECK2D_INT_ENC::m_process_S(size_t idx1, if (is_sig) { counter++; m_code_S(idx1, idx2); - set.type = SetType::Garbage; + set.make_empty(); } } @@ -60,7 +60,7 @@ void sperr::SPECK2D_INT_ENC::m_process_I(bool need_decide) } template -auto sperr::SPECK2D_INT_ENC::m_decide_S_significance(Set2D set) const -> bool +auto sperr::SPECK2D_INT_ENC::m_decide_S_significance(const Set2D& set) const -> bool { assert(!set.is_empty()); From 8f42e882fab8ca7b8885bd8da7126e3f89c1cbf3 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sun, 3 Sep 2023 14:57:13 -0600 Subject: [PATCH 15/23] Remove the use of SetType from SPECK1D, thus from the codebase entirely --- include/SPECK1D_INT.h | 1 - include/sperr_helper.h | 2 -- src/SPECK1D_INT.cpp | 2 +- src/SPECK1D_INT_DEC.cpp | 2 +- src/SPECK1D_INT_ENC.cpp | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/SPECK1D_INT.h b/include/SPECK1D_INT.h index d9f484ba..3cb648c7 100644 --- a/include/SPECK1D_INT.h +++ b/include/SPECK1D_INT.h @@ -10,7 +10,6 @@ class Set1D { uint64_t start = 0; uint64_t length = 0; uint16_t part_level = 0; - SetType type = SetType::TypeS; // Only used to indicate garbage status }; // diff --git a/include/sperr_helper.h b/include/sperr_helper.h index 495d7193..823de72d 100644 --- a/include/sperr_helper.h +++ b/include/sperr_helper.h @@ -39,8 +39,6 @@ using dims_type = std::array; // enum class SigType : unsigned char { Insig, Sig, NewlySig, Dunno, Garbage }; -enum class SetType : unsigned char { TypeS, TypeI, Garbage }; - enum class UINTType : unsigned char { UINT8, UINT16, UINT32, UINT64 }; enum class CompMode : unsigned char { PSNR, PWE, Rate, Unknown }; diff --git a/src/SPECK1D_INT.cpp b/src/SPECK1D_INT.cpp index 06f1bf04..1d11f76c 100644 --- a/src/SPECK1D_INT.cpp +++ b/src/SPECK1D_INT.cpp @@ -10,7 +10,7 @@ void sperr::SPECK1D_INT::m_clean_LIS() { for (auto& list : m_LIS) { auto it = std::remove_if(list.begin(), list.end(), - [](const auto& s) { return s.type == SetType::Garbage; }); + [](const auto& s) { return s.length == 0; }); list.erase(it, list.end()); } } diff --git a/src/SPECK1D_INT_DEC.cpp b/src/SPECK1D_INT_DEC.cpp index 0099792a..c921b68c 100644 --- a/src/SPECK1D_INT_DEC.cpp +++ b/src/SPECK1D_INT_DEC.cpp @@ -54,7 +54,7 @@ void sperr::SPECK1D_INT_DEC::m_process_S(size_t idx1, size_t idx2, size_t& co if (is_sig) { counter++; // Let's increment the counter first! m_code_S(idx1, idx2); - set.type = SetType::Garbage; // this current set is gonna be discarded. + set.length = 0; // this current set is gonna be discarded. } } diff --git a/src/SPECK1D_INT_ENC.cpp b/src/SPECK1D_INT_ENC.cpp index d16d4a4f..9485ce4f 100644 --- a/src/SPECK1D_INT_ENC.cpp +++ b/src/SPECK1D_INT_ENC.cpp @@ -80,7 +80,7 @@ void sperr::SPECK1D_INT_ENC::m_process_S(size_t idx1, if (sig == SigType::Sig) { counter++; // Let's increment the counter first! m_code_S(idx1, idx2, subset_sigs); - set.type = SetType::Garbage; // this current set is gonna be discarded. + set.length = 0; // this current set is gonna be discarded. } } From fa2ab03e3de0025cc7e78c1a89593bcb091ee764 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sun, 3 Sep 2023 15:37:48 -0600 Subject: [PATCH 16/23] reduce the size of Set1D down to 16 bytes --- include/SPECK1D_INT.h | 33 ++++++++++++++++++++++++++++++--- include/SPECK3D_INT.h | 2 +- src/SPECK1D_INT.cpp | 24 ++++++++++++++---------- src/SPECK1D_INT_DEC.cpp | 22 +++++++++++----------- src/SPECK1D_INT_ENC.cpp | 30 +++++++++++++++--------------- 5 files changed, 71 insertions(+), 40 deletions(-) diff --git a/include/SPECK1D_INT.h b/include/SPECK1D_INT.h index 3cb648c7..45f92fb6 100644 --- a/include/SPECK1D_INT.h +++ b/include/SPECK1D_INT.h @@ -3,13 +3,40 @@ #include "SPECK_INT.h" +#include // std::memcpy() + namespace sperr { class Set1D { + // In an effort to reduce the object size of Set1D, I choose to store only the first 7 bytes of + // both the `start` and `length` information of a Set1D. Using another 2 bytes to store the + // `part_level` info, this object fits in 16 bytes nicely. + // + private: + std::array m_16 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + public: - uint64_t start = 0; - uint64_t length = 0; - uint16_t part_level = 0; + void set_start(uint64_t val) { std::memcpy(m_16.data(), &val, 7); }; + void set_length(uint64_t val) { std::memcpy(m_16.data() + 7, &val, 7); }; + void set_level(uint16_t val) { std::memcpy(m_16.data() + 14, &val, 2); }; + auto get_start() const -> uint64_t + { + auto val = uint64_t{0}; + std::memcpy(&val, m_16.data(), 7); + return val; + } + auto get_length() const -> uint64_t + { + auto val = uint64_t{0}; + std::memcpy(&val, m_16.data() + 7, 7); + return val; + } + auto get_level() const -> uint16_t + { + auto val = uint16_t{0}; + std::memcpy(&val, m_16.data() + 14, 2); + return val; + } }; // diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index 51937455..ab89674b 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -3,7 +3,7 @@ #include "SPECK_INT.h" -#include // std::memcpy +#include // std::memcpy() #include namespace sperr { diff --git a/src/SPECK1D_INT.cpp b/src/SPECK1D_INT.cpp index 1d11f76c..6b2961b7 100644 --- a/src/SPECK1D_INT.cpp +++ b/src/SPECK1D_INT.cpp @@ -10,7 +10,7 @@ void sperr::SPECK1D_INT::m_clean_LIS() { for (auto& list : m_LIS) { auto it = std::remove_if(list.begin(), list.end(), - [](const auto& s) { return s.length == 0; }); + [](const auto& s) { return s.get_length() == 0; }); list.erase(it, list.end()); } } @@ -29,26 +29,30 @@ void sperr::SPECK1D_INT::m_initialize_lists() // Put in two sets, each representing a half of the long array. Set1D set; - set.length = total_len; // Set represents the whole 1D array. + set.set_length(total_len); // Set represents the whole 1D array. auto sets = m_partition_set(set); - m_LIS[sets[0].part_level].emplace_back(sets[0]); - m_LIS[sets[1].part_level].emplace_back(sets[1]); + m_LIS[sets[0].get_level()].emplace_back(sets[0]); + m_LIS[sets[1].get_level()].emplace_back(sets[1]); } template auto sperr::SPECK1D_INT::m_partition_set(const Set1D& set) const -> std::array { + const auto start = set.get_start(); + const auto length = set.get_length(); + const auto level = set.get_level(); std::array subsets; + // Prepare the 1st set auto& set1 = subsets[0]; - set1.start = set.start; - set1.length = set.length - set.length / 2; - set1.part_level = set.part_level + 1; + set1.set_start(start); + set1.set_length(length - length / 2); + set1.set_level(level + 1); // Prepare the 2nd set auto& set2 = subsets[1]; - set2.start = set.start + set1.length; - set2.length = set.length / 2; - set2.part_level = set.part_level + 1; + set2.set_start(start + length - length / 2); + set2.set_length(length / 2); + set2.set_level(level + 1); return subsets; } diff --git a/src/SPECK1D_INT_DEC.cpp b/src/SPECK1D_INT_DEC.cpp index c921b68c..3e287139 100644 --- a/src/SPECK1D_INT_DEC.cpp +++ b/src/SPECK1D_INT_DEC.cpp @@ -54,7 +54,7 @@ void sperr::SPECK1D_INT_DEC::m_process_S(size_t idx1, size_t idx2, size_t& co if (is_sig) { counter++; // Let's increment the counter first! m_code_S(idx1, idx2); - set.length = 0; // this current set is gonna be discarded. + set.set_length(0); // this current set is gonna be discarded. } } @@ -84,13 +84,13 @@ void sperr::SPECK1D_INT_DEC::m_code_S(size_t idx1, size_t idx2) // Process the 1st subset const auto& set0 = subsets[0]; - assert(set0.length != 0); - if (set0.length == 1) { - m_LIP_mask.write_true(set0.start); - m_process_P(set0.start, sig_counter, read); + assert(set0.get_length() != 0); + if (set0.get_length() == 1) { + m_LIP_mask.write_true(set0.get_start()); + m_process_P(set0.get_start(), sig_counter, read); } else { - const auto newidx1 = set0.part_level; + const auto newidx1 = set0.get_level(); m_LIS[newidx1].push_back(set0); m_process_S(newidx1, m_LIS[newidx1].size() - 1, sig_counter, read); } @@ -99,13 +99,13 @@ void sperr::SPECK1D_INT_DEC::m_code_S(size_t idx1, size_t idx2) if (sig_counter == 0) read = false; const auto& set1 = subsets[1]; - assert(set1.length != 0); - if (set1.length == 1) { - m_LIP_mask.write_true(set1.start); - m_process_P(set1.start, sig_counter, read); + assert(set1.get_length() != 0); + if (set1.get_length() == 1) { + m_LIP_mask.write_true(set1.get_start()); + m_process_P(set1.get_start(), sig_counter, read); } else { - const auto newidx1 = set1.part_level; + const auto newidx1 = set1.get_level(); m_LIS[newidx1].push_back(set1); m_process_S(newidx1, m_LIS[newidx1].size() - 1, sig_counter, read); } diff --git a/src/SPECK1D_INT_ENC.cpp b/src/SPECK1D_INT_ENC.cpp index 9485ce4f..04e7f841 100644 --- a/src/SPECK1D_INT_ENC.cpp +++ b/src/SPECK1D_INT_ENC.cpp @@ -67,7 +67,7 @@ void sperr::SPECK1D_INT_ENC::m_process_S(size_t idx1, auto set_sig = m_decide_significance(set); sig = set_sig ? SigType::Sig : SigType::Insig; if (set_sig) { - if (*set_sig < set.length - set.length / 2) + if (*set_sig < set.get_length() - set.get_length() / 2) subset_sigs = {SigType::Sig, SigType::Dunno}; else subset_sigs = {SigType::Insig, SigType::Sig}; @@ -80,7 +80,7 @@ void sperr::SPECK1D_INT_ENC::m_process_S(size_t idx1, if (sig == SigType::Sig) { counter++; // Let's increment the counter first! m_code_S(idx1, idx2, subset_sigs); - set.length = 0; // this current set is gonna be discarded. + set.set_length(0); // this current set is gonna be discarded. } } @@ -120,13 +120,13 @@ void sperr::SPECK1D_INT_ENC::m_code_S(size_t idx1, // Process the 1st subset const auto& set0 = subsets[0]; - assert(set0.length != 0); - if (set0.length == 1) { - m_LIP_mask.write_true(set0.start); - m_process_P(set0.start, subset_sigs[0], sig_counter, output); + assert(set0.get_length() != 0); + if (set0.get_length() == 1) { + m_LIP_mask.write_true(set0.get_start()); + m_process_P(set0.get_start(), subset_sigs[0], sig_counter, output); } else { - const auto newidx1 = set0.part_level; + const auto newidx1 = set0.get_level(); m_LIS[newidx1].emplace_back(set0); const auto newidx2 = m_LIS[newidx1].size() - 1; m_process_S(newidx1, newidx2, subset_sigs[0], sig_counter, output); @@ -138,13 +138,13 @@ void sperr::SPECK1D_INT_ENC::m_code_S(size_t idx1, subset_sigs[1] = SigType::Sig; } const auto& set1 = subsets[1]; - assert(set1.length != 0); - if (set1.length == 1) { - m_LIP_mask.write_true(set1.start); - m_process_P(set1.start, subset_sigs[1], sig_counter, output); + assert(set1.get_length() != 0); + if (set1.get_length() == 1) { + m_LIP_mask.write_true(set1.get_start()); + m_process_P(set1.get_start(), subset_sigs[1], sig_counter, output); } else { - const auto newidx1 = set1.part_level; + const auto newidx1 = set1.get_level(); m_LIS[newidx1].emplace_back(set1); const auto newidx2 = m_LIS[newidx1].size() - 1; m_process_S(newidx1, newidx2, subset_sigs[1], sig_counter, output); @@ -155,13 +155,13 @@ template auto sperr::SPECK1D_INT_ENC::m_decide_significance(const Set1D& set) const -> std::optional { - assert(set.length != 0); + assert(set.get_length() != 0); auto result = std::optional(); const auto gtr = [thld = m_threshold](auto v) { return v >= thld; }; - auto first = m_coeff_buf.cbegin() + set.start; - auto last = first + set.length; + auto first = m_coeff_buf.cbegin() + set.get_start(); + auto last = first + set.get_length(); auto found = std::find_if(first, last, gtr); if (found != last) result = static_cast(std::distance(first, found)); From ee08ae707eb1d5a424fc2413118466f50c9c00fa Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Tue, 5 Sep 2023 14:17:09 -0600 Subject: [PATCH 17/23] minor --- include/SPECK1D_INT.h | 2 +- include/SPECK2D_INT.h | 2 +- src/SPECK1D_INT.cpp | 2 +- src/SPECK2D_INT.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/SPECK1D_INT.h b/include/SPECK1D_INT.h index 45f92fb6..d50866ce 100644 --- a/include/SPECK1D_INT.h +++ b/include/SPECK1D_INT.h @@ -60,7 +60,7 @@ class SPECK1D_INT : public SPECK_INT { // void m_clean_LIS() override; void m_initialize_lists() override; - auto m_partition_set(const Set1D&) const -> std::array; + auto m_partition_set(Set1D) const -> std::array; // // SPECK1D_INT specific data members diff --git a/include/SPECK2D_INT.h b/include/SPECK2D_INT.h index b4de1933..3f1721e2 100644 --- a/include/SPECK2D_INT.h +++ b/include/SPECK2D_INT.h @@ -43,7 +43,7 @@ class SPECK2D_INT : public SPECK_INT { virtual void m_process_I(bool need_decide) = 0; void m_clean_LIS() override; - auto m_partition_S(const Set2D&) const -> std::array; + auto m_partition_S(Set2D) const -> std::array; auto m_partition_I() -> std::array; void m_initialize_lists() override; diff --git a/src/SPECK1D_INT.cpp b/src/SPECK1D_INT.cpp index 6b2961b7..48a8e282 100644 --- a/src/SPECK1D_INT.cpp +++ b/src/SPECK1D_INT.cpp @@ -36,7 +36,7 @@ void sperr::SPECK1D_INT::m_initialize_lists() } template -auto sperr::SPECK1D_INT::m_partition_set(const Set1D& set) const -> std::array +auto sperr::SPECK1D_INT::m_partition_set(Set1D set) const -> std::array { const auto start = set.get_start(); const auto length = set.get_length(); diff --git a/src/SPECK2D_INT.cpp b/src/SPECK2D_INT.cpp index beed8455..9cf6cb43 100644 --- a/src/SPECK2D_INT.cpp +++ b/src/SPECK2D_INT.cpp @@ -95,7 +95,7 @@ void sperr::SPECK2D_INT::m_clean_LIS() } template -auto sperr::SPECK2D_INT::m_partition_S(const Set2D& set) const -> std::array +auto sperr::SPECK2D_INT::m_partition_S(Set2D set) const -> std::array { auto subsets = std::array(); From c0c588fe0c7b7879249db583e87950d16b7f7dfc Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Wed, 6 Sep 2023 13:54:46 -0600 Subject: [PATCH 18/23] minor --- include/SPECK3D_INT_ENC.h | 2 +- src/CDF97.cpp | 3 +-- src/SPECK3D_INT_ENC.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index 2a02eb37..e7a20a4e 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -39,7 +39,7 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { // Data structures and functions for morton data layout. vecui_type m_morton_buf; - void m_deposit_set(const Set3D&); + void m_deposit_set(Set3D); }; }; // namespace sperr diff --git a/src/CDF97.cpp b/src/CDF97.cpp index f95c2320..0ea57fc1 100644 --- a/src/CDF97.cpp +++ b/src/CDF97.cpp @@ -342,8 +342,7 @@ void sperr::CDF97::m_idwt1d_one_level(itd_type array, size_t array_len) void sperr::CDF97::m_dwt2d_one_level(itd_type plane, std::array len_xy) { // Note: here we call low-level functions (Qcc*()) instead of - // m_dwt1d_one_level() because we want to have only one even/odd test outside of - // the loop. + // m_dwt1d_one_level() because we want to have only one even/odd test at the outer loop. const size_t max_len = std::max(len_xy[0], len_xy[1]); const auto beg = m_qcc_buf.begin(); diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index ae61a5f9..203102a7 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -6,7 +6,7 @@ #include template -void sperr::SPECK3D_INT_ENC::m_deposit_set(const Set3D& set) +void sperr::SPECK3D_INT_ENC::m_deposit_set(Set3D set) { switch (set.num_elem()) { case 0: From a4085d3f9776642d234114a0b8e44dbf795e9540 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Thu, 7 Sep 2023 22:46:32 -0600 Subject: [PATCH 19/23] remove [[likely]] --- src/CDF97.cpp | 62 +++++++++------------------------------------------ 1 file changed, 10 insertions(+), 52 deletions(-) diff --git a/src/CDF97.cpp b/src/CDF97.cpp index 0ea57fc1..6ae1a17c 100644 --- a/src/CDF97.cpp +++ b/src/CDF97.cpp @@ -306,12 +306,7 @@ void sperr::CDF97::m_idwt2d(itd_type plane, std::array len_xy, size_t void sperr::CDF97::m_dwt1d_one_level(itd_type array, size_t array_len) { std::copy(array, array + array_len, m_qcc_buf.begin()); -#if __cplusplus >= 202002L - if (array_len % 2 == 0) [[likely]] // Even length -#else - if (array_len % 2 == 0) // Even length -#endif - { + if (array_len % 2 == 0) { this->QccWAVCDF97AnalysisSymmetricEvenEven(m_qcc_buf.data(), array_len); m_gather_even(m_qcc_buf.begin(), m_qcc_buf.begin() + array_len, array); } @@ -323,12 +318,7 @@ void sperr::CDF97::m_dwt1d_one_level(itd_type array, size_t array_len) void sperr::CDF97::m_idwt1d_one_level(itd_type array, size_t array_len) { -#if __cplusplus >= 202002L - if (array_len % 2 == 0) [[likely]] // Even length -#else - if (array_len % 2 == 0) // Even length -#endif - { + if (array_len % 2 == 0) { m_scatter_even(array, array + array_len, m_qcc_buf.begin()); this->QccWAVCDF97SynthesisSymmetricEvenEven(m_qcc_buf.data(), array_len); } @@ -349,12 +339,7 @@ void sperr::CDF97::m_dwt2d_one_level(itd_type plane, std::array len_x const auto beg2 = beg + max_len; // First, perform DWT along X for every row -#if __cplusplus >= 202002L - if (len_xy[0] % 2 == 0) [[likely]] // Even Length -#else - if (len_xy[0] % 2 == 0) // Even Length -#endif - { + if (len_xy[0] % 2 == 0) { for (size_t i = 0; i < len_xy[1]; i++) { auto pos = plane + i * m_dims[0]; std::copy(pos, pos + len_xy[0], beg); @@ -379,12 +364,7 @@ void sperr::CDF97::m_dwt2d_one_level(itd_type plane, std::array len_x // on an X86 linux machine using gcc, clang, and pgi. Again the difference is // either indistinguishable, or the current implementation has a slight edge. -#if __cplusplus >= 202002L - if (len_xy[1] % 2 == 0) [[likely]] // Even length -#else - if (len_xy[1] % 2 == 0) // Even length -#endif - { + if (len_xy[1] % 2 == 0) { for (size_t x = 0; x < len_xy[0]; x++) { for (size_t y = 0; y < len_xy[1]; y++) m_qcc_buf[y] = *(plane + y * m_dims[0] + x); @@ -414,12 +394,7 @@ void sperr::CDF97::m_idwt2d_one_level(itd_type plane, std::array len_ const auto beg2 = beg + max_len; // Second half of the buffer // First, perform IDWT along Y for every column -#if __cplusplus >= 202002L - if (len_xy[1] % 2 == 0) [[likely]] // Even length -#else - if (len_xy[1] % 2 == 0) // Even length -#endif - { + if (len_xy[1] % 2 == 0) { for (size_t x = 0; x < len_xy[0]; x++) { for (size_t y = 0; y < len_xy[1]; y++) m_qcc_buf[y] = *(plane + y * m_dims[0] + x); @@ -442,12 +417,7 @@ void sperr::CDF97::m_idwt2d_one_level(itd_type plane, std::array len_ } // Second, perform IDWT along X for every row -#if __cplusplus >= 202002L - if (len_xy[0] % 2 == 0) [[likely]] // Even length -#else - if (len_xy[0] % 2 == 0) // Even length -#endif - { + if (len_xy[0] % 2 == 0) { for (size_t i = 0; i < len_xy[1]; i++) { auto pos = plane + i * m_dims[0]; m_scatter_even(pos, pos + len_xy[0], beg); @@ -484,12 +454,7 @@ void sperr::CDF97::m_dwt3d_one_level(itd_type vol, std::array len_xyz // 3) gather coefficients from `m_qcc_buf` to the second half of `m_qcc_buf` // 4) put the Z column back to their locations as a Z column. -#if __cplusplus >= 202002L - if (len_xyz[2] % 2 == 0) [[likely]] // Even length -#else - if (len_xyz[2] % 2 == 0) // Even length -#endif - { + if (len_xyz[2] % 2 == 0) { // Even length for (size_t y = 0; y < len_xyz[1]; y++) { for (size_t x = 0; x < len_xyz[0]; x++) { const size_t xy_offset = y * m_dims[0] + x; @@ -506,8 +471,7 @@ void sperr::CDF97::m_dwt3d_one_level(itd_type vol, std::array len_xyz } } } - else // Odd length - { + else { // Odd length for (size_t y = 0; y < len_xyz[1]; y++) { for (size_t x = 0; x < len_xyz[0]; x++) { const size_t xy_offset = y * m_dims[0] + x; @@ -538,12 +502,7 @@ void sperr::CDF97::m_idwt3d_one_level(itd_type vol, std::array len_xy // 3) use appropriate even/odd Qcc*** function to transform it // 4) put the Z column back to their locations as a Z column. -#if __cplusplus >= 202002L - if (len_xyz[2] % 2 == 0) [[likely]] -#else - if (len_xyz[2] % 2 == 0) -#endif - { + if (len_xyz[2] % 2 == 0) { for (size_t y = 0; y < len_xyz[1]; y++) { for (size_t x = 0; x < len_xyz[0]; x++) { const size_t xy_offset = y * m_dims[0] + x; @@ -560,8 +519,7 @@ void sperr::CDF97::m_idwt3d_one_level(itd_type vol, std::array len_xy } } } - else // Odd length - { + else { for (size_t y = 0; y < len_xyz[1]; y++) { for (size_t x = 0; x < len_xyz[0]; x++) { const size_t xy_offset = y * m_dims[0] + x; From 2345d52d1cfa0e28352fa98fb63192ce8759669c Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Fri, 8 Sep 2023 11:47:41 -0600 Subject: [PATCH 20/23] minor reformatting --- src/CDF97.cpp | 87 ++++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/CDF97.cpp b/src/CDF97.cpp index 6ae1a17c..beba3d3b 100644 --- a/src/CDF97.cpp +++ b/src/CDF97.cpp @@ -609,99 +609,106 @@ void sperr::CDF97::m_scatter_odd(citd_type begin, citd_type end, itd_type dest) // void sperr::CDF97::QccWAVCDF97AnalysisSymmetricEvenEven(double* signal, size_t signal_length) { - for (size_t index = 1; index < signal_length - 2; index += 2) - signal[index] += ALPHA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 1; i < signal_length - 2; i += 2) + signal[i] += ALPHA * (signal[i - 1] + signal[i + 1]); + signal[signal_length - 1] += 2.0 * ALPHA * signal[signal_length - 2]; signal[0] += 2.0 * BETA * signal[1]; - for (size_t index = 2; index < signal_length; index += 2) - signal[index] += BETA * (signal[index + 1] + signal[index - 1]); - for (size_t index = 1; index < signal_length - 2; index += 2) - signal[index] += GAMMA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 2; i < signal_length; i += 2) + signal[i] += BETA * (signal[i + 1] + signal[i - 1]); + + for (size_t i = 1; i < signal_length - 2; i += 2) + signal[i] += GAMMA * (signal[i - 1] + signal[i + 1]); + signal[signal_length - 1] += 2.0 * GAMMA * signal[signal_length - 2]; signal[0] = EPSILON * (signal[0] + 2.0 * DELTA * signal[1]); - for (size_t index = 2; index < signal_length; index += 2) - signal[index] = EPSILON * (signal[index] + DELTA * (signal[index + 1] + signal[index - 1])); - for (size_t index = 1; index < signal_length; index += 2) - signal[index] *= -INV_EPSILON; + for (size_t i = 2; i < signal_length; i += 2) + signal[i] = EPSILON * (signal[i] + DELTA * (signal[i + 1] + signal[i - 1])); + + for (size_t i = 1; i < signal_length; i += 2) + signal[i] *= -INV_EPSILON; } void sperr::CDF97::QccWAVCDF97SynthesisSymmetricEvenEven(double* signal, size_t signal_length) { - for (size_t index = 1; index < signal_length; index += 2) - signal[index] *= (-EPSILON); + for (size_t i = 1; i < signal_length; i += 2) + signal[i] *= (-EPSILON); signal[0] = signal[0] * INV_EPSILON - 2.0 * DELTA * signal[1]; - for (size_t index = 2; index < signal_length; index += 2) - signal[index] = signal[index] * INV_EPSILON - DELTA * (signal[index + 1] + signal[index - 1]); + for (size_t i = 2; i < signal_length; i += 2) + signal[i] = signal[i] * INV_EPSILON - DELTA * (signal[i + 1] + signal[i - 1]); + + for (size_t i = 1; i < signal_length - 2; i += 2) + signal[i] -= GAMMA * (signal[i - 1] + signal[i + 1]); - for (size_t index = 1; index < signal_length - 2; index += 2) - signal[index] -= GAMMA * (signal[index - 1] + signal[index + 1]); signal[signal_length - 1] -= 2.0 * GAMMA * signal[signal_length - 2]; signal[0] -= 2.0 * BETA * signal[1]; - for (size_t index = 2; index < signal_length; index += 2) - signal[index] -= BETA * (signal[index + 1] + signal[index - 1]); - for (size_t index = 1; index < signal_length - 2; index += 2) - signal[index] -= ALPHA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 2; i < signal_length; i += 2) + signal[i] -= BETA * (signal[i + 1] + signal[i - 1]); + + for (size_t i = 1; i < signal_length - 2; i += 2) + signal[i] -= ALPHA * (signal[i - 1] + signal[i + 1]); + signal[signal_length - 1] -= 2.0 * ALPHA * signal[signal_length - 2]; } void sperr::CDF97::QccWAVCDF97SynthesisSymmetricOddEven(double* signal, size_t signal_length) { - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] *= (-EPSILON); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] *= (-EPSILON); signal[0] = signal[0] * INV_EPSILON - 2.0 * DELTA * signal[1]; - for (size_t index = 2; index < signal_length - 2; index += 2) - signal[index] = signal[index] * INV_EPSILON - DELTA * (signal[index + 1] + signal[index - 1]); + for (size_t i = 2; i < signal_length - 2; i += 2) + signal[i] = signal[i] * INV_EPSILON - DELTA * (signal[i + 1] + signal[i - 1]); signal[signal_length - 1] = signal[signal_length - 1] * INV_EPSILON - 2.0 * DELTA * signal[signal_length - 2]; - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] -= GAMMA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] -= GAMMA * (signal[i - 1] + signal[i + 1]); signal[0] -= 2.0 * BETA * signal[1]; - for (size_t index = 2; index < signal_length - 2; index += 2) - signal[index] -= BETA * (signal[index + 1] + signal[index - 1]); + for (size_t i = 2; i < signal_length - 2; i += 2) + signal[i] -= BETA * (signal[i + 1] + signal[i - 1]); signal[signal_length - 1] -= 2.0 * BETA * signal[signal_length - 2]; - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] -= ALPHA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] -= ALPHA * (signal[i - 1] + signal[i + 1]); } void sperr::CDF97::QccWAVCDF97AnalysisSymmetricOddEven(double* signal, size_t signal_length) { - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] += ALPHA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] += ALPHA * (signal[i - 1] + signal[i + 1]); signal[0] += 2.0 * BETA * signal[1]; - for (size_t index = 2; index < signal_length - 2; index += 2) - signal[index] += BETA * (signal[index + 1] + signal[index - 1]); + for (size_t i = 2; i < signal_length - 2; i += 2) + signal[i] += BETA * (signal[i + 1] + signal[i - 1]); signal[signal_length - 1] += 2.0 * BETA * signal[signal_length - 2]; - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] += GAMMA * (signal[index - 1] + signal[index + 1]); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] += GAMMA * (signal[i - 1] + signal[i + 1]); signal[0] = EPSILON * (signal[0] + 2.0 * DELTA * signal[1]); - for (size_t index = 2; index < signal_length - 2; index += 2) - signal[index] = EPSILON * (signal[index] + DELTA * (signal[index + 1] + signal[index - 1])); + for (size_t i = 2; i < signal_length - 2; i += 2) + signal[i] = EPSILON * (signal[i] + DELTA * (signal[i + 1] + signal[i - 1])); signal[signal_length - 1] = EPSILON * (signal[signal_length - 1] + 2.0 * DELTA * signal[signal_length - 2]); - for (size_t index = 1; index < signal_length - 1; index += 2) - signal[index] *= (-INV_EPSILON); + for (size_t i = 1; i < signal_length - 1; i += 2) + signal[i] *= (-INV_EPSILON); } From 08c74528a7e34da8ab3667adedb6d826026fedaa Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sat, 9 Sep 2023 19:58:32 -0600 Subject: [PATCH 21/23] m_process_P() checks pixel significance from the morton buffer too --- include/SPECK3D_INT.h | 6 +++--- include/SPECK3D_INT_DEC.h | 3 ++- include/SPECK3D_INT_ENC.h | 3 ++- src/SPECK3D_INT.cpp | 10 +++++----- src/SPECK3D_INT_DEC.cpp | 13 ++++++++++++- src/SPECK3D_INT_ENC.cpp | 21 +++++++++++++++++++-- 6 files changed, 43 insertions(+), 13 deletions(-) diff --git a/include/SPECK3D_INT.h b/include/SPECK3D_INT.h index ab89674b..0046a822 100644 --- a/include/SPECK3D_INT.h +++ b/include/SPECK3D_INT.h @@ -36,8 +36,7 @@ class Set3D { return tmp; } void set_morton(uint64_t val) { std::memcpy(m_morton.data(), &val, sizeof(m_morton)); } - auto is_empty() const -> bool { return (length_z == 0 || length_y == 0 || length_x == 0); } - void make_empty() { length_z = 0; } + void make_empty() { length_x = 0; } auto num_elem() const -> size_t { return (size_t{length_x} * length_y * length_z); } }; @@ -61,7 +60,8 @@ class SPECK3D_INT : public SPECK_INT { void m_clean_LIS() override; virtual void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool) = 0; - virtual void m_process_P(size_t idx, size_t& counter, bool) = 0; + virtual void m_process_P(size_t i, size_t m, size_t& c, bool) = 0; // Called by `m_code_S()`. + virtual void m_process_P_lite(size_t idx) = 0; // Called by `m_sorting_pass()` directly. virtual void m_additional_initialization() = 0; void m_code_S(size_t idx1, size_t idx2); diff --git a/include/SPECK3D_INT_DEC.h b/include/SPECK3D_INT_DEC.h index 1b139c67..647b9dc0 100644 --- a/include/SPECK3D_INT_DEC.h +++ b/include/SPECK3D_INT_DEC.h @@ -22,7 +22,8 @@ class SPECK3D_INT_DEC : public SPECK3D_INT { using SPECK3D_INT::m_code_S; void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool read) override; - void m_process_P(size_t idx, size_t& counter, bool read) override; + void m_process_P(size_t idx, size_t no_use, size_t& counter, bool read) override; + void m_process_P_lite(size_t idx) override; void m_additional_initialization() override{}; // empty function }; diff --git a/include/SPECK3D_INT_ENC.h b/include/SPECK3D_INT_ENC.h index e7a20a4e..add3fbbf 100644 --- a/include/SPECK3D_INT_ENC.h +++ b/include/SPECK3D_INT_ENC.h @@ -34,7 +34,8 @@ class SPECK3D_INT_ENC : public SPECK3D_INT { using SPECK3D_INT::m_code_S; void m_process_S(size_t idx1, size_t idx2, size_t& counter, bool output) override; - void m_process_P(size_t idx, size_t& counter, bool output) override; + void m_process_P(size_t idx, size_t morton, size_t& counter, bool output) override; + void m_process_P_lite(size_t idx) override; void m_additional_initialization() override; // Data structures and functions for morton data layout. diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index 51cac32e..e8cb1f70 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -9,7 +9,7 @@ template void sperr::SPECK3D_INT::m_clean_LIS() { for (auto& list : m_LIS) { - auto it = std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.is_empty(); }); + auto it = std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.num_elem() == 0; }); list.erase(it, list.end()); } } @@ -109,7 +109,7 @@ void sperr::SPECK3D_INT::m_sorting_pass() for (size_t j = 0; j < 64; j++) { if ((value >> j) & uint64_t{1}) { size_t dummy = 0; - m_process_P(i + j, dummy, true); + m_process_P_lite(i + j); } } } @@ -117,7 +117,7 @@ void sperr::SPECK3D_INT::m_sorting_pass() for (auto i = bits_x64; i < m_LIP_mask.size(); i++) { if (m_LIP_mask.read_bit(i)) { size_t dummy = 0; - m_process_P(i, dummy, true); + m_process_P_lite(i); } } @@ -139,7 +139,7 @@ void sperr::SPECK3D_INT::m_code_S(size_t idx1, size_t idx2) // Since some subsets could be empty, let's put empty sets at the end. const auto set_end = - std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.is_empty(); }); + std::remove_if(subsets.begin(), subsets.end(), [](auto& s) { return s.num_elem() == 0; }); const auto set_end_m1 = set_end - 1; size_t sig_counter = 0; @@ -153,7 +153,7 @@ void sperr::SPECK3D_INT::m_code_S(size_t idx1, size_t idx2) if (it->num_elem() == 1) { auto idx = it->start_z * m_dims[0] * m_dims[1] + it->start_y * m_dims[0] + it->start_x; m_LIP_mask.write_true(idx); - m_process_P(idx, sig_counter, need_decide); + m_process_P(idx, it->get_morton(), sig_counter, need_decide); } else { m_LIS[next_lev].emplace_back(*it); diff --git a/src/SPECK3D_INT_DEC.cpp b/src/SPECK3D_INT_DEC.cpp index aac02bb3..0fe621e9 100644 --- a/src/SPECK3D_INT_DEC.cpp +++ b/src/SPECK3D_INT_DEC.cpp @@ -22,7 +22,7 @@ void sperr::SPECK3D_INT_DEC::m_process_S(size_t idx1, size_t idx2, size_t& co } template -void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t& counter, bool read) +void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t no_use, size_t& counter, bool read) { bool is_sig = true; if (read) @@ -31,7 +31,18 @@ void sperr::SPECK3D_INT_DEC::m_process_P(size_t idx, size_t& counter, bool re if (is_sig) { counter++; // Let's increment the counter first! m_sign_array[idx] = m_bit_buffer.rbit(); + m_LSP_new.push_back(idx); + m_LIP_mask.write_false(idx); + } +} +template +void sperr::SPECK3D_INT_DEC::m_process_P_lite(size_t idx) +{ + auto is_sig = m_bit_buffer.rbit(); + + if (is_sig) { + m_sign_array[idx] = m_bit_buffer.rbit(); m_LSP_new.push_back(idx); m_LIP_mask.write_false(idx); } diff --git a/src/SPECK3D_INT_ENC.cpp b/src/SPECK3D_INT_ENC.cpp index 203102a7..c87cbbee 100644 --- a/src/SPECK3D_INT_ENC.cpp +++ b/src/SPECK3D_INT_ENC.cpp @@ -85,12 +85,13 @@ void sperr::SPECK3D_INT_ENC::m_process_S(size_t idx1, size_t idx2, size_t& co } template -void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t& counter, bool output) +void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t morton, size_t& counter, bool output) { bool is_sig = true; if (output) { - is_sig = (m_coeff_buf[idx] >= m_threshold); + assert(m_coeff_buf[idx] == m_morton_buf[morton]); + is_sig = (m_morton_buf[morton] >= m_threshold); m_bit_buffer.wbit(is_sig); } @@ -105,6 +106,22 @@ void sperr::SPECK3D_INT_ENC::m_process_P(size_t idx, size_t& counter, bool ou } } +template +void sperr::SPECK3D_INT_ENC::m_process_P_lite(size_t idx) +{ + auto is_sig = (m_coeff_buf[idx] >= m_threshold); + m_bit_buffer.wbit(is_sig); + + if (is_sig) { + assert(m_coeff_buf[idx] >= m_threshold); + m_coeff_buf[idx] -= m_threshold; + + m_bit_buffer.wbit(m_sign_array[idx]); + m_LSP_new.push_back(idx); + m_LIP_mask.write_false(idx); + } +} + template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; template class sperr::SPECK3D_INT_ENC; From 97b218cb1a5a40502a7998683c42a66cb1340049 Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sat, 9 Sep 2023 20:10:58 -0600 Subject: [PATCH 22/23] clang-format --- src/SPECK1D_INT.cpp | 4 ++-- src/SPECK2D_INT.cpp | 3 +-- src/SPECK3D_INT.cpp | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SPECK1D_INT.cpp b/src/SPECK1D_INT.cpp index 48a8e282..bc84f241 100644 --- a/src/SPECK1D_INT.cpp +++ b/src/SPECK1D_INT.cpp @@ -9,8 +9,8 @@ template void sperr::SPECK1D_INT::m_clean_LIS() { for (auto& list : m_LIS) { - auto it = std::remove_if(list.begin(), list.end(), - [](const auto& s) { return s.get_length() == 0; }); + auto it = + std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.get_length() == 0; }); list.erase(it, list.end()); } } diff --git a/src/SPECK2D_INT.cpp b/src/SPECK2D_INT.cpp index 9cf6cb43..cbe6d93c 100644 --- a/src/SPECK2D_INT.cpp +++ b/src/SPECK2D_INT.cpp @@ -88,8 +88,7 @@ template void sperr::SPECK2D_INT::m_clean_LIS() { for (auto& list : m_LIS) { - auto it = std::remove_if(list.begin(), list.end(), - [](auto& s) { return s.is_empty(); }); + auto it = std::remove_if(list.begin(), list.end(), [](auto& s) { return s.is_empty(); }); list.erase(it, list.end()); } } diff --git a/src/SPECK3D_INT.cpp b/src/SPECK3D_INT.cpp index e8cb1f70..a7ef7447 100644 --- a/src/SPECK3D_INT.cpp +++ b/src/SPECK3D_INT.cpp @@ -9,7 +9,8 @@ template void sperr::SPECK3D_INT::m_clean_LIS() { for (auto& list : m_LIS) { - auto it = std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.num_elem() == 0; }); + auto it = + std::remove_if(list.begin(), list.end(), [](const auto& s) { return s.num_elem() == 0; }); list.erase(it, list.end()); } } From 32467215592de3f67050c51ce26f5540deb45c2d Mon Sep 17 00:00:00 2001 From: Samuel Li Date: Sat, 9 Sep 2023 20:19:32 -0600 Subject: [PATCH 23/23] minor --- include/SPECK2D_INT.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/SPECK2D_INT.h b/include/SPECK2D_INT.h index 3f1721e2..771854a7 100644 --- a/include/SPECK2D_INT.h +++ b/include/SPECK2D_INT.h @@ -14,8 +14,8 @@ class Set2D { uint16_t part_level = 0; public: - auto is_pixel() const -> bool { return (length_x == 1 && length_y == 1); }; - auto is_empty() const -> bool { return (length_x == 0 || length_y == 0); }; + auto is_pixel() const -> bool { return (size_t{length_x} * length_y == 1); }; + auto is_empty() const -> bool { return (size_t{length_x} * length_y == 0); }; void make_empty() { length_x = 0; }; };