Skip to content

Commit 108bf1a

Browse files
committed
testing more swizzles
# Conflicts: # test/test_batch_manip.cpp
1 parent 5af6bcd commit 108bf1a

File tree

1 file changed

+159
-137
lines changed

1 file changed

+159
-137
lines changed

test/test_batch_manip.cpp

Lines changed: 159 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
* Martin Renou *
44
* Copyright (c) QuantStack *
55
* Copyright (c) Serge Guelton *
6-
* Copyright (c) Marco Barbone *
76
* *
87
* Distributed under the terms of the BSD 3-Clause License. *
98
* *
@@ -27,143 +26,170 @@ namespace xsimd
2726
}
2827
}
2928

29+
/* Existing patterns kept for backward compatibility */
30+
3031
template <class T>
3132
struct Reversor
3233
{
3334
static constexpr T get(T i, T n) { return n - 1 - i; }
3435
};
36+
3537
template <class T>
3638
struct Last
3739
{
3840
static constexpr T get(T, T n) { return n - 1; }
3941
};
42+
4043
template <class T>
41-
struct DupReal
44+
struct DupReal /* 0,0,2,2,… */
4245
{
4346
static constexpr T get(T i, T) { return (i & ~T { 1 }); }
4447
};
4548

49+
/* New patterns requested */
50+
4651
template <class T>
47-
struct DupImag
52+
struct DupImag /* 1,1,3,3,… */
4853
{
4954
static constexpr T get(T i, T) { return (i & ~T { 1 }) + 1; }
5055
};
56+
5157
template <class T>
52-
struct SwapRI
58+
struct SwapRI /* 1,0,3,2,… swap real <-> imag per complex number */
5359
{
5460
static constexpr T get(T i, T)
5561
{
5662
return i ^ T { 1 };
5763
}
5864
};
65+
5966
template <class T>
60-
struct Identity
67+
struct Identity /* 0,1,2,3,… */
6168
{
6269
static constexpr T get(T i, T) { return i; }
6370
};
71+
6472
template <class T>
65-
struct DupLowPair
73+
struct DupLowPair /* 0,0,1,1,… */
6674
{
6775
static constexpr T get(T i, T) { return i / 2; }
6876
};
77+
6978
template <class T>
70-
struct DupHighPair
79+
struct DupHighPair /* n/2,n/2,n/2+1,n/2+1,… */
7180
{
7281
static constexpr T get(T i, T n) { return n / 2 + i / 2; }
7382
};
7483

7584
template <class T>
76-
struct RotateRight1
77-
{
78-
static constexpr T get(T i, T n) { return (i + n - 1) % n; }
79-
};
80-
template <class T>
81-
struct RotateLeft1
85+
struct as_index
8286
{
83-
static constexpr T get(T i, T n) { return (i + 1) % n; }
87+
using type = xsimd::as_unsigned_integer_t<T>;
8488
};
8589

