File indexing completed on 2025-09-17 08:54:11
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <algorithm>
0010 #include <climits>
0011 #include <iostream>
0012 #include <memory>
0013 #include <numeric>
0014 #include <type_traits>
0015
0016 #include <covfie/core/array.hpp>
0017 #include <covfie/core/backend/primitive/array.hpp>
0018 #include <covfie/core/concepts.hpp>
0019 #include <covfie/core/parameter_pack.hpp>
0020 #include <covfie/core/qualifiers.hpp>
0021 #include <covfie/core/utility/binary_io.hpp>
0022 #include <covfie/core/utility/nd_map.hpp>
0023 #include <covfie/core/utility/nd_size.hpp>
0024 #include <covfie/core/utility/numeric.hpp>
0025 #include <covfie/core/vector.hpp>
0026
0027 namespace covfie::backend {
0028 template <
0029 concepts::vector_descriptor _input_vector_t,
0030 concepts::field_backend _storage_t>
0031 struct hilbert {
0032 using this_t = hilbert<_input_vector_t, _storage_t>;
0033 static constexpr bool is_initial = false;
0034
0035 using backend_t = _storage_t;
0036
0037 using contravariant_input_t =
0038 covfie::vector::array_vector_d<_input_vector_t>;
0039 using contravariant_output_t = typename backend_t::contravariant_input_t;
0040 using covariant_input_t = typename backend_t::covariant_output_t;
0041 using covariant_output_t = covariant_input_t;
0042
0043 using coordinate_t = typename contravariant_input_t::vector_t;
0044 using array_t = backend_t;
0045
0046 using configuration_t = utility::nd_size<contravariant_input_t::dimensions>;
0047
0048 static constexpr uint32_t IO_MAGIC_HEADER = 0xAB020004;
0049
0050 static_assert(
0051 contravariant_input_t::dimensions == 2,
0052 "Number of dimensions for input must be exactly two."
0053 );
0054
0055 COVFIE_HOST_DEVICE static void
0056 rot(std::size_t n,
0057 std::size_t * x,
0058 std::size_t * y,
0059 std::size_t rx,
0060 std::size_t ry)
0061 {
0062 if (ry == 0) {
0063 if (rx == 1) {
0064 *x = n - 1 - *x;
0065 *y = n - 1 - *y;
0066 }
0067
0068 std::size_t t = *x;
0069 *x = *y;
0070 *y = t;
0071 }
0072 }
0073
0074 COVFIE_HOST_DEVICE static std::size_t calculate_index(
0075 coordinate_t c,
0076 utility::nd_size<contravariant_input_t::dimensions> sizes
0077 )
0078 {
0079
0080
0081 std::size_t rx, ry, s, d = 0;
0082
0083 std::size_t x = c[0];
0084 std::size_t y = c[1];
0085
0086
0087 for (s = sizes[0] / 2; s > 0; s /= 2) {
0088 rx = (x & s) > 0;
0089 ry = (y & s) > 0;
0090 d += s * s * ((3 * rx) ^ ry);
0091 rot(sizes[0], &x, &y, rx, ry);
0092 }
0093
0094 return d;
0095 }
0096
0097 template <typename T>
0098 static std::unique_ptr<
0099 std::decay_t<typename backend_t::covariant_output_t::vector_t>[]>
0100 make_hilbert_copy(const T & other)
0101 {
0102 configuration_t sizes = other.get_configuration();
0103
0104 std::unique_ptr<
0105 std::decay_t<typename backend_t::covariant_output_t::vector_t>[]>
0106 res = std::make_unique<std::decay_t<
0107 typename backend_t::covariant_output_t::vector_t>[]>(
0108 utility::ipow(
0109 utility::round_pow2(
0110 *std::max_element(sizes.begin(), sizes.end())
0111 ),
0112 contravariant_input_t::dimensions
0113 )
0114 );
0115 typename T::parent_t::non_owning_data_t nother(other);
0116
0117 utility::nd_map<decltype(sizes)>(
0118 [¬her, &res](decltype(sizes) t) {
0119 coordinate_t c;
0120
0121 for (std::size_t i = 0; i < contravariant_input_t::dimensions;
0122 ++i) {
0123 c[i] = t[i];
0124 }
0125
0126 std::size_t idx = calculate_index(c);
0127
0128 for (std::size_t i = 0; i < covariant_output_t::dimensions; ++i)
0129 {
0130 res[idx][i] = nother.at(c)[i];
0131 }
0132 },
0133 sizes
0134 );
0135
0136 return res;
0137 }
0138
0139 struct owning_data_t {
0140 using parent_t = this_t;
0141
0142 owning_data_t() = default;
0143 owning_data_t(const owning_data_t &) = default;
0144 owning_data_t(owning_data_t &&) = default;
0145 owning_data_t & operator=(const owning_data_t &) = default;
0146 owning_data_t & operator=(owning_data_t &&) = default;
0147
0148 template <typename T>
0149 requires(std::same_as<
0150 typename T::parent_t::configuration_t,
0151 configuration_t> &&
0152 std::constructible_from<
0153 typename backend_t::owning_data_t,
0154 std::size_t,
0155 std::add_rvalue_reference_t<std::unique_ptr<std::decay_t<
0156 typename backend_t::covariant_output_t::
0157 vector_t>[]>>>) explicit owning_data_t(const T &
0158 o)
0159 : m_sizes(o.get_configuration())
0160 , m_storage(
0161 utility::ipow(
0162 utility::round_pow2(
0163 *std::max_element(m_sizes.begin(), m_sizes.end())
0164 ),
0165 contravariant_input_t::dimensions
0166 ),
0167 make_hilbert_copy(o)
0168 )
0169 {
0170 }
0171
0172 template <typename... Args>
0173 requires(std::constructible_from<
0174 typename backend_t::owning_data_t,
0175 std::
0176 size_t>) explicit owning_data_t(configuration_t conf, Args... args)
0177 : m_sizes(conf)
0178 , m_storage(std::forward<Args>(args)...)
0179 {
0180 }
0181
0182 template <typename... Args>
0183 explicit owning_data_t(parameter_pack<configuration_t, Args...> && args)
0184 : m_sizes(args.x)
0185 , m_storage(std::move(args.xs))
0186 {
0187 }
0188
0189 explicit owning_data_t(parameter_pack<owning_data_t> && conf)
0190 : owning_data_t(std::move(conf.x))
0191 {
0192 }
0193
0194 explicit owning_data_t(
0195 const configuration_t & c, typename backend_t::owning_data_t && b
0196 )
0197 : m_sizes(c)
0198 , m_storage(std::forward<typename backend_t::owning_data_t>(b))
0199 {
0200 }
0201
0202 typename backend_t::owning_data_t & get_backend(void)
0203 {
0204 return m_storage;
0205 }
0206
0207 const typename backend_t::owning_data_t & get_backend(void) const
0208 {
0209 return m_storage;
0210 }
0211
0212 configuration_t get_configuration(void) const
0213 {
0214 return m_sizes;
0215 }
0216
0217 static owning_data_t read_binary(std::istream & fs)
0218 {
0219 utility::read_io_header(fs, IO_MAGIC_HEADER);
0220
0221 auto sizes = utility::read_binary<decltype(m_sizes)>(fs);
0222 auto be = decltype(m_storage)::read_binary(fs);
0223
0224 utility::read_io_footer(fs, IO_MAGIC_HEADER);
0225
0226 return owning_data_t(sizes, std::move(be));
0227 }
0228
0229 static void write_binary(std::ostream & fs, const owning_data_t & o)
0230 {
0231 utility::write_io_header(fs, IO_MAGIC_HEADER);
0232
0233 fs.write(
0234 reinterpret_cast<const char *>(&o.m_sizes),
0235 sizeof(decltype(m_sizes))
0236 );
0237
0238 decltype(m_storage)::write_binary(fs, o.m_storage);
0239
0240 utility::write_io_footer(fs, IO_MAGIC_HEADER);
0241 }
0242
0243 configuration_t m_sizes;
0244 typename backend_t::owning_data_t m_storage;
0245 };
0246
0247 struct non_owning_data_t {
0248 using parent_t = this_t;
0249
0250 non_owning_data_t(const owning_data_t & o)
0251 : m_sizes(o.m_sizes)
0252 , m_storage(o.m_storage)
0253 {
0254 }
0255
0256 COVFIE_HOST_DEVICE typename covariant_output_t::vector_t
0257 at(coordinate_t c) const
0258 {
0259 #ifndef NDEBUG
0260 for (std::size_t i = 0; i < contravariant_input_t::dimensions; ++i)
0261 {
0262 assert(c[i] < m_sizes[i]);
0263 }
0264 #endif
0265
0266 return m_storage.at(calculate_index(c));
0267 }
0268
0269 typename backend_t::non_owning_data_t & get_backend(void)
0270 {
0271 return m_storage;
0272 }
0273
0274 const typename backend_t::non_owning_data_t & get_backend(void) const
0275 {
0276 return m_storage;
0277 }
0278
0279 configuration_t m_sizes;
0280 typename backend_t::non_owning_data_t m_storage;
0281 };
0282 };
0283 }