liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
//
//  Copyright (c) 2018-2019, Cem Bassoy, cem.bassoy@gmail.com
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
//  The authors gratefully acknowledge the support of
//  Fraunhofer IOSB, Ettlingen, Germany
//
 
#ifndef BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
#define BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP
 
 
#include <tuple>
#include <type_traits>
 
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
 
template<class ... index_types>
struct has_index_impl;
 
template<class itype_left, class itype_right>
struct has_index_impl<itype_left, itype_right>
{
    static constexpr bool value = itype_left::value == itype_right::value;
};
 
template<class itype_left>
struct has_index_impl <itype_left, std::tuple<> >
{
    static constexpr bool value = false;
};
 
template<class itype_left, class itype_right>
struct has_index_impl <itype_left, std::tuple<itype_right> >
{
    static constexpr bool value = has_index_impl<itype_left,itype_right>::value;
};
 
template<class itype_left, class itype_right, class ... index_types>
struct has_index_impl <itype_left, std::tuple<itype_right, index_types...> >
{
    using next_type = has_index_impl<itype_left, std::tuple<index_types...>>;
    static constexpr bool value = has_index_impl<itype_left,itype_right>::value || next_type::value;
};
} // namespace detail
 
 
 
/** @brief has_index is true if index occurs once or more in a multi-index
 *
 * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
 *
 * @code auto has_index_value = has_index<index_type<1>, std::tuple<index_type<2>,index_type<1>> >::value; @endcode
 *
 * @tparam index_type type of index
 * @tparam tuple_type type of std::tuple representing a multi-index
*/
template<class index_type, class tuple_type>
struct has_index
{
    static constexpr bool value = detail::has_index_impl<std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
};
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
////////////////////////////////////////////////
////////////////////////////////////////////////
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
 
template<class ... index_types>
struct valid_multi_index_impl;
 
template<>
struct valid_multi_index_impl<std::tuple<>>
{
    static constexpr bool value = true;
};
 
template<class itype>
struct valid_multi_index_impl<std::tuple<itype>>
{
    static constexpr bool value = true;
};
 
 
template<class itype, class ... index_types>
struct valid_multi_index_impl<std::tuple<itype,index_types...>>
{
    using ttype     = std::tuple<index_types...>;
    using has_index_type = has_index<itype, ttype>;
 
    static constexpr bool is_index_zero   = itype::value==0ul;
    static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
    static constexpr bool value = !has_index_value && valid_multi_index_impl<ttype>::value;
};
} // namespace detail
 
/** @brief valid_multi_index is true if indexes occur only once in a multi-index
 *
 * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
 *
 * @code auto valid = valid_multi_index<  std::tuple<index_type<2>,index_type<1>>  >::value;
 * @endcode
 *
 * @tparam tuple_type type of std::tuple representing a multi-index
*/
template<class tupe_type>
struct valid_multi_index
{
    static constexpr bool value = detail::valid_multi_index_impl<std::decay_t<tupe_type>>::value;
};
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
////////////////////////////////////////////////
////////////////////////////////////////////////
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
template<class ... index_types >
struct number_equal_indexes_impl;
 
template<class ... itypes_right >
struct number_equal_indexes_impl < std::tuple<>, std::tuple<itypes_right...>>
{
    static constexpr unsigned value  = 0;
};
 
template<class itype, class ... itypes_left, class ... itypes_right>
struct number_equal_indexes_impl < std::tuple<itype,itypes_left...>, std::tuple<itypes_right...>>
{
    using tuple_right = std::tuple<itypes_right...>;
    using has_index_type = has_index<itype, tuple_right>;
 
    static constexpr bool is_index_zero   = itype::value==0ul;
    static constexpr bool has_index_value = has_index_type::value && !is_index_zero;
 
    using next_type = number_equal_indexes_impl< std::tuple<itypes_left...>, tuple_right >;
    static constexpr unsigned v = has_index_value ? 1 : 0;
    static constexpr unsigned value  = v + next_type::value;
};
} // namespace detail
 
 
/** @brief number_equal_indexes contains the number of equal indexes of two multi-indexes
 *
 * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
 *
 *
 * @code auto num = number_equal_indexes<
 *                        std::tuple<index_type<2>,index_type<1>>,
 *                        std::tuple<index_type<1>,index_type<3>>  >::value;
 * @endcode
 *
 * @tparam tuple_type_left  type of left std::tuple representing a multi-index
 * @tparam tuple_type_right type of right std::tuple representing a multi-index
*/
template<class tuple_left, class tuple_right>
struct number_equal_indexes
{
    static constexpr unsigned value  =
        detail::number_equal_indexes_impl< std::decay_t<tuple_left>, std::decay_t<tuple_right>>::value;
};
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
 
////////////////////////////////////////////////
////////////////////////////////////////////////
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
 
template<std::size_t r, std::size_t m, class itype, class ttype>
struct index_position_impl
{
    static constexpr auto is_same = std::is_same< std::decay_t<itype>, std::decay_t<std::tuple_element_t<r,ttype>> >::value;
    static constexpr auto value   = is_same ? r : index_position_impl<r+1,m,itype,ttype>::value;
};
 
 
 