8690
template <class T>
87-
struct ReversePairs
91+
struct as_index<std::complex<T>> : as_index<T>
8892
{
89-
static constexpr T get(T i, T) { return (i & ~T { 1 }) | (1 - (i & T { 1 })); }
9093
};
91-
template <class T>
92-
struct EvenThenOdd
94+
95+
template <typename T, std::size_t N>
96+
struct init_swizzle_base
9397
{
94-
static constexpr T get(T i, T n)
98+
using swizzle_vector_type = std::array<T, N>;
99+
100+
swizzle_vector_type lhs_in {},
101+
exped_reverse {}, exped_fill {}, exped_dup {},
102+
exped_ror {}, exped_rol {}, exped_rol2 {},
103+
/* new patterns */
104+
exped_dup_imag {}, exped_swap_ri {}, exped_identity {},
105+
exped_dup_low {}, exped_dup_high {}, exped_generic {};
106+
107+
template <int... Indices>
108+
std::vector<swizzle_vector_type> create_swizzle_vectors()
95109
{
96-
return (i < n / 2 ? 2 * i : 2 * (i - n / 2) + 1);
110+
std::vector<swizzle_vector_type> vects;
111+
112+
/* 0) Generate input data */
113+
for (std::size_t i = 0; i < N; ++i)
114+
{
115+
lhs_in[i] = static_cast<T>(2 * i + 1);
116+
}
117+
vects.push_back(lhs_in);
118+
119+
/* 1‑3) Original expectations */
120+
for (std::size_t i = 0; i < N; ++i)
121+
{
122+
exped_reverse[i] = lhs_in[N - 1 - i];
123+
exped_fill[i] = lhs_in[N - 1];
124+
exped_dup[i] = lhs_in[(i & ~std::size_t { 1 })];
125+
exped_ror[i] = lhs_in[(i + N - 1) % N];
126+
exped_rol[i] = lhs_in[(i + 1) % N];
127+
exped_rol2[i] = lhs_in[(i + N - 1) % N]; // rotate_left<N-1>
128+
}
129+
130+
/* New expectations built through generic helper */
131+
fill_pattern<DupImag>(exped_dup_imag, lhs_in);
132+
fill_pattern<SwapRI>(exped_swap_ri, lhs_in);
133+
fill_pattern<Identity>(exped_identity, lhs_in);
134+
fill_pattern<DupLowPair>(exped_dup_low, lhs_in);
135+
fill_pattern<DupHighPair>(exped_dup_high, lhs_in);
136+
137+
/* Push in the original order, then the new ones */
138+
vects.push_back(exped_reverse); // 1
139+
vects.push_back(exped_fill); // 2
140+
vects.push_back(exped_dup); // 3
141+
vects.push_back(exped_ror); // 4
142+
vects.push_back(exped_rol); // 5
143+
vects.push_back(exped_rol2); // 6
144+
145+
vects.push_back(exped_dup_imag); // 7
146+
vects.push_back(exped_swap_ri); // 8
147+
vects.push_back(exped_identity); // 9
148+
vects.push_back(exped_dup_low); // 10
149+
vects.push_back(exped_dup_high); // 11
150+
vects.push_back(exped_generic); // 12
151+
152+
return vects;
97153
}
98154
};
99-
template <class T>
100-
struct OddThenEven
155+
template <class B>
156+
struct insert_test
101157
{
102-
static constexpr T get(T i, T n)
158+
using batch_type = B;
159+
using value_type = typename B::value_type;
160+
static constexpr std::size_t size = B::size;
161+
162+
void insert_first()
103163
{
104-
return (i < n / 2 ? 2 * i + 1 : 2 * (i - n / 2));
164+
value_type fill_value = 0;
165+
value_type sentinel_value = 1;
166+
batch_type v(fill_value);
167+
batch_type w = insert(v, sentinel_value, ::xsimd::index<0>());
168+
std::array<value_type, batch_type::size> data {};
169+
w.store_unaligned(data.data());
170+
CHECK_SCALAR_EQ(data.front(), sentinel_value);
171+
for (std::size_t i = 1; i < batch_type::size; ++i)
172+
CHECK_SCALAR_EQ(data[i], fill_value);
105173
}
106-
};
107-
template <class T>
108-
struct InterleavePairs
109-
{
110-
static constexpr T get(T i, T n)
174+
175+
void insert_last()
111176
{
112-
return (i & 1) ? (i / 2 + n / 2) : (i / 2);
177+
value_type fill_value = 0;
178+
value_type sentinel_value = 1;
179+
batch_type v(fill_value);
180+
batch_type w = insert(v, sentinel_value, ::xsimd::index<batch_type::size - 1>());
181+
std::array<value_type, batch_type::size> data {};
182+
w.store_unaligned(data.data());
183+
for (std::size_t i = 0; i < batch_type::size - 1; ++i)
184+
CHECK_SCALAR_EQ(data[i], fill_value);
185+
CHECK_SCALAR_EQ(data.back(), sentinel_value);
113186
}
114187
};
115-
template <class T>
116-
struct as_index
117-
{
118-
using type = xsimd::as_unsigned_integer_t<T>;
119-
};
120-
121-
template <class T>
122-
struct as_index<std::complex<T>> : as_index<T>
123-
{
124-
};
125188
} // namespace xsimd
126189

