vstat
Loading...
Searching...
No Matches
vstat.hpp
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: Copyright 2020-2024 Heal Research
3
4#ifndef VSTAT_HPP
5#define VSTAT_HPP
6
7#include "bivariate.hpp"
8#include "univariate.hpp"
9
10#include <algorithm>
11#include <functional>
12#include <iterator>
13#include <limits>
14
15#include <eve/module/math.hpp>
16#include <eve/module/special.hpp>
17
18namespace VSTAT_NAMESPACE {
19
20namespace detail {
21 // utility method to load data into a wide type
22 template<eve::simd_value T, std::input_iterator I, typename F>
23 requires std::is_invocable_v<F, std::iter_value_t<I>>
24 auto inline load(I iter, F&& func) {
25 return [&]<std::size_t ...Idx>(std::index_sequence<Idx...>){
26 return T{ std::forward<F>(func)(*(iter + Idx))... };
27 }(std::make_index_sequence<T::size()>{});
28 }
29
30 // utility method to advance a set of iterators
31 template<typename Distance, typename... Iters>
32 auto inline advance(Distance d, Iters&... iters) -> void {
33 (std::advance(iters, d), ...);
34 }
35} // namespace detail
36
37namespace concepts {
38 template<typename T>
39 concept arithmetic = std::is_arithmetic_v<T>;
40
41 template<typename F, typename... Args>
42 concept arithmetic_projection = requires(F&&) {
43 { std::is_invocable_v<F, Args...> };
44 { arithmetic<std::remove_reference_t<std::invoke_result_t<F, Args...>>> };
45 };
46} // namespace concepts
47
48
54namespace univariate {
66template<std::floating_point T, std::input_iterator I, typename F = std::identity>
67requires concepts::arithmetic_projection<F, std::iter_value_t<I>>
68inline auto accumulate(I first, std::sized_sentinel_for<I> auto last, F&& f = F{}) noexcept -> univariate_statistics
69{
70 using wide = eve::wide<T>;
71 auto constexpr s{ wide::size() };
72 auto const n{ std::distance(first, last) };
73 auto const m = n - n % s;
74
75 if (n < s) {
76 univariate_accumulator<T> scalar_acc;
77 for (; first < last; ++first) {
78 scalar_acc(std::invoke(std::forward<F>(f), *first));
79 }
80 return univariate_statistics(scalar_acc);
81 }
82
83 univariate_accumulator<wide> acc;
84 for (size_t i = 0; i < m; i += s) {
85 acc(detail::load<wide>(first, std::forward<F>(f)));
86 detail::advance(s, first);
87 }
88
89 // gather the remaining values with a scalar accumulator
90 if (m < n) {
91 auto [sw, sx, sxx] = acc.stats();
92 auto scalar_acc = univariate_accumulator<T>::load_state(sw, sx, sxx);
93 for (; first < last; ++first) {
94 scalar_acc(std::invoke(std::forward<F>(f), *first));
95 }
96 return univariate_statistics(scalar_acc);
97 }
98 return univariate_statistics(acc);
99}
100
113template<std::floating_point T, std::input_iterator I, std::input_iterator J, typename F = std::identity>
114requires concepts::arithmetic_projection<F, std::iter_value_t<I>> and std::is_arithmetic_v<std::iter_value_t<J>>
115inline auto accumulate(I first1, std::sized_sentinel_for<I> auto last1, J first2, F&& f = F{}) noexcept -> univariate_statistics
116{
117 using wide = eve::wide<T>;
118 auto constexpr s{ wide::size() };
119 auto const n { std::distance(first1, last1) };
120 const size_t m = n - n % s;
121
122 if (n < s) {
123 univariate_accumulator<T> scalar_acc;
124 for (; first1 < last1; ++first1, ++first2) {
125 scalar_acc(std::invoke(std::forward<F>(f), *first1), *first2);
126 }
127 return univariate_statistics(scalar_acc);
128 }
129
130 univariate_accumulator<wide> acc;
131 for (size_t i = 0; i < m; i += s) {
132 acc(detail::load<wide>(first1, std::forward<F>(f)), wide(first2, first2 + s));
133 detail::advance(s, first1, first2);
134 }
135
136 // use a scalar accumulator to gather the remaining values
137 if (m < n) {
138 auto [sw, sx, sxx] = acc.stats();
139 auto scalar_acc = univariate_accumulator<T>::load_state(sw, sx, sxx);
140 for (; first1 < last1; ++first1, ++first2) {
141 scalar_acc(std::invoke(std::forward<F>(f), *first1), *first2);
142 }
143 return univariate_statistics(scalar_acc);
144 }
145 return univariate_statistics(acc);
146}
147
165template<std::floating_point T, std::input_iterator I, std::input_iterator J, typename BinaryOp, typename F1 = std::identity, typename F2 = std::identity>
166requires std::is_invocable_v<F1, std::iter_value_t<I>> and
167 std::is_invocable_v<F2, std::iter_value_t<J>> and
168 std::is_invocable_v<
169 BinaryOp,
170 std::invoke_result_t<F1, std::iter_value_t<I>>,
171 std::invoke_result_t<F2, std::iter_value_t<J>>
172 > and
173 concepts::arithmetic_projection<
174 BinaryOp,
175 std::invoke_result_t<F1, std::iter_value_t<I>>,
176 std::invoke_result_t<F2, std::iter_value_t<J>>
177 >
178inline auto accumulate(I first1, std::sized_sentinel_for<I> auto last1, J first2, BinaryOp&& op = BinaryOp{}, F1&& f1 = F1{}, F2&& f2 = F2{}) noexcept -> univariate_statistics
179{
180 using wide = eve::wide<T>;
181 auto constexpr s{ wide::size() };
182 auto const n{ std::distance(first1, last1) };
183 auto const m = n - n % s;
184
185 auto f = [&](auto a, auto b){
186 return std::invoke(std::forward<BinaryOp>(op), std::invoke(std::forward<F1>(f1), a), std::invoke(std::forward<F2>(f2), b));
187 };
188
189 if (n < s) {
190 univariate_accumulator<T> scalar_acc;
191 for (; first1 < last1; ++first1, ++first2) {
192 scalar_acc(f(*first1, *first2));
193 }
194 return univariate_statistics(scalar_acc);
195 }
196
197 std::array<T, s> x;
198 univariate_accumulator<wide> acc;
199 for (size_t i = 0; i < m; i += s) {
200 std::transform(first1, first1 + s, first2, x.begin(), f);
201 acc(wide{x.data()});
202 detail::advance(s, first1, first2);
203 }
204
205 // use a scalar accumulator to gather the remaining values
206 if (m < n) {
207 auto [sw, sx, sxx] = acc.stats();
208 auto scalar_acc = univariate_accumulator<T>::load_state(sw, sx, sxx);
209 for (; first1 < last1; ++first1, ++first2) {
210 scalar_acc(f(*first1, *first2));
211 }
212 return univariate_statistics(scalar_acc);
213 }
214 return univariate_statistics(acc);
215}
216
235template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K, typename BinaryOp, typename F1 = std::identity, typename F2 = std::identity>
236requires std::is_arithmetic_v<std::iter_value_t<K>> &&
237 std::is_invocable_v<F1, std::iter_value_t<I>> &&
238 std::is_invocable_v<F2, std::iter_value_t<J>> &&
239 std::is_invocable_v<
240 BinaryOp,
241 std::invoke_result_t<F1, std::iter_value_t<I>>,
242 std::invoke_result_t<F2, std::iter_value_t<J>>
243 > &&
244 concepts::arithmetic_projection<
245 BinaryOp,
246 std::invoke_result_t<F1, std::iter_value_t<I>>,
247 std::invoke_result_t<F2, std::iter_value_t<J>>
248 >
249inline auto accumulate(I first1, std::sized_sentinel_for<I> auto last1, J first2, K first3, BinaryOp&& op = BinaryOp{}, F1&& f1 = F1{}, F2&& f2 = F2{}) noexcept -> univariate_statistics
250{
251 using wide = eve::wide<T>;
252 auto constexpr s{ wide::size() };
253 auto const n{ std::distance(first1, last1) };
254 auto const m = n - n % s;
255
256 auto f = [&](auto a, auto b){
257 return std::invoke(std::forward<BinaryOp>(op), std::invoke(std::forward<F1>(f1), a), std::invoke(std::forward<F2>(f2), b));
258 };
259
260 if (n < s) {
261 univariate_accumulator<T> scalar_acc;
262 for (; first1 < last1; ++first1, ++first2, ++first3) {
263 scalar_acc(f(*first1, *first2), *first3);
264 }
265 return univariate_statistics(scalar_acc);
266 }
267
268 std::array<T, s> x;
269 univariate_accumulator<wide> acc;
270 for (size_t i = 0; i < m; i += s) {
271 std::transform(first1, first1 + s, first2, x.begin(), f);
272 acc(wide(x), wide(first3, first3 + s));
273 detail::advance(s, first1, first2, first3);
274 }
275
276 // use a scalar accumulator to gather the remaining values
277 if (m < n) {
278 auto [sw, sx, sxx] = acc.stats();
279 auto scalar_acc = univariate_accumulator<T>::load_state(sw, sx, sxx);
280 for (; first1 < last1; ++first1, ++first2, ++first3) {
281 scalar_acc(f(*first1, *first2), *first3);
282 }
283 return univariate_statistics(scalar_acc);
284 }
285 return univariate_statistics(acc);
286}
287} // namespace univariate
288
289namespace bivariate {
333template<std::floating_point T, std::input_iterator I, std::input_iterator J, typename F1 = std::identity, typename F2 = std::identity>
334requires concepts::arithmetic_projection<F1, std::iter_value_t<I>> and
335 concepts::arithmetic_projection<F2, std::iter_value_t<J>>
336inline auto accumulate(I first1, std::sized_sentinel_for<I> auto last1, J first2, F1&& f1 = F1{}, F2&& f2 = F2{})
337{
338 using wide = eve::wide<T>;
339 auto constexpr s { wide::size() };
340 auto const n { std::distance(first1, last1) };
341 auto const m = n - n % s;
342
343 if (n < s) {
344 bivariate_accumulator<T> scalar_acc;
345 for (; first1 < last1; ++first1, ++first2) {
346 scalar_acc(std::invoke(std::forward<F1>(f1), *first1), std::invoke(std::forward<F2>(f2), *first2));
347 }
348 return bivariate_statistics(scalar_acc);
349 }
350
351 bivariate_accumulator<wide> acc;
352 for (size_t i = 0; i < m; i += s) {
353 acc(detail::load<wide>(first1, std::forward<F1>(f1)), detail::load<wide>(first2, std::forward<F2>(f2)));
354 detail::advance(s, first1, first2);
355 }
356
357 if (m < n) {
358 auto [sw, sx, sy, sxx, syy, sxy] = acc.stats();
359 auto scalar_acc = bivariate_accumulator<T>::load_state(sx, sy, sw, sxx, syy, sxy);
360 for (; first1 < last1; ++first1, ++first2) {
361 scalar_acc(std::invoke(std::forward<F1>(f1), *first1), std::invoke(std::forward<F2>(f2), *first2));
362 }
363 return bivariate_statistics(scalar_acc);
364 }
365
366 return bivariate_statistics(acc);
367}
368
369template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K, typename F1 = std::identity, typename F2 = std::identity>
370requires concepts::arithmetic_projection<F1, std::iter_value_t<I>> and
371 concepts::arithmetic_projection<F2, std::iter_value_t<J>> and
372 std::is_arithmetic_v<std::iter_value_t<K>>
373inline auto accumulate(I first1, std::sized_sentinel_for<I> auto last1, J first2, K first3, F1&& f1 = F1{}, F2&& f2 = F2{}) noexcept -> bivariate_statistics
374{
375 using wide = eve::wide<T>;
376 auto constexpr s { wide::size() };
377 auto const n = std::distance(first1, last1);
378 auto const m = n - n % s;
379
380 if (n < s) {
381 bivariate_accumulator<T> scalar_acc;
382 for (; first1 < last1; ++first1, ++first2, ++first3) {
383 scalar_acc(std::invoke(std::forward<F1>(f1), *first1++), std::invoke(std::forward<F2>(f2), *first2++), *first3++);
384 }
385 return bivariate_statistics(scalar_acc);
386 }
387
388 bivariate_accumulator<wide> acc;
389 for (size_t i = 0; i < m; i += s) {
390 acc(
391 detail::load<wide>(first1, std::forward<F1>(f1)),
392 detail::load<wide>(first2, std::forward<F2>(f2)),
393 wide(first3, first3 + s)
394 );
395 detail::advance(s, first1, first2, first3);
396 }
397
398 if (m < n) {
399 auto [sw, sx, sy, sxx, syy, sxy] = acc.stats();
400 auto scalar_acc = bivariate_accumulator<T>::load_state(sx, sy, sw, sxx, syy, sxy);
401 for (; first1 < last1; ++first1, ++first2, ++first3) {
402 scalar_acc(std::invoke(std::forward<F1>(f1), *first1), std::invoke(std::forward<F2>(f2), *first2), *first3);
403 }
404 return bivariate_statistics(scalar_acc);
405 }
406 return bivariate_statistics(acc);
407}
408} // namespace bivariate
409
410namespace metrics {
430template<std::floating_point T, std::input_iterator I, std::input_iterator J>
431inline auto r2_score(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
432 using wide = eve::wide<T>;
433 auto constexpr s{ wide::size() };
434 auto const n{ std::distance(first1, last1) };
435 auto const m{ n - n % s };
436
439 for (auto i = 0; i < m; i += s) {
440 wide y_true{first1, first1+s};
441 wide y_pred{first2, first2+s};
442 wx(eve::sqr(y_true-y_pred));
443 wy(y_true);
444 detail::advance(s, first1, first2);
445 }
446
447 // use scalar accumulators for the remaining values
448 auto sx = univariate_accumulator<T>::load_state(wx.stats());
449 auto sy = univariate_accumulator<T>::load_state(wy.stats());
450
451 for(; first1 < last1; ++first1, ++first2) {
452 sx(eve::sqr(*first1 - *first2));
453 sy(*first1);
454 }
455
456 auto const rss = univariate_statistics(sx).sum;
457 auto const tss = univariate_statistics(sy).ssr;
458
459 return tss < std::numeric_limits<double>::epsilon()
460 ? std::numeric_limits<double>::lowest()
461 : 1.0 - rss / tss;
462}
463
475template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
476inline auto r2_score(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
477 using wide = eve::wide<T>;
478 auto constexpr s{ wide::size() };
479 auto const n{ std::distance(first1, last1) };
480 auto const m{ n - n % s };
481
484 for (auto i = 0; i < m; i += s) {
485 wide y_true{first1, first1+s};
486 wide y_pred{first2, first2+s};
487 wide weight{first3, first3+s};
488 wx(eve::sqr(y_true-y_pred), weight);
489 wy(y_true, weight);
490 detail::advance(s, first1, first2, first3);
491 }
492
493 // use scalar accumulators for the remaining values
494 auto sx = univariate_accumulator<T>::load_state(wx.stats());
495 auto sy = univariate_accumulator<T>::load_state(wy.stats());
496
497 for(; first1 < last1; ++first1, ++first2, ++first3) {
498 sx(eve::sqr(*first1 - *first2), *first3);
499 sy(*first1, *first3);
500 }
501
502 auto const rss = univariate_statistics(sx).sum;
503 auto const tss = univariate_statistics(sy).ssr;
504
505 return tss < std::numeric_limits<double>::epsilon()
506 ? std::numeric_limits<double>::lowest()
507 : 1.0 - rss / tss;
508}
509
519template<std::floating_point T, std::input_iterator I, std::input_iterator J>
520inline auto mean_squared_error(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
521 using wide = eve::wide<T>;
522 auto constexpr s{ wide::size() };
523 auto const n{ std::distance(first1, last1) };
524 auto const m{ n - n % s };
525
527 for (auto i = 0; i < m; i += s) {
528 wide y_true{first1, first1+s};
529 wide y_pred{first2, first2+s};
530 we(eve::sqr(y_true-y_pred));
531 detail::advance(s, first1, first2);
532 }
533
534 // use scalar accumulators for the remaining values
535 auto se = univariate_accumulator<T>::load_state(we.stats());
536 for(; first1 < last1; ++first1, ++first2) {
537 se(eve::sqr(*first1 - *first2));
538 }
539 return univariate_statistics(se).mean;
540}
541
551template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
552inline auto mean_squared_error(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
553 using wide = eve::wide<T>;
554 auto constexpr s{ wide::size() };
555 auto const n{ std::distance(first1, last1) };
556 auto const m{ n - n % s };
557
559 for (auto i = 0; i < m; i += s) {
560 wide y_true{first1, first1+s};
561 wide y_pred{first2, first2+s};
562 wide weight{first3, first3+s};
563 we(eve::sqr(y_true-y_pred), weight);
564 detail::advance(s, first1, first2, first3);
565 }
566
567 // use scalar accumulators for the remaining values
568 auto se = univariate_accumulator<T>::load_state(we.stats());
569 for(; first1 < last1; ++first1, ++first2, ++first3) {
570 se(eve::sqr(*first1 - *first2), *first3);
571 }
572 return univariate_statistics(se).mean;
573}
574
584template<std::floating_point T, std::input_iterator I, std::input_iterator J>
585inline auto mean_squared_log_error(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
586 using wide = eve::wide<T>;
587 auto constexpr s{ wide::size() };
588 auto const n{ std::distance(first1, last1) };
589 auto const m{ n - n % s };
590
592 for (auto i = 0; i < m; i += s) {
593 wide y_true{first1, first1+s};
594 wide y_pred{first2, first2+s};
595 we(eve::sqr(eve::log1p(y_true)-eve::log1p(y_pred)));
596 detail::advance(s, first1, first2);
597 }
598
599 // use scalar accumulators for the remaining values
600 auto se = univariate_accumulator<T>::load_state(we.stats());
601 for(; first1 < last1; ++first1, ++first2) {
602 se(eve::sqr(eve::log1p(*first1) - eve::log1p(*first2)));
603 }
604 return univariate_statistics(se).mean;
605}
606
616template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
617inline auto mean_squared_log_error(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
618 using wide = eve::wide<T>;
619 auto constexpr s{ wide::size() };
620 auto const n{ std::distance(first1, last1) };
621 auto const m{ n - n % s };
622
624 for (auto i = 0; i < m; i += s) {
625 wide y_true{first1, first1+s};
626 wide y_pred{first2, first2+s};
627 wide weight{first3, first3+s};
628 we(eve::sqr(eve::log1p(y_true)-eve::log1p(y_pred)), weight);
629 detail::advance(s, first1, first2, first3);
630 }
631
632 // use scalar accumulators for the remaining values
633 auto se = univariate_accumulator<T>::load_state(we.stats());
634 for(; first1 < last1; ++first1, ++first2, ++first3) {
635 se(eve::sqr(eve::log1p(*first1) - eve::log1p(*first2)), *first3);
636 }
637 return univariate_statistics(se).mean;
638}
639
649template<std::floating_point T, std::input_iterator I, std::input_iterator J>
650inline auto mean_absolute_error(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
651 using wide = eve::wide<T>;
652 auto constexpr s{ wide::size() };
653 auto const n{ std::distance(first1, last1) };
654 auto const m{ n - n % s };
655
657 for (auto i = 0; i < m; i += s) {
658 wide y_true{first1, first1+s};
659 wide y_pred{first2, first2+s};
660 we(eve::abs(y_true-y_pred));
661 detail::advance(s, first1, first2);
662 }
663
664 // use scalar accumulators for the remaining values
665 auto se = univariate_accumulator<T>::load_state(we.stats());
666 for(; first1 < last1; ++first1, ++first2) {
667 se(eve::abs(*first1 - *first2));
668 }
669 return univariate_statistics(se).mean;
670}
671
681template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
682inline auto mean_absolute_error(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
683 using wide = eve::wide<T>;
684 auto constexpr s{ wide::size() };
685 auto const n{ std::distance(first1, last1) };
686 auto const m{ n - n % s };
687
689 for (auto i = 0; i < m; i += s) {
690 wide y_true{first1, first1+s};
691 wide y_pred{first2, first2+s};
692 wide weight{first3, first3+s};
693 we(eve::abs(y_true-y_pred), weight);
694 detail::advance(s, first1, first2, first3);
695 }
696
697 // use scalar accumulators for the remaining values
698 auto se = univariate_accumulator<T>::load_state(we.stats());
699 for(; first1 < last1; ++first1, ++first2, ++first3) {
700 se(eve::abs(*first1 - *first2), *first3);
701 }
702 return univariate_statistics(se).mean;
703}
704
717template<std::floating_point T, std::input_iterator I, std::input_iterator J>
718inline auto mean_absolute_percentage_error(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
719 using wide = eve::wide<T>;
720 auto constexpr s{ wide::size() };
721 auto const n{ std::distance(first1, last1) };
722 auto const m{ n - n % s };
723
724 auto constexpr eps{ std::numeric_limits<T>::epsilon() };
725
727 for (auto i = 0; i < m; i += s) {
728 wide y_true{first1, first1+s};
729 wide y_pred{first2, first2+s};
730 we(eve::abs(y_true-y_pred) / eve::max(eps, eve::abs(y_true)));
731 detail::advance(s, first1, first2);
732 }
733
734 // use scalar accumulators for the remaining values
735 auto se = univariate_accumulator<T>::load_state(we.stats());
736 for(; first1 < last1; ++first1, ++first2) {
737 se(eve::abs(*first1 - *first2) / eve::max(eps, eve::abs(*first1)));
738 }
739 return univariate_statistics(se).mean;
740}
741
751template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
752inline auto mean_absolute_percentage_error(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
753 using wide = eve::wide<T>;
754 auto constexpr s{ wide::size() };
755 auto const n{ std::distance(first1, last1) };
756 auto const m{ n - n % s };
757
759 for (auto i = 0; i < m; i += s) {
760 wide y_true{first1, first1+s};
761 wide y_pred{first2, first2+s};
762 wide weight{first3, first3+s};
763 we(eve::abs(y_true-y_pred), weight);
764 detail::advance(s, first1, first2, first3);
765 }
766
767 // use scalar accumulators for the remaining values
768 auto se = univariate_accumulator<T>::load_state(we.stats());
769 for(; first1 < last1; ++first1, ++first2, ++first3) {
770 se(eve::abs(*first1 - *first2), *first3);
771 }
772 return univariate_statistics(se).mean;
773}
774
784template<std::floating_point T, std::input_iterator I, std::input_iterator J>
785inline auto poisson_neg_likelihood_loss(I first1, std::sentinel_for<I> auto last1, J first2) noexcept -> double {
786 using wide = eve::wide<T>;
787 auto constexpr s{ wide::size() };
788 auto const n{ std::distance(first1, last1) };
789 auto const m{ n - n % s };
790
791 auto constexpr eps{ std::numeric_limits<T>::epsilon() };
792
794 for (auto i = 0; i < m; i += s) {
795 wide y_true{first1, first1+s};
796 wide y_pred{first2, first2+s};
797 we(y_pred - y_true * eve::log(y_pred) + eve::log_abs_gamma(T{1} + y_true));
798 detail::advance(s, first1, first2);
799 }
800
801 // use scalar accumulators for the remaining values
802 auto se = univariate_accumulator<T>::load_state(we.stats());
803 for(; first1 < last1; ++first1, ++first2) {
804 se(*first2 - *first1 * eve::log(*first2) + eve::log_abs_gamma(T{1} + *first1));
805 }
806 return univariate_statistics(se).sum;
807}
808
818template<std::floating_point T, std::input_iterator I, std::input_iterator J, std::input_iterator K>
819inline auto poisson_neg_likelihood_loss(I first1, std::sentinel_for<I> auto last1, J first2, K first3) noexcept -> double {
820 using wide = eve::wide<T>;
821 auto constexpr s{ wide::size() };
822 auto const n{ std::distance(first1, last1) };
823 auto const m{ n - n % s };
824
825 auto constexpr eps{ std::numeric_limits<T>::epsilon() };
826
828 for (auto i = 0; i < m; i += s) {
829 wide y_true{first1, first1+s};
830 wide y_pred = eve::mul(wide{first2, first2+s}, wide{first3, first3+s});
831 we(y_pred - y_true * eve::log(y_pred) + eve::log_abs_gamma(T{1} + y_true));
832 detail::advance(s, first1, first2, first3);
833 }
834
835 // use scalar accumulators for the remaining values
836 auto se = univariate_accumulator<T>::load_state(we.stats());
837 for(; first1 < last1; ++first1, ++first2, ++first3) {
838 se(*first2 * *first3 - *first1 * eve::log(*first2 * *first3) + eve::log_abs_gamma(T{1} + *first1));
839 }
840 return univariate_statistics(se).sum;
841}
842} // namespace metrics
843
844} // namespace VSTAT_NAMESPACE
845
846#endif
auto poisson_neg_likelihood_loss(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Negative log likelihood loss with Poisson distribution of target.
Definition vstat.hpp:785
auto mean_absolute_error(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Computes the mean absolute error.
Definition vstat.hpp:650
auto mean_absolute_percentage_error(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Computes the mean absolute error.
Definition vstat.hpp:718
auto r2_score(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Computes the coefficient of determination .
Definition vstat.hpp:431
auto mean_squared_log_error(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Computes the mean squared logarithmic error.
Definition vstat.hpp:585
auto mean_squared_error(I first1, std::sentinel_for< I > auto last1, J first2) noexcept -> double
Computes the mean squared error.
Definition vstat.hpp:520
auto accumulate(I first, std::sized_sentinel_for< I > auto last, F &&f=F{}) noexcept -> univariate_statistics
Accumulates a sequence of (projected) values.
Definition vstat.hpp:68
Univariate accumulator object.
Definition univariate.hpp:14
Univariate statistics.
Definition univariate.hpp:84