diff options
author | David Robillard <d@drobilla.net> | 2018-08-19 18:22:26 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2018-09-29 14:50:07 +0200 |
commit | ac65326242af579d6e1a7bd71730f1c78c8bde9b (patch) | |
tree | ae5225c4b9856b3e5d454378d00867d9b0c53d26 /chilbert/detail/gray_code_rank.hpp | |
parent | 7567f77828ff9661f85eabe3b4cfb1876b307d42 (diff) | |
download | chilbert-ac65326242af579d6e1a7bd71730f1c78c8bde9b.tar.gz chilbert-ac65326242af579d6e1a7bd71730f1c78c8bde9b.tar.bz2 chilbert-ac65326242af579d6e1a7bd71730f1c78c8bde9b.zip |
Reorganize headers to make a clear public/private distinction
Diffstat (limited to 'chilbert/detail/gray_code_rank.hpp')
-rw-r--r-- | chilbert/detail/gray_code_rank.hpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/chilbert/detail/gray_code_rank.hpp b/chilbert/detail/gray_code_rank.hpp new file mode 100644 index 0000000..815519e --- /dev/null +++ b/chilbert/detail/gray_code_rank.hpp @@ -0,0 +1,182 @@ +/* + Copyright (C) 2018 David Robillard <d@drobilla.net> + Copyright (C) 2006-2007 Chris Hamilton <chamilton@cs.dal.ca> + + This program is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation, either version 2 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef CHILBERT_GRAYCODERANK_HPP +#define CHILBERT_GRAYCODERANK_HPP + +#include <cassert> +#include <cstddef> +#include <numeric> + +namespace chilbert { +namespace detail { + +// This is the bulk of the cost in calculating +// a Compact Hilbert Index. It compresses a previously +// calculated index when provided the rotation +// at each level of precision. +template <class H, class HC> +inline void +compact_index(const size_t* const ms, + const size_t* const ds, + const size_t n, + const size_t m, + H& h, + HC& hc) +{ + assert(h.size() >= n * m); + assert(hc.size() >= std::accumulate(ms, ms + n, size_t(0))); + + reset_bits(hc); + + auto hm = h.mask(0); + auto hcm = hc.mask(0); + + // Run through the levels of precision + for (size_t i = 0; i < m; i++) { + // Run through the dimensions + size_t j = ds[i]; + do { + // This dimension contributes a bit? + if (ms[j] > i) { + if (h.test(hm)) { + hc.set(hcm); + } + ++hcm; + } + + if (++j == n) { + j = 0; + } + ++hm; + } while (j != ds[i]); + } +} + +template <class I> +inline void +gray_code_rank(const I& mask, const I& gi, const size_t n, I& r) +{ + assert(mask.size() == n); + assert(gi.size() == n); + assert(r.size() == n); + + r.reset(); + + auto mi = mask.begin(); + auto gii = gi.begin(); + auto ri = r.begin(); + + for (size_t i = 0; i < n; ++i, ++mi, ++gii) { + if (*mi) { + if (*gii) { + ri.set(); + } + ++ri; + } + } +} + +template <class I> +inline void +gray_code_rank_inv(const I& mask, + const I& ptrn, + const I& r, + const size_t n, + const size_t b, + I& g, + I& gi) +{ + assert(mask.size() == n); + assert(ptrn.size() == n); + assert(r.size() == n); + assert(g.size() == n); + assert(gi.size() == n); + + g.reset(); + gi.reset(); + + auto m = mask.mask(n - 1); + auto ri = r.begin(b - 1); + + typename I::Rack gi0 = 0; + typename I::Rack gi1 = 0; + typename I::Rack g0 = 0; + + for (size_t i = 0; i < n; ++i) { + if (mask.test(m)) { // Unconstrained bit + gi1 = gi0; + gi0 = *ri; + g0 = gi0 ^ gi1; + if (gi0) { + gi.set(m); + } + if (g0) { + g.set(m); + } + --ri; + } else { // Constrained bit + g0 = (ptrn.test(m) > 0); + gi1 = gi0; + gi0 = g0 ^ gi1; + if (gi0) { + gi.set(m); + } + if (g0) { + g.set(m); + } + } + + --m; + } +} + +template <class I> +inline void +extract_mask(const size_t* const ms, + const size_t n, + const size_t d, + const size_t i, + I& mask, + size_t& b) +{ + assert(0 <= d && d < n); + assert(mask.size() == n); + + mask.reset(); + b = 0; + + auto mi = mask.begin(); + size_t j = d; // #D j = (d==n-1) ? 0 : d+1; + do { + if (ms[j] > i) { + mi.set(); + ++b; + } + + ++mi; + if (++j == n) { + j = 0; + } + } while (j != d); +} + +} // namespace detail +} // namespace chilbert + +#endif |