Line data Source code
1 : #include "doctest/doctest.h"
2 :
3 : #include "IdenticalBlocksDescriptor.h"
4 : #include "PartitionDescriptor.h"
5 : #include "RandomBlocksDescriptor.h"
6 : #include "BlockLinearOperator.h"
7 : #include "VolumeDescriptor.h"
8 : #include "Identity.h"
9 : #include "Scaling.h"
10 : #include "TypeCasts.hpp"
11 : #include "testHelpers.h"
12 :
13 : using namespace elsa;
14 : using namespace doctest;
15 :
16 : TEST_SUITE_BEGIN("core");
17 :
18 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing construction", TestType, float, double)
19 28 : {
20 28 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
21 28 : using OperatoList = std::vector<std::unique_ptr<LinearOperator<TestType>>>;
22 :
23 28 : index_t rows = 6, cols = 8;
24 28 : IndexVector_t size2D(2);
25 28 : size2D << rows, cols;
26 28 : VolumeDescriptor dd{size2D};
27 :
28 28 : auto sizeBlock = size2D;
29 28 : sizeBlock[1] *= 2;
30 28 : VolumeDescriptor bdBase{sizeBlock};
31 28 : PartitionDescriptor bd{bdBase, 2};
32 :
33 28 : GIVEN("an empty operator list")
34 28 : {
35 :
36 2 : OperatoList ops;
37 :
38 2 : WHEN("creating a BlockLinearOperator from it")
39 2 : {
40 2 : THEN("an exception is thrown")
41 2 : {
42 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
43 2 : InvalidArgumentError);
44 :
45 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
46 2 : InvalidArgumentError);
47 :
48 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bd, ops, BlockType::ROW),
49 2 : InvalidArgumentError);
50 :
51 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, dd, ops, BlockType::COL),
52 2 : InvalidArgumentError);
53 2 : }
54 2 : }
55 2 : }
56 :
57 28 : GIVEN("a list of identical operators")
58 28 : {
59 10 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
60 10 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
61 10 : ops.push_back(std::move(iop1->clone()));
62 10 : ops.push_back(std::move(iop1->clone()));
63 10 : WHEN("creating a BlockLinearOperator from it")
64 10 : {
65 4 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
66 4 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
67 :
68 4 : THEN("the BlockLinearOperator contains the correct operators")
69 4 : {
70 2 : REQUIRE_EQ(blockOp1.numberOfOps(), 2);
71 2 : REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
72 2 : REQUIRE_EQ(blockOp1.getIthOperator(1), *iop1);
73 2 : REQUIRE_EQ(blockOp2.numberOfOps(), 2);
74 2 : REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
75 2 : REQUIRE_EQ(blockOp2.getIthOperator(1), *iop1);
76 2 : }
77 :
78 4 : THEN("the automatically generated operator descriptors are correct")
79 4 : {
80 2 : REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd);
81 2 : REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
82 2 : REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
83 2 : REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd);
84 2 : }
85 4 : }
86 :
87 10 : WHEN("creating a BlockLinearOperator with user specified descriptors from it")
88 10 : {
89 4 : IdenticalBlocksDescriptor bd2{2, dd};
90 4 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
91 4 : BlockLinearOperator<TestType> blockOp1{bd2, ddLinearized, ops, BlockType::COL};
92 4 : BlockLinearOperator<TestType> blockOp2{ddLinearized, bd2, ops, BlockType::ROW};
93 :
94 4 : THEN("the BlockLinearOperator contains the correct operators")
95 4 : {
96 2 : REQUIRE_EQ(blockOp1.numberOfOps(), 2);
97 2 : REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
98 2 : REQUIRE_EQ(blockOp1.getIthOperator(1), *iop1);
99 2 : REQUIRE_EQ(blockOp2.numberOfOps(), 2);
100 2 : REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
101 2 : REQUIRE_EQ(blockOp2.getIthOperator(1), *iop1);
102 2 : }
103 :
104 4 : THEN("the automatically generated operator descriptors are correct")
105 4 : {
106 2 : REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd2);
107 2 : REQUIRE_EQ(blockOp1.getRangeDescriptor(), ddLinearized);
108 2 : REQUIRE_EQ(blockOp2.getDomainDescriptor(), ddLinearized);
109 2 : REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd2);
110 2 : }
111 4 : }
112 :
113 10 : WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
114 10 : {
115 2 : THEN("an exception is thrown")
116 2 : {
117 2 : IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
118 :
119 : // wrong number of coefficients
120 2 : REQUIRE_THROWS_AS(
121 2 : BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
122 2 : InvalidArgumentError);
123 2 : REQUIRE_THROWS_AS(
124 2 : BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
125 2 : InvalidArgumentError);
126 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
127 2 : InvalidArgumentError);
128 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
129 2 : InvalidArgumentError);
130 :
131 : // descriptor not of block type
132 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
133 2 : InvalidArgumentError);
134 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
135 2 : InvalidArgumentError);
136 2 : }
137 2 : }
138 10 : }
139 :
140 28 : GIVEN("a list of operators with different number of dimensions")
141 28 : {
142 10 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
143 10 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
144 10 : auto iop2 = std::make_unique<Identity<TestType>>(ddLinearized);
145 10 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
146 10 : ops.push_back(std::move(iop1->clone()));
147 10 : ops.push_back(std::move(iop2->clone()));
148 :
149 10 : std::vector<std::unique_ptr<DataDescriptor>> descVec;
150 10 : descVec.push_back(dd.clone());
151 10 : descVec.push_back(ddLinearized.clone());
152 10 : RandomBlocksDescriptor expectedBlocks(std::move(descVec));
153 :
154 10 : WHEN("creating a BlockLinearOperator from it")
155 10 : {
156 4 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
157 4 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
158 :
159 4 : THEN("the BlockLinearOperator contains the correct operators")
160 4 : {
161 2 : REQUIRE_EQ(blockOp1.numberOfOps(), 2);
162 2 : REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
163 2 : REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
164 2 : REQUIRE_EQ(blockOp2.numberOfOps(), 2);
165 2 : REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
166 2 : REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
167 2 : }
168 :
169 4 : THEN("the automatically generated operator descriptors are correct")
170 4 : {
171 2 : REQUIRE_EQ(blockOp1.getDomainDescriptor(), expectedBlocks);
172 2 : REQUIRE_EQ(blockOp1.getRangeDescriptor(), ddLinearized);
173 2 : REQUIRE_EQ(blockOp2.getDomainDescriptor(), ddLinearized);
174 2 : REQUIRE_EQ(blockOp2.getRangeDescriptor(), expectedBlocks);
175 2 : }
176 4 : }
177 :
178 10 : WHEN("creating a BlockLinearOperator with user specified descriptors from it")
179 10 : {
180 4 : IdenticalBlocksDescriptor bd2{2, dd};
181 4 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
182 4 : BlockLinearOperator<TestType> blockOp1{bd2, dd, ops, BlockType::COL};
183 4 : BlockLinearOperator<TestType> blockOp2{dd, bd2, ops, BlockType::ROW};
184 :
185 4 : THEN("the BlockLinearOperator contains the correct operators")
186 4 : {
187 2 : REQUIRE_EQ(blockOp1.numberOfOps(), 2);
188 2 : REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
189 2 : REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
190 2 : REQUIRE_EQ(blockOp2.numberOfOps(), 2);
191 2 : REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
192 2 : REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
193 2 : }
194 :
195 4 : THEN("the automatically generated operator descriptors are correct")
196 4 : {
197 2 : REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd2);
198 2 : REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
199 2 : REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
200 2 : REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd2);
201 2 : }
202 4 : }
203 :
204 10 : WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
205 10 : {
206 2 : THEN("an exception is thrown")
207 2 : {
208 2 : IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
209 :
210 : // wrong number of coefficients
211 2 : REQUIRE_THROWS_AS(
212 2 : BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
213 2 : InvalidArgumentError);
214 2 : REQUIRE_THROWS_AS(
215 2 : BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
216 2 : InvalidArgumentError);
217 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
218 2 : InvalidArgumentError);
219 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
220 2 : InvalidArgumentError);
221 :
222 : // descriptor not of block type
223 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
224 2 : InvalidArgumentError);
225 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
226 2 : InvalidArgumentError);
227 2 : }
228 2 : }
229 10 : }
230 :
231 28 : GIVEN("a list of operators that cannot be stacked in the given fashion")
232 28 : {
233 2 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
234 2 : auto iop2 = std::make_unique<Identity<TestType>>(bdBase);
235 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
236 2 : ops.push_back(std::move(iop1->clone()));
237 2 : ops.push_back(std::move(iop2->clone()));
238 :
239 2 : WHEN("creating a BlockLinearOperator from it")
240 2 : {
241 2 : THEN("an exception is thrown")
242 2 : {
243 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
244 2 : InvalidArgumentError);
245 2 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
246 2 : InvalidArgumentError);
247 2 : }
248 2 : }
249 2 : }
250 :
251 28 : GIVEN("a list of operators whose descriptors have equal number of coefficients per dimension "
252 28 : "but different spacing")
253 28 : {
254 4 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
255 4 : VolumeDescriptor dds2{size2D, dd.getSpacingPerDimension() * 2};
256 4 : auto iop2 = std::make_unique<Identity<TestType>>(dds2);
257 4 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
258 4 : ops.push_back(std::move(iop1->clone()));
259 4 : ops.push_back(std::move(iop2->clone()));
260 :
261 4 : WHEN("creating a BlockLinearOperator from it")
262 4 : {
263 4 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
264 4 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
265 :
266 4 : THEN("the BlockLinearOperator contains the correct operators")
267 4 : {
268 2 : REQUIRE_EQ(blockOp1.numberOfOps(), 2);
269 2 : REQUIRE_EQ(blockOp1.getIthOperator(0), *iop1);
270 2 : REQUIRE_EQ(blockOp1.getIthOperator(1), *iop2);
271 2 : REQUIRE_EQ(blockOp2.numberOfOps(), 2);
272 2 : REQUIRE_EQ(blockOp2.getIthOperator(0), *iop1);
273 2 : REQUIRE_EQ(blockOp2.getIthOperator(1), *iop2);
274 2 : }
275 :
276 4 : THEN("the automatically generated operator descriptors are correct and have a uniform "
277 4 : "spacing of one")
278 4 : {
279 2 : REQUIRE_EQ(blockOp1.getDomainDescriptor(), bd);
280 2 : REQUIRE_EQ(blockOp1.getRangeDescriptor(), dd);
281 2 : REQUIRE_EQ(blockOp2.getDomainDescriptor(), dd);
282 2 : REQUIRE_EQ(blockOp2.getRangeDescriptor(), bd);
283 2 : }
284 4 : }
285 4 : }
286 28 : }
287 :
288 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing apply", TestType, float, double)
289 8 : {
290 8 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
291 8 : index_t rows = 4, cols = 8, numBlks = 3;
292 8 : GIVEN("a 2D volume")
293 8 : {
294 6 : IndexVector_t domainIndex(2);
295 6 : domainIndex << rows, cols;
296 6 : VolumeDescriptor domainDesc(domainIndex);
297 :
298 6 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
299 6 : vec << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
300 6 : 2, 2, 2, 2;
301 :
302 6 : DataContainer<TestType> domain(domainDesc, vec);
303 :
304 6 : WHEN("3 Scaling operators are applied to it, in a ROW-Block fashion")
305 6 : {
306 6 : IndexVector_t rangeIndex(2);
307 6 : rangeIndex << rows, cols * numBlks;
308 6 : VolumeDescriptor rangeDesc(rangeIndex);
309 6 : DataContainer<TestType> range(rangeDesc);
310 :
311 6 : TestType scale1 = 2.f;
312 6 : TestType scale2 = 3.f;
313 6 : TestType scale3 = 4.f;
314 :
315 6 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
316 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
317 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
318 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
319 :
320 6 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
321 :
322 6 : blockOp.apply(domain, range);
323 :
324 6 : THEN("the for the first block, x was multiplied by 2.")
325 6 : {
326 66 : for (int i = 0; i < rows * cols; i++)
327 2 : REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1));
328 2 : }
329 6 : THEN("the for the second block, x was multiplied by 3.")
330 6 : {
331 66 : for (int i = 0; i < rows * cols; i++)
332 2 : REQUIRE_UNARY(checkApproxEq(range[i + rows * cols], vec[i] * scale2));
333 2 : }
334 6 : THEN("the for the third block, x was multiplied by 4.")
335 6 : {
336 66 : for (int i = 0; i < rows * cols; i++)
337 2 : REQUIRE_UNARY(checkApproxEq(range[i + rows * cols * 2], vec[i] * scale3));
338 2 : }
339 6 : }
340 6 : }
341 :
342 8 : GIVEN("a 2D volume with 3 blocks")
343 8 : {
344 2 : IndexVector_t blockIndex(2);
345 2 : blockIndex << rows, cols;
346 2 : VolumeDescriptor blockDesc(blockIndex);
347 2 : IdenticalBlocksDescriptor domainDesc(numBlks, blockDesc);
348 :
349 2 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
350 2 : vec << 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
351 :
352 2 : 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2,
353 :
354 2 : 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1,
355 :
356 2 : 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2;
357 :
358 2 : DataContainer<TestType> domain(domainDesc, vec);
359 :
360 2 : WHEN("3 Scaling operators are applied to it in a COL-Block fashion")
361 2 : {
362 2 : IndexVector_t rangeIndex(2);
363 2 : rangeIndex << rows, cols;
364 2 : VolumeDescriptor rangeDesc(rangeIndex);
365 2 : DataContainer<TestType> range(rangeDesc);
366 :
367 2 : float scale1 = 2.f;
368 2 : float scale2 = 3.f;
369 2 : float scale3 = 4.f;
370 :
371 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
372 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale1)));
373 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale2)));
374 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(blockDesc, scale3)));
375 :
376 2 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
377 :
378 2 : blockOp.apply(domain, range);
379 :
380 2 : THEN("then the range data, is a component wise addition of the 3 blocks each "
381 2 : "scaled with the corresponding factor")
382 2 : {
383 2 : auto size = rows * cols;
384 66 : for (int i = 0; i < size; i++) {
385 64 : REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1 + vec[i + size] * scale2
386 64 : + vec[i + size * 2] * scale3));
387 64 : }
388 2 : }
389 2 : }
390 2 : }
391 8 : }
392 :
393 : TEST_CASE_TEMPLATE("BlockLinearOperator: applyAdjoint", TestType, float, double)
394 8 : {
395 8 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
396 8 : index_t rows = 4, cols = 8, numBlks = 3;
397 8 : GIVEN("a 2D volume with 3 blocks")
398 8 : {
399 2 : IndexVector_t rangeIndex(2);
400 2 : rangeIndex << rows, cols * numBlks;
401 2 : VolumeDescriptor rangeDesc(rangeIndex);
402 :
403 2 : const index_t n = rangeDesc.getNumberOfCoefficients();
404 2 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> rangeVec(n);
405 2 : rangeVec.topRows(n / 3).setConstant(5);
406 2 : rangeVec.middleRows(n / 3, 2 * n / 3).setConstant(7);
407 2 : rangeVec.bottomRows(n / 3).setOnes();
408 :
409 2 : DataContainer<TestType> range(rangeDesc, rangeVec);
410 :
411 2 : WHEN("applying the adjoint of 3 Scaling operators ordered in a ROW-Block fashion")
412 2 : {
413 2 : IndexVector_t domainIndex(2);
414 2 : domainIndex << rows, cols;
415 2 : VolumeDescriptor domainDesc(domainIndex);
416 :
417 2 : TestType scale1 = 2.f;
418 2 : TestType scale2 = 3.f;
419 2 : TestType scale3 = 4.f;
420 :
421 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
422 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
423 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
424 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
425 :
426 2 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
427 :
428 2 : auto result = blockOp.applyAdjoint(range);
429 :
430 2 : THEN("then the result is a component wise addition of the 3 blocks each "
431 2 : "scaled with the corresponding factor")
432 2 : {
433 66 : for (int i = 0; i < rows * cols; i++)
434 2 : REQUIRE_UNARY(checkApproxEq(result[i], 35));
435 2 : }
436 2 : }
437 2 : }
438 :
439 8 : GIVEN("a 2D volume")
440 8 : {
441 6 : IndexVector_t rangeIndex(2);
442 6 : rangeIndex << rows, cols;
443 6 : VolumeDescriptor rangeDesc(rangeIndex);
444 :
445 6 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(rangeDesc.getNumberOfCoefficients());
446 6 : vec << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
447 6 : 2, 2, 2, 2;
448 :
449 6 : DataContainer<TestType> range(rangeDesc, vec);
450 :
451 6 : WHEN("applying the adjoint of 3 Scaling operators ordered in a COL-Block fashion")
452 6 : {
453 6 : TestType scale1 = 2.f;
454 6 : TestType scale2 = 3.f;
455 6 : TestType scale3 = 4.f;
456 :
457 6 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
458 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale1)));
459 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale2)));
460 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale3)));
461 :
462 6 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
463 :
464 6 : auto result = blockOp.applyAdjoint(range);
465 :
466 6 : THEN("the for the first block, x was multiplied by 2.")
467 6 : {
468 66 : for (int i = 0; i < rows * cols; i++)
469 2 : REQUIRE_EQ(result[i], vec[i] * scale1);
470 2 : }
471 6 : THEN("the for the second block, x was multiplied by 3.")
472 6 : {
473 66 : for (int i = 0; i < rows * cols; i++)
474 2 : REQUIRE_EQ(result[i + rows * cols], vec[i] * scale2);
475 2 : }
476 6 : THEN("the for the third block, x was multiplied by 4.")
477 6 : {
478 66 : for (int i = 0; i < rows * cols; i++)
479 2 : REQUIRE_EQ(result[i + rows * cols * 2], vec[i] * scale3);
480 2 : }
481 6 : }
482 6 : }
483 8 : }
484 :
485 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing cloning", TestType, float, double)
486 4 : {
487 4 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
488 4 : index_t rows = 4, cols = 8;
489 4 : GIVEN("a ROW BlockLinearOperator")
490 4 : {
491 2 : IndexVector_t domainIndex(2);
492 2 : domainIndex << rows, cols;
493 2 : VolumeDescriptor domainDesc(domainIndex);
494 :
495 2 : TestType scale1 = 2.f;
496 2 : TestType scale2 = 3.f;
497 2 : TestType scale3 = 4.f;
498 :
499 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
500 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
501 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
502 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
503 :
504 2 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
505 :
506 2 : WHEN("cloning the operator")
507 2 : {
508 2 : auto bloClone = blockOp.clone();
509 :
510 2 : THEN("it's a real clone")
511 2 : {
512 2 : REQUIRE_NE(bloClone.get(), &blockOp);
513 2 : REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
514 2 : REQUIRE_EQ(blockOp, *bloClone);
515 2 : }
516 2 : }
517 2 : }
518 :
519 4 : GIVEN("a COL BlockLinearOperator")
520 4 : {
521 2 : IndexVector_t rangeIndex(2);
522 2 : rangeIndex << rows, cols;
523 2 : VolumeDescriptor rangeDesc(rangeIndex);
524 :
525 2 : TestType scale1 = 2.f;
526 2 : TestType scale2 = 3.f;
527 2 : TestType scale3 = 4.f;
528 :
529 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
530 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale1)));
531 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale2)));
532 2 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(rangeDesc, scale3)));
533 :
534 2 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
535 :
536 2 : WHEN("cloning the operator")
537 2 : {
538 2 : auto bloClone = blockOp.clone();
539 :
540 2 : THEN("it's a real clone")
541 2 : {
542 2 : REQUIRE_NE(bloClone.get(), &blockOp);
543 2 : REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
544 2 : REQUIRE_EQ(blockOp, *bloClone);
545 2 : }
546 2 : }
547 2 : }
548 4 : }
549 :
550 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing comparison", TestType, float, double)
551 6 : {
552 6 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
553 6 : index_t rows = 4, cols = 8;
554 6 : GIVEN("a BlockLinearOperator")
555 6 : {
556 6 : IndexVector_t domainIndex(2);
557 6 : domainIndex << rows, cols;
558 6 : VolumeDescriptor domainDesc(domainIndex);
559 :
560 6 : TestType scale1 = 2.f;
561 6 : TestType scale2 = 3.f;
562 6 : TestType scale3 = 4.f;
563 :
564 6 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops(0);
565 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
566 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
567 6 : ops.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale3)));
568 :
569 6 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
570 :
571 6 : WHEN("comparing the operator to a leaf of itself")
572 6 : {
573 2 : auto blockOpLeaf = leaf(blockOp);
574 :
575 2 : THEN("they are not equal")
576 2 : {
577 2 : REQUIRE_NE(blockOp, blockOpLeaf);
578 2 : REQUIRE_NE(blockOpLeaf, blockOp);
579 2 : }
580 2 : }
581 :
582 6 : WHEN("comparing the operator to a BlockLinearOperator containing the same operators, but "
583 6 : "stacked differently")
584 6 : {
585 2 : BlockLinearOperator<TestType> blockOp2(ops, BlockType::COL);
586 :
587 2 : THEN("they are not equal")
588 2 : {
589 2 : REQUIRE_NE(blockOp, blockOp2);
590 2 : REQUIRE_NE(blockOp2, blockOp);
591 2 : }
592 2 : }
593 :
594 6 : WHEN("comparing the operator to a BlockLinearOperator containing different operators")
595 6 : {
596 2 : std::vector<std::unique_ptr<LinearOperator<TestType>>> ops2(0);
597 2 : ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale1)));
598 2 : ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
599 2 : ops2.push_back(std::move(std::make_unique<Scaling<TestType>>(domainDesc, scale2)));
600 2 : BlockLinearOperator<TestType> blockOp2(ops2, BlockType::ROW);
601 :
602 2 : THEN("they are not equal")
603 2 : {
604 2 : REQUIRE_NE(blockOp, blockOp2);
605 2 : REQUIRE_NE(blockOp2, blockOp);
606 2 : }
607 2 : }
608 6 : }
609 6 : }
610 : TEST_SUITE_END();
|