File: verifier.hpp

package info (click to toggle)
gridtools 2.3.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 29,480 kB
  • sloc: cpp: 228,792; python: 17,561; javascript: 9,164; ansic: 4,101; sh: 850; makefile: 231; f90: 201
file content (166 lines) | stat: -rw-r--r-- 6,867 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * GridTools
 *
 * Copyright (c) 2014-2023, ETH Zurich
 * All rights reserved.
 *
 * Please, refer to the LICENSE file in the root directory.
 * SPDX-License-Identifier: BSD-3-Clause
 */
#pragma once

#include <iostream>
#include <memory>
#include <type_traits>

#include <gridtools/common/array.hpp>
#include <gridtools/common/array_addons.hpp>
#include <gridtools/common/gt_math.hpp>
#include <gridtools/common/hypercube_iterator.hpp>
#include <gridtools/common/tuple_util.hpp>
#include <gridtools/storage/data_store.hpp>

namespace gridtools {
    namespace impl_ {
        template <class T>
        struct default_precision_impl {
            static constexpr double value = 0;
        };

        template <>
        struct default_precision_impl<float> {
            static constexpr double value = 1e-6;
        };

        template <>
        struct default_precision_impl<double> {
            static constexpr double value = 1e-14;
        };
    } // namespace impl_

    template <class T>
    GT_FUNCTION double default_precision() {
        return impl_::default_precision_impl<T>::value;
    }

    template <class T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
    GT_FUNCTION bool expect_with_threshold(T expected, T actual, double precision = default_precision<T>()) {
        auto abs_error = math::fabs(expected - actual);
        auto abs_max = math::max(math::fabs(expected), math::fabs(actual));
        return abs_error < precision || abs_error < abs_max * precision;
    }

    template <class T, std::enable_if_t<!std::is_floating_point_v<T> && !tuple_util::is_tuple_like<T>::value, int> = 0>
    GT_FUNCTION bool expect_with_threshold(T const &expected, T const &actual, double = 0) {
        return actual == expected;
    }

    template <class T, std::enable_if_t<tuple_util::is_tuple_like<T>::value, int> = 0>
    GT_FUNCTION bool expect_with_threshold(T const &expected,
        T const &actual,
        double precision = default_precision<std::decay_t<decltype(tuple_util::get<0>(std::declval<T>()))>>()) {
        return tuple_util::all_of(
            [=](auto const &ex, auto const &ac) { return expect_with_threshold(ex, ac, precision); }, expected, actual);
    }

    namespace verify_impl_ {
        template <class F, class Indices, size_t... Is>
        auto apply_impl(F const &fun, Indices const &indices, std::index_sequence<Is...>)
            -> decltype(fun(tuple_util::get<Is>(indices)...)) {
            return fun(tuple_util::get<Is>(indices)...);
        }
        template <class F, class Indices>
        auto apply(F const &fun, Indices const &indices) -> decltype(verify_impl_::apply_impl(
            fun, indices, std::make_index_sequence<tuple_util::size<Indices>::value>())) {
            return apply_impl(fun, indices, std::make_index_sequence<tuple_util::size<Indices>::value>());
        }

        template <class F, size_t N, class = void>
        struct is_view_compatible : std::false_type {};

        template <class F, size_t N>
        struct is_view_compatible<F,
            N,
            std::void_t<decltype(verify_impl_::apply(std::declval<F const &>(), array<size_t, N>{}))>>
            : std::true_type {};

        struct default_equal_to {
            template <class T>
            bool operator()(T lhs, T rhs) const {
                return expect_with_threshold(lhs, rhs);
            }
        };

        template <class T, std::enable_if_t<tuple_util::is_tuple_like<T>::value, int> = 0>
        std::ostream &operator<<(std::ostream &out, T const &t) {
            out << "{";
            bool first = true;
            tuple_util::for_each(
                [&](auto const &x) {
                    if (first)
                        first = false;
                    else
                        out << ", ";
                    out << x;
                },
                t);
            out << "}";
            return out;
        }

        template <class Expected, class Actual, size_t NDims, class EqualTo = default_equal_to>
        bool verify_generic(Expected const &expected,
            Actual const &actual,
            array<array<size_t, 2>, NDims> const &bounds,
            EqualTo equal_to = {}) {
            static constexpr size_t err_lim = 20;
            size_t err_count = 0;
            for (auto &&pos : make_hypercube_view(bounds)) {
                auto a = verify_impl_::apply(actual, pos);
                decltype(a) e = verify_impl_::apply(expected, pos);
                if (equal_to(e, a))
                    continue;
                if (err_count < err_lim)
                    std::cout << "Error in position " << pos << " ; expected : " << e << " ; actual : " << a << "\n";
                err_count++;
            }
            if (err_count > err_lim)
                std::cout << "Displayed the first " << err_lim << " errors, " << err_count - err_lim << " skipped!"
                          << std::endl;
            return err_count == 0;
        }

        template <class Expected, class DataStore, class Halos, class EqualTo = default_equal_to>
        std::enable_if_t<storage::is_data_store<DataStore>::value &&
                             is_view_compatible<Expected, DataStore::ndims>::value,
            bool>
        verify_data_store(Expected const &expected,
            std::shared_ptr<DataStore> const &actual,
            Halos const &halos,
            EqualTo equal_to = {}) {
            array<array<size_t, 2>, DataStore::ndims> bounds;
            auto &&lengths = actual->lengths();
            for (size_t i = 0; i < bounds.size(); ++i)
                bounds[i] = {halos[i][0], lengths[i] - halos[i][1]};
            auto view = actual->const_host_view();
            return verify_generic(expected, view, bounds, equal_to);
        }

        template <class DataStore, class Halos, class EqualTo = default_equal_to>
        std::enable_if_t<storage::is_data_store_ptr<DataStore>::value, bool> verify_data_store(
            DataStore const &expected, DataStore const &actual, Halos const &halos, EqualTo equal_to = {}) {
            return verify_data_store(expected->const_host_view(), actual, halos, equal_to);
        }

        template <class T, class DataStore, class Halos, class EqualTo = default_equal_to>
        std::enable_if_t<storage::is_data_store<DataStore>::value &&
                             std::is_convertible<T, typename DataStore::data_t>::value,
            bool>
        verify_data_store(
            T const &expected, std::shared_ptr<DataStore> const &actual, Halos const &halos, EqualTo equal_to = {}) {
            return verify_data_store([=](auto &&...) { return expected; }, actual, halos, equal_to);
        }
    } // namespace verify_impl_
    using verify_impl_::default_equal_to;
    using verify_impl_::verify_data_store;
} // namespace gridtools