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 58 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing construction", TestType, float, double)
19 : {
20 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
21 : using OperatoList = std::vector<std::unique_ptr<LinearOperator<TestType>>>;
22 :
23 28 : index_t rows = 6, cols = 8;
24 56 : IndexVector_t size2D(2);
25 28 : size2D << rows, cols;
26 56 : VolumeDescriptor dd{size2D};
27 :
28 56 : auto sizeBlock = size2D;
29 28 : sizeBlock[1] *= 2;
30 56 : VolumeDescriptor bdBase{sizeBlock};
31 56 : PartitionDescriptor bd{bdBase, 2};
32 :
33 30 : GIVEN("an empty operator list")
34 : {
35 :
36 4 : OperatoList ops;
37 :
38 4 : WHEN("creating a BlockLinearOperator from it")
39 : {
40 4 : THEN("an exception is thrown")
41 : {
42 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
43 : InvalidArgumentError);
44 :
45 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
46 : InvalidArgumentError);
47 :
48 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bd, ops, BlockType::ROW),
49 : InvalidArgumentError);
50 :
51 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, dd, ops, BlockType::COL),
52 : InvalidArgumentError);
53 : }
54 : }
55 : }
56 :
57 38 : GIVEN("a list of identical operators")
58 : {
59 20 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
60 20 : 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 14 : WHEN("creating a BlockLinearOperator from it")
64 : {
65 8 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
66 8 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
67 :
68 6 : THEN("the BlockLinearOperator contains the correct operators")
69 : {
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 : }
77 :
78 6 : THEN("the automatically generated operator descriptors are correct")
79 : {
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 : }
85 : }
86 :
87 14 : WHEN("creating a BlockLinearOperator with user specified descriptors from it")
88 : {
89 8 : IdenticalBlocksDescriptor bd2{2, dd};
90 8 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
91 8 : BlockLinearOperator<TestType> blockOp1{bd2, ddLinearized, ops, BlockType::COL};
92 8 : BlockLinearOperator<TestType> blockOp2{ddLinearized, bd2, ops, BlockType::ROW};
93 :
94 6 : THEN("the BlockLinearOperator contains the correct operators")
95 : {
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 : }
103 :
104 6 : THEN("the automatically generated operator descriptors are correct")
105 : {
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 : }
111 : }
112 :
113 12 : WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
114 : {
115 4 : THEN("an exception is thrown")
116 : {
117 4 : IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
118 :
119 : // wrong number of coefficients
120 4 : REQUIRE_THROWS_AS(
121 : BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
122 : InvalidArgumentError);
123 4 : REQUIRE_THROWS_AS(
124 : BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
125 : InvalidArgumentError);
126 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
127 : InvalidArgumentError);
128 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
129 : InvalidArgumentError);
130 :
131 : // descriptor not of block type
132 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
133 : InvalidArgumentError);
134 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
135 : InvalidArgumentError);
136 : }
137 : }
138 : }
139 :
140 38 : GIVEN("a list of operators with different number of dimensions")
141 : {
142 20 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
143 20 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
144 20 : auto iop2 = std::make_unique<Identity<TestType>>(ddLinearized);
145 20 : 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 20 : std::vector<std::unique_ptr<DataDescriptor>> descVec;
150 10 : descVec.push_back(dd.clone());
151 10 : descVec.push_back(ddLinearized.clone());
152 20 : RandomBlocksDescriptor expectedBlocks(std::move(descVec));
153 :
154 14 : WHEN("creating a BlockLinearOperator from it")
155 : {
156 8 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
157 8 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
158 :
159 6 : THEN("the BlockLinearOperator contains the correct operators")
160 : {
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 : }
168 :
169 6 : THEN("the automatically generated operator descriptors are correct")
170 : {
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 : }
176 : }
177 :
178 14 : WHEN("creating a BlockLinearOperator with user specified descriptors from it")
179 : {
180 8 : IdenticalBlocksDescriptor bd2{2, dd};
181 8 : VolumeDescriptor ddLinearized{IndexVector_t::Constant(1, dd.getNumberOfCoefficients())};
182 8 : BlockLinearOperator<TestType> blockOp1{bd2, dd, ops, BlockType::COL};
183 8 : BlockLinearOperator<TestType> blockOp2{dd, bd2, ops, BlockType::ROW};
184 :
185 6 : THEN("the BlockLinearOperator contains the correct operators")
186 : {
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 : }
194 :
195 6 : THEN("the automatically generated operator descriptors are correct")
196 : {
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 : }
202 : }
203 :
204 12 : WHEN("creating a BlockLinearOperator with invalid user specified descriptors from it")
205 : {
206 4 : THEN("an exception is thrown")
207 : {
208 4 : IdenticalBlocksDescriptor blocksOfIncorrectSize{2, bd};
209 :
210 : // wrong number of coefficients
211 4 : REQUIRE_THROWS_AS(
212 : BlockLinearOperator<TestType>(blocksOfIncorrectSize, dd, ops, BlockType::COL),
213 : InvalidArgumentError);
214 4 : REQUIRE_THROWS_AS(
215 : BlockLinearOperator<TestType>(dd, blocksOfIncorrectSize, ops, BlockType::ROW),
216 : InvalidArgumentError);
217 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bd, bdBase, ops, BlockType::COL),
218 : InvalidArgumentError);
219 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, bd, ops, BlockType::ROW),
220 : InvalidArgumentError);
221 :
222 : // descriptor not of block type
223 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(dd, bdBase, ops, BlockType::ROW),
224 : InvalidArgumentError);
225 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(bdBase, dd, ops, BlockType::COL),
226 : InvalidArgumentError);
227 : }
228 : }
229 : }
230 :
231 30 : GIVEN("a list of operators that cannot be stacked in the given fashion")
232 : {
233 4 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
234 4 : auto iop2 = std::make_unique<Identity<TestType>>(bdBase);
235 4 : 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 4 : WHEN("creating a BlockLinearOperator from it")
240 : {
241 4 : THEN("an exception is thrown")
242 : {
243 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::COL),
244 : InvalidArgumentError);
245 4 : REQUIRE_THROWS_AS(BlockLinearOperator<TestType>(ops, BlockType::ROW),
246 : InvalidArgumentError);
247 : }
248 : }
249 : }
250 :
251 32 : GIVEN("a list of operators whose descriptors have equal number of coefficients per dimension "
252 : "but different spacing")
253 : {
254 8 : auto iop1 = std::make_unique<Identity<TestType>>(dd);
255 12 : VolumeDescriptor dds2{size2D, dd.getSpacingPerDimension() * 2};
256 8 : auto iop2 = std::make_unique<Identity<TestType>>(dds2);
257 8 : 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 8 : WHEN("creating a BlockLinearOperator from it")
262 : {
263 8 : BlockLinearOperator<TestType> blockOp1{ops, BlockType::COL};
264 8 : BlockLinearOperator<TestType> blockOp2{ops, BlockType::ROW};
265 :
266 6 : THEN("the BlockLinearOperator contains the correct operators")
267 : {
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 : }
275 :
276 6 : THEN("the automatically generated operator descriptors are correct and have a uniform "
277 : "spacing of one")
278 : {
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 : }
284 : }
285 : }
286 28 : }
287 :
288 38 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing apply", TestType, float, double)
289 : {
290 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
291 8 : index_t rows = 4, cols = 8, numBlks = 3;
292 14 : GIVEN("a 2D volume")
293 : {
294 12 : IndexVector_t domainIndex(2);
295 6 : domainIndex << rows, cols;
296 12 : VolumeDescriptor domainDesc(domainIndex);
297 :
298 12 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
299 12 : 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 12 : 2, 2, 2, 2;
301 :
302 12 : DataContainer<TestType> domain(domainDesc, vec);
303 :
304 12 : WHEN("3 Scaling operators are applied to it, in a ROW-Block fashion")
305 : {
306 12 : IndexVector_t rangeIndex(2);
307 6 : rangeIndex << rows, cols * numBlks;
308 12 : VolumeDescriptor rangeDesc(rangeIndex);
309 12 : 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 12 : 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 12 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
321 :
322 6 : blockOp.apply(domain, range);
323 :
324 8 : THEN("the for the first block, x was multiplied by 2.")
325 : {
326 66 : for (int i = 0; i < rows * cols; i++)
327 64 : REQUIRE_UNARY(checkApproxEq(range[i], vec[i] * scale1));
328 : }
329 8 : THEN("the for the second block, x was multiplied by 3.")
330 : {
331 66 : for (int i = 0; i < rows * cols; i++)
332 64 : REQUIRE_UNARY(checkApproxEq(range[i + rows * cols], vec[i] * scale2));
333 : }
334 8 : THEN("the for the third block, x was multiplied by 4.")
335 : {
336 66 : for (int i = 0; i < rows * cols; i++)
337 64 : REQUIRE_UNARY(checkApproxEq(range[i + rows * cols * 2], vec[i] * scale3));
338 : }
339 : }
340 : }
341 :
342 10 : GIVEN("a 2D volume with 3 blocks")
343 : {
344 4 : IndexVector_t blockIndex(2);
345 2 : blockIndex << rows, cols;
346 4 : VolumeDescriptor blockDesc(blockIndex);
347 4 : IdenticalBlocksDescriptor domainDesc(numBlks, blockDesc);
348 :
349 4 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(domainDesc.getNumberOfCoefficients());
350 4 : 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 4 : 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 4 : DataContainer<TestType> domain(domainDesc, vec);
359 :
360 4 : WHEN("3 Scaling operators are applied to it in a COL-Block fashion")
361 : {
362 4 : IndexVector_t rangeIndex(2);
363 2 : rangeIndex << rows, cols;
364 4 : VolumeDescriptor rangeDesc(rangeIndex);
365 4 : 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 4 : 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 4 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
377 :
378 2 : blockOp.apply(domain, range);
379 :
380 4 : THEN("then the range data, is a component wise addition of the 3 blocks each "
381 : "scaled with the corresponding factor")
382 : {
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 : + vec[i + size * 2] * scale3));
387 : }
388 : }
389 : }
390 : }
391 8 : }
392 :
393 38 : TEST_CASE_TEMPLATE("BlockLinearOperator: applyAdjoint", TestType, float, double)
394 : {
395 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
396 8 : index_t rows = 4, cols = 8, numBlks = 3;
397 10 : GIVEN("a 2D volume with 3 blocks")
398 : {
399 4 : IndexVector_t rangeIndex(2);
400 2 : rangeIndex << rows, cols * numBlks;
401 4 : VolumeDescriptor rangeDesc(rangeIndex);
402 :
403 2 : const index_t n = rangeDesc.getNumberOfCoefficients();
404 4 : 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 4 : DataContainer<TestType> range(rangeDesc, rangeVec);
410 :
411 4 : WHEN("applying the adjoint of 3 Scaling operators ordered in a ROW-Block fashion")
412 : {
413 4 : IndexVector_t domainIndex(2);
414 2 : domainIndex << rows, cols;
415 4 : VolumeDescriptor domainDesc(domainIndex);
416 :
417 2 : TestType scale1 = 2.f;
418 2 : TestType scale2 = 3.f;
419 2 : TestType scale3 = 4.f;
420 :
421 4 : 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 4 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
427 :
428 4 : auto result = blockOp.applyAdjoint(range);
429 :
430 4 : THEN("then the result is a component wise addition of the 3 blocks each "
431 : "scaled with the corresponding factor")
432 : {
433 66 : for (int i = 0; i < rows * cols; i++)
434 64 : REQUIRE_UNARY(checkApproxEq(result[i], 35));
435 : }
436 : }
437 : }
438 :
439 14 : GIVEN("a 2D volume")
440 : {
441 12 : IndexVector_t rangeIndex(2);
442 6 : rangeIndex << rows, cols;
443 12 : VolumeDescriptor rangeDesc(rangeIndex);
444 :
445 12 : Eigen::Matrix<TestType, Eigen::Dynamic, 1> vec(rangeDesc.getNumberOfCoefficients());
446 12 : 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 12 : 2, 2, 2, 2;
448 :
449 12 : DataContainer<TestType> range(rangeDesc, vec);
450 :
451 12 : WHEN("applying the adjoint of 3 Scaling operators ordered in a COL-Block fashion")
452 : {
453 6 : TestType scale1 = 2.f;
454 6 : TestType scale2 = 3.f;
455 6 : TestType scale3 = 4.f;
456 :
457 12 : 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 12 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
463 :
464 12 : auto result = blockOp.applyAdjoint(range);
465 :
466 8 : THEN("the for the first block, x was multiplied by 2.")
467 : {
468 66 : for (int i = 0; i < rows * cols; i++)
469 64 : REQUIRE_EQ(result[i], vec[i] * scale1);
470 : }
471 8 : THEN("the for the second block, x was multiplied by 3.")
472 : {
473 66 : for (int i = 0; i < rows * cols; i++)
474 64 : REQUIRE_EQ(result[i + rows * cols], vec[i] * scale2);
475 : }
476 8 : THEN("the for the third block, x was multiplied by 4.")
477 : {
478 66 : for (int i = 0; i < rows * cols; i++)
479 64 : REQUIRE_EQ(result[i + rows * cols * 2], vec[i] * scale3);
480 : }
481 : }
482 : }
483 8 : }
484 :
485 34 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing cloning", TestType, float, double)
486 : {
487 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
488 4 : index_t rows = 4, cols = 8;
489 6 : GIVEN("a ROW BlockLinearOperator")
490 : {
491 4 : IndexVector_t domainIndex(2);
492 2 : domainIndex << rows, cols;
493 4 : VolumeDescriptor domainDesc(domainIndex);
494 :
495 2 : TestType scale1 = 2.f;
496 2 : TestType scale2 = 3.f;
497 2 : TestType scale3 = 4.f;
498 :
499 4 : 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 4 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
505 :
506 4 : WHEN("cloning the operator")
507 : {
508 4 : auto bloClone = blockOp.clone();
509 :
510 4 : THEN("it's a real clone")
511 : {
512 2 : REQUIRE_NE(bloClone.get(), &blockOp);
513 2 : REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
514 2 : REQUIRE_EQ(blockOp, *bloClone);
515 : }
516 : }
517 : }
518 :
519 6 : GIVEN("a COL BlockLinearOperator")
520 : {
521 4 : IndexVector_t rangeIndex(2);
522 2 : rangeIndex << rows, cols;
523 4 : VolumeDescriptor rangeDesc(rangeIndex);
524 :
525 2 : TestType scale1 = 2.f;
526 2 : TestType scale2 = 3.f;
527 2 : TestType scale3 = 4.f;
528 :
529 4 : 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 4 : BlockLinearOperator<TestType> blockOp(ops, BlockType::COL);
535 :
536 4 : WHEN("cloning the operator")
537 : {
538 4 : auto bloClone = blockOp.clone();
539 :
540 4 : THEN("it's a real clone")
541 : {
542 2 : REQUIRE_NE(bloClone.get(), &blockOp);
543 2 : REQUIRE_UNARY(is<BlockLinearOperator<TestType>>(bloClone.get()));
544 2 : REQUIRE_EQ(blockOp, *bloClone);
545 : }
546 : }
547 : }
548 4 : }
549 :
550 36 : TEST_CASE_TEMPLATE("BlockLinearOperator: Testing comparison", TestType, float, double)
551 : {
552 : using BlockType = typename BlockLinearOperator<TestType>::BlockType;
553 6 : index_t rows = 4, cols = 8;
554 12 : GIVEN("a BlockLinearOperator")
555 : {
556 12 : IndexVector_t domainIndex(2);
557 6 : domainIndex << rows, cols;
558 12 : VolumeDescriptor domainDesc(domainIndex);
559 :
560 6 : TestType scale1 = 2.f;
561 6 : TestType scale2 = 3.f;
562 6 : TestType scale3 = 4.f;
563 :
564 12 : 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 12 : BlockLinearOperator<TestType> blockOp(ops, BlockType::ROW);
570 :
571 8 : WHEN("comparing the operator to a leaf of itself")
572 : {
573 4 : auto blockOpLeaf = leaf(blockOp);
574 :
575 4 : THEN("they are not equal")
576 : {
577 2 : REQUIRE_NE(blockOp, blockOpLeaf);
578 2 : REQUIRE_NE(blockOpLeaf, blockOp);
579 : }
580 : }
581 :
582 8 : WHEN("comparing the operator to a BlockLinearOperator containing the same operators, but "
583 : "stacked differently")
584 : {
585 4 : BlockLinearOperator<TestType> blockOp2(ops, BlockType::COL);
586 :
587 4 : THEN("they are not equal")
588 : {
589 2 : REQUIRE_NE(blockOp, blockOp2);
590 2 : REQUIRE_NE(blockOp2, blockOp);
591 : }
592 : }
593 :
594 8 : WHEN("comparing the operator to a BlockLinearOperator containing different operators")
595 : {
596 4 : 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 4 : BlockLinearOperator<TestType> blockOp2(ops2, BlockType::ROW);
601 :
602 4 : THEN("they are not equal")
603 : {
604 2 : REQUIRE_NE(blockOp, blockOp2);
605 2 : REQUIRE_NE(blockOp2, blockOp);
606 : }
607 : }
608 : }
609 6 : }
610 : TEST_SUITE_END();
|