diff options
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/codec/c++/data.hpp | 27 | ||||
| -rw-r--r-- | modules/codec/c++/data_math.hpp | 21 | ||||
| -rw-r--r-- | modules/codec/c++/math.hpp | 62 | ||||
| -rw-r--r-- | modules/codec/tests/math.cpp | 25 |
4 files changed, 122 insertions, 13 deletions
diff --git a/modules/codec/c++/data.hpp b/modules/codec/c++/data.hpp index c43402e..a8b7836 100644 --- a/modules/codec/c++/data.hpp +++ b/modules/codec/c++/data.hpp @@ -330,13 +330,28 @@ public: { } - /* + /** + * Forwarding constructor, so the elements can be written without + * spelling out the inner array. + * + * data<FixedArray<UInt64,3>>{0,1,2} instead of {{0,1,2}} + * + * The guards keep it out of the way of the copy and the meta schema + * constructor in the single element case. + * + * Explicit for a single element, because a one dimensional index would + * otherwise be convertible to both data<UInt64> and this, which makes + * the two at overloads of data<Array<T,1>> ambiguous. + */ template<typename... Args> - requires (sizeof...(Args) == ct_multiply<uint64_t, D...>::value) && - (std::constructible_from<data<T, encode::Native>, Args> && ...) - constexpr data(Args&&... args): - value_{ { std::forward<Args>(args)... } } {} - */ + requires (sizeof...(Args) == ct_multiply<uint64_t, D...>::value) + && (sizeof...(Args) > 1u + || (!std::same_as<std::remove_cvref_t<Args>, data> && ...)) + && (!std::same_as<std::remove_cvref_t<Args>, data<MetaSchema, encode::Native>> && ...) + && (std::constructible_from<data<T, encode::Native>, Args> && ...) + explicit(sizeof...(Args) == 1u) constexpr data(Args&&... args): + value_{ data<T, encode::Native>{std::forward<Args>(args)}... } + {} SAW_DEFAULT_COPY(data); SAW_DEFAULT_MOVE(data); diff --git a/modules/codec/c++/data_math.hpp b/modules/codec/c++/data_math.hpp index 9d07eb3..7caedd9 100644 --- a/modules/codec/c++/data_math.hpp +++ b/modules/codec/c++/data_math.hpp @@ -93,6 +93,27 @@ public: values_{inner_values__} {} + /** + * Forwarding constructor, so a tensor can be written as its elements + * in row major order. + * + * data<Tensor<Float64,2u,2u>>{1.0, 2.0, 3.0, 4.0} + * data<Scalar<Float32>>{5.1f} + * + * The guards keep it out of the way of the copy constructor and of the + * two constructors above in the single element case. + */ + template<typename... Args> + requires (sizeof...(Args) == ct_multiply<uint64_t, Dims...>::value) + && (sizeof...(Args) > 1u + || (!std::same_as<std::remove_cvref_t<Args>, data> && ...)) + && (!std::same_as<std::remove_cvref_t<Args>, data<Inner, encode::Native>> && ...) + && (!std::same_as<std::remove_cvref_t<Args>, data<schema::FixedArray<Inner, Dims...>, encode::Native>> && ...) + && (std::constructible_from<data<Inner, encode::Native>, Args> && ...) + data(Args&&... args): + values_{std::forward<Args>(args)...} + {} + data<Inner, encode::Native>& at(const data<schema::FixedArray<schema::UInt64, sizeof...(Dims)>, encode::Native>& index){ return values_.at(index); } diff --git a/modules/codec/c++/math.hpp b/modules/codec/c++/math.hpp index 1d627e6..f831256 100644 --- a/modules/codec/c++/math.hpp +++ b/modules/codec/c++/math.hpp @@ -36,12 +36,30 @@ public: }; namespace math { -/* +/** + * Builds a scalar from its native value. Shorthand for the two step + * data<T>{value} -> data<Scalar<T>>{...} conversion, which the language won't + * do implicitly. + */ template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> -data<typename T::InnerType,Encoding> norm_2(const data<T,Encoding>& d){ - return {}; +constexpr data<schema::Scalar<T>, Encoding> make_scalar(typename native_data_type<T>::type value){ + return data<schema::Scalar<T>, Encoding>{data<T,Encoding>{value}}; +} + +/** + * Builds a vector from its native component values. The dimension is deduced + * from the argument count. + */ +template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING, typename... Args> +constexpr data<schema::Vector<T,sizeof...(Args)>, Encoding> make_vector(Args... args){ + return data<schema::Vector<T,sizeof...(Args)>, Encoding>{ + data<schema::FixedArray<T,sizeof...(Args)>, Encoding>{ + std::array<data<T,Encoding>, sizeof...(Args)>{ + data<T,Encoding>{static_cast<typename native_data_type<T>::type>(args)}... + } + } + }; } -*/ template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> data<schema::Scalar<T>, Encoding> dot(const data<schema::Vector<T,D>, Encoding>& left, const data<schema::Vector<T,D>, Encoding>& right){ @@ -61,6 +79,14 @@ data<schema::Scalar<T>,Encoding> sqrt(const data<schema::Scalar<T>,Encoding>& in return out; } +/** + * Euclidean length of a vector. + */ +template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> +data<schema::Scalar<T>, Encoding> norm(const data<schema::Vector<T,D>, Encoding>& input){ + return sqrt<T,Encoding>(dot<T,D,Encoding>(input,input)); +} + template<typename T, uint64_t D, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> data<schema::Vector<T,D>, Encoding> normalize(const data<schema::Vector<T,D>>& input ) { auto inp_dot = dot<T,D,Encoding>(input,input); @@ -174,6 +200,32 @@ data<schema::Scalar<T>,Encoding> sin( } +/** + * Angle of a 2d vector measured counter clockwise from the positive x axis. + * Inverse of unit_vector(). + */ +template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> +data<schema::Scalar<T>,Encoding> angle( + const data<schema::Vector<T,2u>, Encoding>& vec +){ + data<schema::Scalar<T>,Encoding> ret; + ret.at({}).set(std::atan2(vec.at({{1u}}).get(), vec.at({{0u}}).get())); + return ret; +} + +/** + * Unit length 2d vector pointing along the given angle. Inverse of angle(). + */ +template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> +data<schema::Vector<T,2u>,Encoding> unit_vector( + const data<schema::Scalar<T>, Encoding>& rot +){ + data<schema::Vector<T,2u>,Encoding> ret; + ret.at({{0u}}) = cos<T,Encoding>(rot).at({}); + ret.at({{1u}}) = sin<T,Encoding>(rot).at({}); + return ret; +} + template<typename T, typename Encoding = FORSTIO_DEFAULT_DATA_ENCODING> data<schema::Vector<T,2u>,Encoding> rotate( const data<schema::Vector<T,2u>, Encoding> vec, @@ -192,7 +244,7 @@ data<schema::Vector<T,D>,Encoding> scale( ){ data<schema::Vector<T,D>, Encoding> sc_vec; for(uint64_t i = 0u; i< D; ++i){ - sc_vec.at({{i}}) = vec.at({{i}}) * scale; + sc_vec.at({{i}}) = vec.at({{i}}) * scale.at({}); } return sc_vec; } diff --git a/modules/codec/tests/math.cpp b/modules/codec/tests/math.cpp index 18b6c41..ad79c95 100644 --- a/modules/codec/tests/math.cpp +++ b/modules/codec/tests/math.cpp @@ -24,8 +24,29 @@ SAW_TEST("Math/Basic"){ SAW_TEST("Math/Tensor Construction"){ using namespace saw; - // data<sch::Scalar<sch::Float32>> a{{5.1f}}; - // data<sch::Vector<sch::Int32,3u>> b{{{1,3,5}}}; + data<sch::Vector<sch::Int32,3u>> b{1,3,5}; + + /** + * A one dimensional index keeps the inner braces, since a single + * element has to stay explicit to not clash with data<UInt64>. + */ + SAW_EXPECT(b.at({{0u}}).get() == 1, "Wrong value at 0"); + SAW_EXPECT(b.at({{1u}}).get() == 3, "Wrong value at 1"); + SAW_EXPECT(b.at({{2u}}).get() == 5, "Wrong value at 2"); + + /** + * From two dimensions up the index forwards, since it is a FixedArray + * itself. + * + * The elements are given in flat order, and get_flat_index runs the + * stride from dimension zero up, so the first index varies fastest. + */ + data<sch::Matrix<sch::Float64,2u,2u>> c{1.0, 2.0, 3.0, 4.0}; + + SAW_EXPECT(c.at({0u,0u}).get() == 1.0, "Wrong value at 0,0"); + SAW_EXPECT(c.at({1u,0u}).get() == 2.0, "Wrong value at 1,0"); + SAW_EXPECT(c.at({0u,1u}).get() == 3.0, "Wrong value at 0,1"); + SAW_EXPECT(c.at({1u,1u}).get() == 4.0, "Wrong value at 1,1"); } SAW_TEST("Math/Tensor Fill"){ |