127-
//------------------------------------------------------------------------------
128-
// insert_test: unchanged from original
129-
//------------------------------------------------------------------------------
130-
template <class B>
131-
struct insert_test
132-
{
133-
using batch_type = B;
134-
using value_type = typename B::value_type;
135-
136-
void insert_first()
137-
{
138-
value_type fill_value = 0;
139-
value_type sentinel_value = 1;
140-
batch_type v(fill_value);
141-
batch_type w = xsimd::insert(v, sentinel_value, xsimd::index<0>());
142-
std::array<value_type, batch_type::size> data {};
143-
w.store_unaligned(data.data());
144-
CHECK_SCALAR_EQ(data.front(), sentinel_value);
145-
for (std::size_t i = 1; i < batch_type::size; ++i)
146-
CHECK_SCALAR_EQ(data[i], fill_value);
147-
}
148-
149-
void insert_last()
150-
{
151-
value_type fill_value = 0;
152-
value_type sentinel_value = 1;
153-
batch_type v(fill_value);
154-
batch_type w = xsimd::insert(v, sentinel_value,
155-
xsimd::index<batch_type::size - 1>());
156-
std::array<value_type, batch_type::size> data {};
157-
w.store_unaligned(data.data());
158-
for (std::size_t i = 0; i < batch_type::size - 1; ++i)
159-
CHECK_SCALAR_EQ(data[i], fill_value);
160-
CHECK_SCALAR_EQ(data.back(), sentinel_value);
161-
}
162-
};
163-
164190
TEST_CASE_TEMPLATE("[insert_test]", B, BATCH_TYPES)
165191
{
166-
insert_test<B> Test;
192+
xsimd::insert_test<B> Test;
167193
SUBCASE("insert_first") { Test.insert_first(); }
168194
SUBCASE("insert_last") { Test.insert_last(); }
169195
}
@@ -174,87 +200,83 @@ struct swizzle_test
174200
using batch_type = B;
175201
using value_type = typename B::value_type;
176202
using arch_type = typename B::arch_type;
177-
static constexpr std::size_t N = B::size;
178-
using vec_t = std::array<value_type, N>;
179-
180-
// Build the input [1,3,5,...,2N-1]
181-
static vec_t make_lhs()
182-
{
183-
vec_t v;
184-
for (std::size_t i = 0; i < N; ++i)
185-
v[i] = static_cast<value_type>(2 * i + 1);
186-
return v;
187-
}
203+
static constexpr std::size_t size = B::size;
188204

189-
template <template <class> class Pattern>
190-
void run()
205+
template <template <class> class Pattern, std::size_t VectIndex>
206+
void check_swizzle_pattern()
191207
{
192-
vec_t lhs = make_lhs();
193-
vec_t expect = lhs;
194-
xsimd::fill_pattern<Pattern>(expect, lhs);
208+
xsimd::init_swizzle_base<value_type, size> swb;
209+
auto vecs = swb.create_swizzle_vectors();
210+
auto v_lhs = vecs[0];
211+
auto v_exped = vecs[VectIndex];
195212

196-
auto b_lhs = batch_type::load_unaligned(lhs.data());
197-
auto b_expect = batch_type::load_unaligned(expect.data());
213+
batch_type b_lhs = batch_type::load_unaligned(v_lhs.data());
214+
batch_type b_exped = batch_type::load_unaligned(v_exped.data());
198215

199216
using idx_t = typename xsimd::as_index<value_type>::type;
200217
auto idx_batch = xsimd::make_batch_constant<idx_t, Pattern<idx_t>, arch_type>();
201218

202-
CHECK_BATCH_EQ(xsimd::swizzle(b_lhs, idx_batch), b_expect);
203-
CHECK_BATCH_EQ(xsimd::swizzle(b_lhs,
204-
static_cast<xsimd::batch<idx_t, arch_type>>(idx_batch)),
205-
b_expect);
219+
CHECK_BATCH_EQ(xsimd::swizzle(b_lhs, idx_batch), b_exped);
220+
CHECK_BATCH_EQ(xsimd::swizzle(b_lhs, static_cast<xsimd::batch<idx_t, arch_type>>(idx_batch)), b_exped);
206221
}
207222

208223
void rotate_right()
209224
{
210-
vec_t lhs = make_lhs(), expect;
211-
std::rotate_copy(lhs.begin(), lhs.end() - 1, lhs.end(), expect.begin());
212-
CHECK_BATCH_EQ(xsimd::rotate_right<1>(batch_type::load_unaligned(lhs.data())),
213-
batch_type::load_unaligned(expect.data()));
225+
xsimd::init_swizzle_base<value_type, size> sb;
226+
auto vv = sb.create_swizzle_vectors();
227+
batch_type b_lhs = batch_type::load_unaligned(vv[0].data());
228+
batch_type b_exped = batch_type::load_unaligned(vv[4].data());
229+
CHECK_BATCH_EQ(xsimd::rotate_right<1>(b_lhs), b_exped);
214230
}
231+
215232
void rotate_left()
216233
{
217-
vec_t lhs = make_lhs(), expect;
218-
std::rotate_copy(lhs.begin(), lhs.begin() + 1, lhs.end(), expect.begin());
219-
CHECK_BATCH_EQ(xsimd::rotate_left<1>(batch_type::load_unaligned(lhs.data())),
220-
batch_type::load_unaligned(expect.data()));
234+
xsimd::init_swizzle_base<value_type, size> sb;
235+
auto vv = sb.create_swizzle_vectors();
236+
batch_type b_lhs = batch_type::load_unaligned(vv[0].data());
237+
batch_type b_exped = batch_type::load_unaligned(vv[5].data());
238+
CHECK_BATCH_EQ(xsimd::rotate_left<1>(b_lhs), b_exped);
221239
}
240+
222241
void rotate_left_inv()
223242
{
224-
vec_t lhs = make_lhs(), expect;
225-
std::rotate_copy(lhs.begin(), lhs.end() - 1, lhs.end(), expect.begin());
226-
CHECK_BATCH_EQ(xsimd::rotate_left<N - 1>(batch_type::load_unaligned(lhs.data())),
227-
batch_type::load_unaligned(expect.data()));
243+
xsimd::init_swizzle_base<value_type, size> sb;
244+
auto vv = sb.create_swizzle_vectors();
245+
batch_type b_lhs = batch_type::load_unaligned(vv[0].data());
246+
batch_type b_exped = batch_type::load_unaligned(vv[6].data());
247+
CHECK_BATCH_EQ(xsimd::rotate_left<size - 1>(b_lhs), b_exped);
228248
}
229-
};
230249

