commit fd9297e20eb4d07a1f4c5fc99a74f1c9c36e4a78
parent 8450ed6fb4749d0e03e39da510638bbd0c328404
Author: [email protected] <[email protected]>
Date: Wed, 30 Nov 2022 03:54:43 +0000
Histograms
Diffstat:
6 files changed, 149 insertions(+), 79 deletions(-)
diff --git a/include/kfr/base/expression.hpp b/include/kfr/base/expression.hpp
@@ -835,6 +835,32 @@ static auto process(Out&& out, In&& in, shape<outdims> start = shape<outdims>(0)
return stop;
}
+template <typename Tin, index_t Dims>
+struct expression_discard : public expression_traits_defaults
+{
+ using value_type = Tin;
+ constexpr static size_t dims = Dims;
+ constexpr static shape<dims> get_shape(const expression_discard&) { return shape<dims>(infinite_size); }
+ constexpr static shape<dims> get_shape() { return shape<dims>(infinite_size); }
+
+ template <size_t N, index_t VecAxis>
+ friend KFR_INTRINSIC void set_elements(const expression_discard& self, shape<Dims>,
+ axis_params<VecAxis, N>, const identity<vec<Tin, N>>& x)
+ {
+ }
+};
+
+/// @brief Read the expression @c expr through the whole range.
+/// @param expr the input expression
+/// @return the input expression is returned
+template <size_t width = 0, index_t Axis = infinite_size, typename E, typename Traits = expression_traits<E>>
+KFR_FUNCTION const E& sink(E&& expr)
+{
+ static_assert(!Traits::get_shape().has_infinity());
+ process<width, Axis>(expression_discard<expression_value_type<E>, expression_dims<E>>{}, expr);
+ return expr;
+}
+
template <typename Fn, typename... Args>
KFR_FUNCTION expression_function<std::decay_t<Fn>, Args...> bind_expression(Fn&& fn, Args&&... args)
{
diff --git a/include/kfr/base/reduce.hpp b/include/kfr/base/reduce.hpp
@@ -157,6 +157,68 @@ KFR_INTRINSIC Tout reduce(const E1& e1, ReduceFn&& reducefn,
return reduce_call_final(finalfn, counter, result);
}
+template <size_t Bins = 0, typename TCount = uint32_t>
+struct histogram_data
+{
+ using vector_type = univector<TCount, Bins == 0 ? tag_dynamic_vector : 2 + Bins>;
+
+ KFR_MEM_INTRINSIC histogram_data(size_t steps)
+ {
+ if constexpr (Bins == 0)
+ {
+ m_values = vector_type(2 + steps, 0);
+ }
+ }
+
+ KFR_MEM_INTRINSIC TCount operator[](size_t n) const
+ {
+ KFR_LOGIC_CHECK(n < size() - 2, "n is outside histogram size");
+ return m_values[1 + n];
+ }
+ KFR_MEM_INTRINSIC TCount below() const { return m_values.front(); }
+ KFR_MEM_INTRINSIC TCount above() const { return m_values.back(); }
+ KFR_MEM_INTRINSIC size_t size() const { return m_values.size() - 2; }
+ KFR_MEM_INTRINSIC univector_ref<const TCount> values() const { return m_values.slice(1, size()); }
+
+ template <typename T>
+ KFR_MEM_INTRINSIC void put(T value)
+ {
+ const T x = 1 + value * size();
+ ++m_values[std::floor(clamp(x, 0, size() + 1))];
+ }
+
+private:
+ vector_type m_values{};
+};
+
+template <size_t Bins, typename E, typename TCount = uint32_t>
+struct expression_histogram : public expression_with_traits<E>
+{
+ mutable histogram_data<Bins, TCount> data{};
+
+ using expression_with_traits<E>::expression_with_traits;
+
+ KFR_MEM_INTRINSIC expression_histogram(E&& e, size_t steps)
+ : expression_with_traits<E>{ std::forward<E>(e) }, data(steps)
+ {
+ }
+
+ using value_type = typename expression_with_traits<E>::value_type;
+
+ template <index_t Axis, size_t N>
+ friend KFR_INTRINSIC vec<value_type, N> get_elements(const expression_histogram& self,
+ const shape<expression_with_traits<E>::dims>& index,
+ const axis_params<Axis, N>& sh)
+ {
+ vec<value_type, N> v = get_elements(self.first(), index, sh);
+ for (size_t i = 0; i < N; ++i)
+ {
+ self.data.template put<value_type>(v[i]);
+ }
+ return v;
+ }
+};
+
/**
* @brief Returns the sum of all the elements in x.
*
@@ -299,5 +361,45 @@ KFR_FUNCTION T product(const E1& x)
return reduce(x, fn::mul());
}
+/**
+ * @brief Returns expression that computes histogram as data flows through it.
+ * Number of bins defined at runtime
+ */
+template <typename E, typename TCount = uint32_t>
+KFR_FUNCTION expression_histogram<0, E, TCount> histogram_expression(E&& expr, size_t bins)
+{
+ return { std::forward<E>(expr), bins };
+}
+
+/**
+ * @brief Returns expression that computes histogram as data flows through it.
+ * Number of bins defined at compile time
+ */
+template <size_t Bins, typename E, typename TCount = uint32_t>
+KFR_FUNCTION expression_histogram<Bins, E, TCount> histogram_expression(E&& expr)
+{
+ return { std::forward<E>(expr), Bins };
+}
+
+/**
+ * @brief Returns histogram of the expression data.
+ * Number of bins defined at runtime
+ */
+template <typename E, typename TCount = uint32_t>
+KFR_FUNCTION histogram_data<0, TCount> histogram(E&& expr, size_t bins)
+{
+ return sink(histogram_expression(std::forward<E>(expr), bins)).data;
+}
+
+/**
+ * @brief Returns histogram of the expression data.
+ * Number of bins defined at compile time
+ */
+template <size_t Bins, typename E, typename TCount = uint32_t>
+KFR_FUNCTION histogram_data<Bins, TCount> histogram(E&& expr)
+{
+ return sink(histogram_expression(std::forward<E>(expr), Bins)).data;
+}
+
} // namespace CMT_ARCH_NAME
} // namespace kfr
diff --git a/include/kfr/base/tensor.hpp b/include/kfr/base/tensor.hpp
@@ -90,7 +90,7 @@ struct tensor_subscript<T, Derived, std::integer_sequence<index_t, Dims...>>
}
};
-/// @brief tensor holds or references multidimensional data and
+/// @brief tensor holds or references multidimensional data and
/// provides a way to access individual elements and perform complex operations on the data.
///
/// The number of elements in each axis of the array is defined by its shape.
@@ -176,7 +176,7 @@ public:
{
}
- /// @brief Construct from external pointer, shape and finalizer with default strides
+ /// @brief Construct from external pointer, shape and finalizer with default strides
KFR_MEM_INTRINSIC tensor(T* data, const shape_type& shape, memory_finalizer finalizer)
: m_data(data), m_size(size_of_shape(shape)), m_is_contiguous(true), m_shape(shape),
m_strides(internal_generic::strides_for_shape(shape)), m_finalizer(std::move(finalizer))
@@ -234,7 +234,7 @@ public:
{
internal_generic::list_copy_recursively(values, contiguous_begin_unsafe());
}
-
+
/// @brief Initialize with braced list. Defined for 2D tensor only
template <typename U, KFR_ENABLE_IF(std::is_convertible_v<U, T>&& dims == 2)>
KFR_INTRINSIC tensor(const std::initializer_list<std::initializer_list<U>>& values)
@@ -242,7 +242,7 @@ public:
{
internal_generic::list_copy_recursively(values, contiguous_begin_unsafe());
}
-
+
/// @brief Initialize with braced list. Defined for 3D tensor only
template <typename U, KFR_ENABLE_IF(std::is_convertible_v<U, T>&& dims == 3)>
KFR_INTRINSIC tensor(const std::initializer_list<std::initializer_list<std::initializer_list<U>>>& values)
@@ -250,7 +250,7 @@ public:
{
internal_generic::list_copy_recursively(values, contiguous_begin_unsafe());
}
-
+
/// @brief Initialize with braced list. Defined for 4D tensor only
template <typename U, KFR_ENABLE_IF(std::is_convertible_v<U, T>&& dims == 4)>
KFR_INTRINSIC tensor(
@@ -336,7 +336,7 @@ public:
m_finalizer,
};
}
-
+
#if defined(CMT_COMPILER_IS_MSVC)
tensor(const tensor& other)
: m_data(other.m_data), m_size(other.m_size), m_is_contiguous(other.m_is_contiguous),
diff --git a/include/kfr/dsp/waveshaper.hpp b/include/kfr/dsp/waveshaper.hpp
@@ -25,10 +25,10 @@
*/
#pragma once
+#include "../base/expression.hpp"
#include "../math/hyperbolic.hpp"
#include "../simd/clamp.hpp"
#include "../simd/operators.hpp"
-#include "../base/expression.hpp"
namespace kfr
{
diff --git a/include/kfr/dsp/weighting.hpp b/include/kfr/dsp/weighting.hpp
@@ -25,9 +25,9 @@
*/
#pragma once
+#include "../base/expression.hpp"
#include "../math/sqrt.hpp"
#include "../simd/operators.hpp"
-#include "../base/expression.hpp"
namespace kfr
{
diff --git a/tests/unit/base/random.cpp b/tests/unit/base/random.cpp
@@ -73,64 +73,6 @@ TEST(gen_random_range)
// println(mean(v));
}
-template <size_t Bins, typename E, typename TCount = uint32_t>
-struct expression_histogram : public expression_with_traits<E>
-{
- size_t size;
- using vector_type = univector<TCount, Bins == 0 ? tag_dynamic_vector : Bins>;
- mutable vector_type values{};
-
- using expression_with_traits<E>::expression_with_traits;
-
- KFR_MEM_INTRINSIC expression_histogram(E&& e, size_t steps) : expression_with_traits<E>{ std::forward<E>(e) }
- {
- if constexpr (Bins == 0)
- {
- values = vector_type(steps, 0);
- }
- }
-
- KFR_MEM_INTRINSIC TCount operator[](size_t n) const
- {
- KFR_LOGIC_CHECK(n < values.size() - 2, "n is outside histogram size");
- return values[1 + n];
- }
- KFR_MEM_INTRINSIC TCount below() const { return values.front(); }
- KFR_MEM_INTRINSIC TCount above() const { return values.back(); }
- KFR_MEM_INTRINSIC univector_ref<const TCount> histogram() const
- {
- return values.slice(1, values.size());
- }
-
- using value_type = typename expression_with_traits<E>::value_type;
-
- template <index_t Axis, size_t N>
- friend KFR_INTRINSIC vec<value_type, N> get_elements(const expression_histogram& self,
- const shape<expression_with_traits<E>::dims>& index,
- const axis_params<Axis, N>& sh)
- {
- vec<value_type, N> v = get_elements(self.first(), index, sh);
- for (size_t i = 0; i < N; ++i)
- {
- int64_t n = 1 + std::floor(v[i] * (self.values.size() - 2));
- ++self.values[clamp(n, 0, self.values.size() - 1)];
- }
- return v;
- }
-};
-
-template <typename E, typename TCount = uint32_t>
-KFR_INTRINSIC expression_histogram<0, E, TCount> histogram(E&& expr, size_t bins)
-{
- return { std::forward<E>(expr), bins };
-}
-
-template <size_t Bins, typename E, typename TCount = uint32_t>
-KFR_INTRINSIC expression_histogram<Bins, E, TCount> histogram(E&& expr)
-{
- return { std::forward<E>(expr), Bins };
-}
-
TEST(random_normal)
{
random_state gen = random_init(1, 2, 3, 4);
@@ -140,19 +82,19 @@ TEST(random_normal)
vec<fbase, 11> r2 = random_normal<11, fbase>(gen, 0.0, 1.0);
println(r2);
- expression_histogram h = histogram<20>(gen_random_normal<double>() * 0.15 + 0.5);
- render(truncate(h, 1000));
- println(h.below());
- println(h.histogram());
- println(h.above());
- render(truncate(h, 10000));
- println(h.below());
- println(h.histogram());
- println(h.above());
- render(truncate(h, 100000));
- println(h.below());
- println(h.histogram());
- println(h.above());
+ expression_histogram h = histogram_expression<20>(gen_random_normal<double>() * 0.15 + 0.5);
+ sink(truncate(h, 1000));
+ println(h.data.below());
+ println(h.data.values());
+ println(h.data.above());
+ sink(truncate(h, 10000));
+ println(h.data.below());
+ println(h.data.values());
+ println(h.data.above());
+ auto hh = histogram(truncate(h, 100000), 20);
+ println(hh.below());
+ println(hh.values());
+ println(hh.above());
}
} // namespace CMT_ARCH_NAME
} // namespace kfr