GCC Code Coverage Report


Directory: include/polyfloat/
File: include/polyfloat/module/core/cosine_similarity.hpp
Date: 2026-11-09 15:28:50
Exec Total Coverage
Lines: 17 17 100.0%
Functions: 24 24 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 POLYFLOAT - Extended precision floating points
4 Copyright : POLYFLOAT Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <polyfloat/details/callable.hpp>
11 #include <polyfloat/types/concepts.hpp>
12 #include <polyfloat/types/traits.hpp>
13 #include <type_traits>
14 #include <polyfloat/module/core/dot.hpp>
15 #include <polyfloat/module/core/sum_of_squares.hpp>
16
17 namespace plf
18 {
19 template<typename Options>
20 struct cosine_similarity_t
21 : eve::strict_tuple_callable<cosine_similarity_t, Options, kahan_option, raw_option, pedantic_option>
22 {
23 template<typename... Ts> struct result : as_polyfloat_like<Ts...>
24 {
25 };
26
27 template<concepts::polyfloat_like... Ts>
28 requires(eve::same_lanes_or_scalar<Ts...>)
29 8 POLYFLOAT_ABI typename result<Ts...>::type constexpr operator()(Ts... ts) const noexcept
30 {
31 8 return POLYFLOAT_CALL(ts...);
32 }
33
34 template<eve::non_empty_product_type Tup1, eve::non_empty_product_type Tup2>
35 8 POLYFLOAT_ABI constexpr kumi::apply_traits_t<result, kumi::result::cat_t<Tup1, Tup2>> operator()(
36 Tup1 const& t1, Tup2 const& t2) const noexcept
37 requires(eve::same_lanes_or_scalar_tuple<Tup1> && eve::same_lanes_or_scalar_tuple<Tup2> &&
38 (Tup1::size() == Tup2::size()) && !concepts::polyfloat_like<Tup1> && !concepts::polyfloat_like<Tup2>)
39 {
40 8 return POLYFLOAT_CALL(t1, t2);
41 }
42
43 template<eve::non_empty_product_type Tup>
44 requires(eve::same_lanes_or_scalar_tuple<Tup> && !concepts::polyfloat_like<Tup>)
45 POLYFLOAT_ABI constexpr kumi::apply_traits_t<result, Tup> operator()(Tup const& t) const noexcept
46 requires(kumi::size_v<Tup> >= 1)
47 {
48 return POLYFLOAT_CALL(t);
49 }
50
51 16 POLYFLOAT_CALLABLE_OBJECT(cosine_similarity_t, cosine_similarity_);
52 };
53 //======================================================================================================================
54 //! @addtogroup core
55 //! @{
56 //! @var cosine_similarity
57 //! @brief return the cosine_similarity product of the vector of the first half of parameters by
58 //! the vector of the second half.
59 //!
60 //! @groupheader{Header file}
61 //!
62 //! @code
63 //! #include <polyfloat/module/core.hpp>
64 //! @endcode
65 //!
66 //! @groupheader{Callable Signatures}
67 //!
68 //! @code
69 //! namespace polyfloat
70 //! {
71 //! // Regular overloads
72 //! constexpr auto cosine_similarity(auto ... xs, auto value... ys) noexcept; // 1
73 //! constexpr auto cosine_similarity(kumi::tuple xs, kumi::tuple ys) noexcept; // 2
74 //! }
75 //! @endcode
76 //!
77 //! **Parameters**
78 //!
79 //! * `xs`, `ys`: Values to process.
80 //!
81 //! **Return value**
82 //!
83 //! 1. cosine_similarity product. \f$\frac{\sum_s (x_s*y_s)}{\sqrt{\sum_s (x_s^2)*\sum_s (y_s^2)}}\f$.
84 //! It is the cosine of the angle between the two vectors. One or minus one means thaat the vectors are proportionnal,
85 //! zero that they are orthogonal.
86 //! 2. use the content of the tuples
87 //!
88 //! @groupheader{Example}
89 //!
90 //! @godbolt_todo{doc/core/core/cosine_similarity.cpp}
91 //======================================================================================================================
92
93 inline constexpr auto cosine_similarity = eve::functor<cosine_similarity_t>;
94 //======================================================================================================================
95 //! @}
96 //======================================================================================================================
97 }
98
99 namespace plf::_
100 {
101
102 template<eve::callable_options O, concepts::polyfloat_like... Ts>
103 8 constexpr auto cosine_similarity_(POLYFLOAT_DELAY(), O const&, Ts const&... args) noexcept
104 requires(sizeof...(Ts) > 1 && sizeof...(Ts) % 2 == 0)
105 {
106 using r_t = as_polyfloat_like_t<Ts...>;
107 using u_t = eve::element_type_t<r_t>;
108 16 auto cvt = [](auto a) { return plf::convert(a, as<u_t>()); };
109 8 auto coeffs = eve::zip(cvt(args)...);
110 24 auto [f, s] = kumi::split(coeffs, kumi::index<sizeof...(Ts) / 2>);
111 8 return cosine_similarity(f, s);
112 }
113
114 template<eve::non_empty_product_type PT1, eve::non_empty_product_type PT2, eve::callable_options O>
115 8 constexpr auto cosine_similarity_(POLYFLOAT_DELAY(), O const& o, PT1 f, PT2 s) noexcept
116 requires(kumi::as_tuple_t<PT1>::size() == kumi::as_tuple_t<PT2>::size() && !concepts::polyfloat_like<PT1> &&
117 !concepts::polyfloat_like<PT2>)
118 {
119 using Tup1 = kumi::as_tuple_t<PT1>;
120 8 constexpr auto siz = Tup1::size();
121 if constexpr (siz == 1)
122 {
123 return plf::sign(get<0>(f) * get<0>(s));
124 }
125 else
126 {
127 8 auto sa2 = plf::sum_of_squares[o](f);
128 8 auto sb2 = plf::sum_of_squares[o](s);
129 8 auto sab = plf::dot[o](f, s);
130 8 auto r = sab * plf::rsqrt(sa2 * sb2);
131 8 return plf::if_else(plf::is_eqz(sab), zero, plf::if_else(is_eqz(sa2) || is_eqz(sb2), sa2 * sb2, r));
132 }
133 }
134 }
135