template<std::size_t m, class itype, class ttype>
struct index_position_impl < m, m, itype, ttype>
{
    static constexpr auto value = std::tuple_size<ttype>::value;
};
 
} // namespace detail
 
 
 
/** @brief index_position contains the zero-based index position of an index type within a multi-index
 *
 * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
 *
 * @code auto num = index_position<
 *                       index_type<1>,
 *                       std::tuple<index_type<2>,index_type<1>>  >::value;
 * @endcode
 *
 * @returns value returns 0 and N-1 if index_type is found, N otherwise where N is tuple_size_v<tuple_type>.
 *
 * @tparam index_type type of index
 * @tparam tuple_type type of std::tuple that is searched for index
*/
template<class index_type, class tuple_type>
struct index_position
{
    static constexpr auto value  = detail::index_position_impl<0ul,std::tuple_size<tuple_type>::value,std::decay_t<index_type>,std::decay_t<tuple_type>>::value;
};
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
////////////////////////////////////////////////
////////////////////////////////////////////////
 
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
template<std::size_t r, std::size_t m>
struct index_position_pairs_impl
{
    template<class array_type, class tuple_left, class tuple_right>
    static constexpr void run(array_type& out, tuple_left const& lhs, tuple_right const& rhs, std::size_t p)
    {
        using index_type     = std::tuple_element_t<r-1,tuple_left>;
        using has_index_type = has_index<index_type, tuple_right>;
        using get_index_type = index_position<index_type,tuple_right>;
        using next_type      = index_position_pairs_impl<r+1,m>;
        if constexpr ( has_index_type::value && index_type::value != 0)
            out[p++] = std::make_pair(r-1,get_index_type::value);
        next_type::run( out, lhs, rhs, p );
    }
};
 
template<std::size_t m>
struct index_position_pairs_impl<m,m>
{
    template<class array_type, class tuple_left, class tuple_right>
    static constexpr void run(array_type& out, tuple_left const& , tuple_right const& , std::size_t p)
    {
        using index_type     = std::tuple_element_t<m-1,tuple_left>;
        using has_index_type = has_index<index_type, tuple_right>;
        using get_index_type = index_position<index_type, tuple_right>;
        if constexpr ( has_index_type::value && index_type::value != 0 )
            out[p] = std::make_pair(m-1,get_index_type::value);
    }
};
 
template<std::size_t r>
struct index_position_pairs_impl<r,0>
{
    template<class array_type, class tuple_left, class tuple_right>
    static constexpr void run(array_type&, tuple_left const& , tuple_right const& , std::size_t)
    {}
};
 
 
} // namespace detail
 
 
/** @brief index_position_pairs returns zero-based index positions of matching indexes of two multi-indexes
 *
 * @note a multi-index represents as tuple of single indexes of type boost::numeric::ublas::index::index_type
 *
 * @code auto pairs = index_position_pairs(std::make_tuple(_a,_b), std::make_tuple(_b,_c));
 * @endcode
 *
 * @returns a std::array instance containing index position pairs of type std::pair<std::size_t, std::size_t>.
 *
 * @param lhs left std::tuple instance representing a multi-index
 * @param rhs right std::tuple instance representing a multi-index
*/
template<class tuple_left, class tuple_right>
auto index_position_pairs(tuple_left const& lhs, tuple_right const& rhs)
{
    using pair_type = std::pair<std::size_t,std::size_t>;
    constexpr auto m = std::tuple_size<tuple_left >::value;
    constexpr auto p = number_equal_indexes<tuple_left, tuple_right>::value;
    auto array = std::array<pair_type,p>{};
    detail::index_position_pairs_impl<1,m>::run(array, lhs, rhs,0);
    return array;
}
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
////////////////////////////
////////////////////////////
////////////////////////////
////////////////////////////
 
 
namespace boost   {
namespace numeric {
namespace ublas   {
namespace detail  {
 
template<class array_type, std::size_t ... R>
constexpr auto array_to_vector_impl( array_type const& array, std::index_sequence<R...> )
{
    return std::make_pair(
          std::vector<std::size_t>{std::get<0>( std::get<R>(array) )+1 ...} ,
          std::vector<std::size_t>{std::get<1>( std::get<R>(array) )+1 ...} );
}
 
} // namespace detail
 
 
/** @brief array_to_vector converts a std::array of zero-based index position pairs into two std::vector of one-based index positions
 *
 * @code auto two_vectors = array_to_vector(std::make_array ( std::make_pair(1,2), std::make_pair(3,4) ) ) ;
 * @endcode
 *
 * @returns two std::vector of one-based index positions
 *
 * @param array std::array of zero-based index position pairs
*/
template<class pair_type, std::size_t N>
constexpr auto array_to_vector( std::array<pair_type,N> const& array)
{
    constexpr auto sequence = std::make_index_sequence<N>{};
    return detail::array_to_vector_impl( array, sequence );
}
 
 
} // namespace ublas
} // namespace numeric
} // namespace boost
 
 
#endif // _BOOST_UBLAS_TENSOR_MULTI_INDEX_UTILITY_HPP_