231-
// Macro to instantiate one SUBCASE per pattern
232-
#define XSIMD_SWIZZLE_PATTERN_CASE(PAT) \
233-
SUBCASE(#PAT) { swizzle_test<B>().template run<xsimd::PAT>(); }
250+
void swizzle_reverse() { check_swizzle_pattern<xsimd::Reversor, 1>(); }
251+
void swizzle_fill() { check_swizzle_pattern<xsimd::Last, 2>(); }
252+
void swizzle_dup() { check_swizzle_pattern<xsimd::DupReal, 3>(); }
253+
void dup_imag() { check_swizzle_pattern<xsimd::DupImag, 7>(); }
254+
void swap_ri() { check_swizzle_pattern<xsimd::SwapRI, 8>(); }
255+
void identity() { check_swizzle_pattern<xsimd::Identity, 9>(); }
256+
void dup_low_pair() { check_swizzle_pattern<xsimd::DupLowPair, 10>(); }
257+
void dup_high_pair() { check_swizzle_pattern<xsimd::DupHighPair, 11>(); }
258+
};
234259

235260
TEST_CASE_TEMPLATE("[swizzle]", B, BATCH_SWIZZLE_TYPES)
236261
{
237-
// All existing patterns:
238-
XSIMD_SWIZZLE_PATTERN_CASE(Reversor);
239-
XSIMD_SWIZZLE_PATTERN_CASE(Last);
240-
XSIMD_SWIZZLE_PATTERN_CASE(DupReal);
241-
XSIMD_SWIZZLE_PATTERN_CASE(DupImag);
242-
XSIMD_SWIZZLE_PATTERN_CASE(SwapRI);
243-
XSIMD_SWIZZLE_PATTERN_CASE(Identity);
244-
XSIMD_SWIZZLE_PATTERN_CASE(DupLowPair);
245-
XSIMD_SWIZZLE_PATTERN_CASE(DupHighPair);
246-
XSIMD_SWIZZLE_PATTERN_CASE(RotateRight1);
247-
XSIMD_SWIZZLE_PATTERN_CASE(RotateLeft1);
248-
XSIMD_SWIZZLE_PATTERN_CASE(ReversePairs);
249-
XSIMD_SWIZZLE_PATTERN_CASE(EvenThenOdd);
250-
XSIMD_SWIZZLE_PATTERN_CASE(OddThenEven);
251-
XSIMD_SWIZZLE_PATTERN_CASE(InterleavePairs);
252-
// Rotation checks:
253-
SUBCASE("rotate_left") { swizzle_test<B>().rotate_left(); }
254-
SUBCASE("rotate_left_inv") { swizzle_test<B>().rotate_left_inv(); }
255-
SUBCASE("rotate_right") { swizzle_test<B>().rotate_right(); }
256-
}
262+
swizzle_test<B> t;
263+
264+
SUBCASE("reverse") { t.swizzle_reverse(); }
257265

258-
#undef XSIMD_SWIZZLE_PATTERN_CASE
266+
SUBCASE("rotate")
267+
{
268+
t.rotate_left();
269+
t.rotate_left_inv();
270+
t.rotate_right();
271+
}
272+
273+
SUBCASE("fill") { t.swizzle_fill(); }
274+
SUBCASE("dup real") { t.swizzle_dup(); }
275+
SUBCASE("dup imag") { t.dup_imag(); }
276+
SUBCASE("swap R/I") { t.swap_ri(); }
277+
SUBCASE("identity") { t.identity(); }
278+
SUBCASE("dup low pair") { t.dup_low_pair(); }
279+
SUBCASE("dup high pair") { t.dup_high_pair(); }
280+
}
259281

260282
#endif /* XSIMD_NO_SUPPORTED_ARCHITECTURE */

0 commit comments

Comments
 (0)