1 /************************************************************************/
2 /* */
3 /* Copyright 2004 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35
36 #include <iostream>
37 #include <algorithm>
38 #include <cmath>
39 #include "vigra/unittest.hxx"
40 #include "vigra/functorexpression.hxx"
41 #include "vigra/rgbvalue.hxx"
42 #include "vigra/sized_int.hxx"
43
44 using namespace vigra::functor;
45
46 template <class EXPR>
47 typename ResultTraits0<UnaryFunctor<EXPR> >::Res
exec(UnaryFunctor<EXPR> f)48 exec(UnaryFunctor<EXPR> f) { return f(); }
49
50 template <class EXPR, class T1>
51 typename ResultTraits1<UnaryFunctor<EXPR>, T1>::Res
exec(UnaryFunctor<EXPR> f,T1 const & a1)52 exec(UnaryFunctor<EXPR> f, T1 const & a1) { return f(a1); }
53
54 template <class EXPR, class T1, class T2>
55 typename ResultTraits2<UnaryFunctor<EXPR>, T1, T2>::Res
exec(UnaryFunctor<EXPR> f,T1 const & a1,T2 const & a2)56 exec(UnaryFunctor<EXPR> f, T1 const & a1, T2 const & a2) { return f(a1, a2); }
57
58 template <class EXPR, class T1, class T2, class T3>
59 typename ResultTraits3<UnaryFunctor<EXPR>, T1, T2, T3>::Res
exec(UnaryFunctor<EXPR> f,T1 const & a1,T2 const & a2,T3 const & a3)60 exec(UnaryFunctor<EXPR> f, T1 const & a1, T2 const & a2, T3 const & a3)
61 { return f(a1, a2, a3); }
62
63 template <class EXPR, class T1>
64 void
exec(UnaryAnalyser<EXPR> f,T1 const & a1)65 exec(UnaryAnalyser<EXPR> f, T1 const & a1) { f(a1); }
66
67 template <class EXPR, class T1, class T2>
68 void
exec(UnaryAnalyser<EXPR> f,T1 const & a1,T2 const & a2)69 exec(UnaryAnalyser<EXPR> f, T1 const & a1, T2 const & a2) { f(a1, a2); }
70
71 template <class EXPR, class T1, class T2, class T3>
72 void
exec(UnaryAnalyser<EXPR> f,T1 const & a1,T2 const & a2,T3 const & a3)73 exec(UnaryAnalyser<EXPR> f, T1 const & a1, T2 const & a2, T3 const & a3)
74 { f(a1, a2, a3); }
75
76 struct FunctorExpressionTest
77 {
testArg1FunctorExpressionTest78 void testArg1()
79 {
80 should(exec(Arg1(), 1.5) == 1.5);
81 should(exec(Arg1(), 1.5, 2) == 1.5);
82 should(exec(Arg1(), 1.5, 2, true) == 1.5);
83 }
84
testArg2FunctorExpressionTest85 void testArg2()
86 {
87 should(exec(Arg2(), 1, 2.5) == 2.5);
88 should(exec(Arg2(), 1, 2.5, false) == 2.5);
89 }
90
testArg3FunctorExpressionTest91 void testArg3()
92 {
93 should(exec(Arg3(), 1, true, 3.5) == 3.5);
94 }
95
testParamFunctorExpressionTest96 void testParam()
97 {
98 should(exec(Param(4.5), 1) == 4.5);
99 should(exec(Param(4.5), 1, true) == 4.5);
100 should(exec(Param(4.5), 1, true, 3) == 4.5);
101 }
102
testVarFunctorExpressionTest103 void testVar()
104 {
105 double v = 4.5;
106 should(exec(Var(v), 1) == 4.5);
107 should(exec(Var(v), 1, true) == 4.5);
108 should(exec(Var(v), 1, true, 3) == 4.5);
109 }
110
testAssignmentFunctorExpressionTest111 void testAssignment()
112 {
113 double v = 0.0;
114 exec(Var(v) = Arg1(), 1.5);
115 should(v == 1.5);
116 exec(Var(v) = Arg2(), 1, 2.5);
117 should(v == 2.5);
118 exec(Var(v) = Arg3(), 1, 2, 3.5);
119 should(v == 3.5);
120 exec(Var(v) += Arg1(), 2.5);
121 should(v == 6.0);
122 exec(Var(v) -= Arg1(), 2.5);
123 should(v == 3.5);
124 exec(Var(v) *= Arg1(), 2.0);
125 should(v == 7.0);
126 exec(Var(v) /= Arg1(), 2.0);
127 should(v == 3.5);
128 }
129
testIfThenFunctorExpressionTest130 void testIfThen()
131 {
132 double v = 4.0;
133 exec(ifThen(Arg1(), Var(v) = Param(1.5)), false);
134 should(v == 4.0);
135 exec(ifThen(Arg1(), Var(v) = Param(1.5)), true);
136 should(v == 1.5);
137 exec(ifThen(Arg2(), Var(v) = Arg1()), 2.5, false);
138 should(v == 1.5);
139 exec(ifThen(Arg2(), Var(v) = Arg1()), 2.5, true);
140 should(v == 2.5);
141 exec(ifThen(Arg3(), Var(v) = Arg2()), 1, 3.5, false);
142 should(v == 2.5);
143 exec(ifThen(Arg3(), Var(v) = Arg2()), 1, 3.5, true);
144 should(v == 3.5);
145 }
146
testIfThenElseFunctorExpressionTest147 void testIfThenElse()
148 {
149 should(exec(ifThenElse(Arg1(), Arg2(), Arg3()), true, 2, 3.5) == 2.0);
150 should(exec(ifThenElse(Arg1(), Arg2(), Arg3()), false, 2, 3.5) == 3.5);
151 int trueBranch = 0, falseBranch = 0;
152 should(exec(ifThenElse(Arg1(),
153 (Var(trueBranch) += Param(1), Arg2()),
154 (Var(falseBranch) += Param(1), Arg3())),
155 true, 1, 2) == 1);
156 should(exec(ifThenElse(Arg1(),
157 (Var(trueBranch) += Param(1), Arg2()),
158 (Var(falseBranch) += Param(1), Arg3())),
159 true, 3.5, 2) == 3.5);
160 should(exec(ifThenElse(Arg1(),
161 (Var(trueBranch) += Param(1), Arg2()),
162 (Var(falseBranch) += Param(1), Arg3())),
163 false, 1, 2) == 2);
164 shouldEqual(trueBranch, 2);
165 shouldEqual(falseBranch, 1);
166 }
167
testUnaryFunctorExpressionTest168 void testUnary()
169 {
170 shouldEqual(exec(sq(Arg1()), 7.0) , vigra::sq(7.0));
171 shouldEqual(exec(sqrt(Arg1()), 7.0) , VIGRA_CSTD::sqrt(7.0));
172 shouldEqual(exec(exp(Arg1()), 4.0) , VIGRA_CSTD::exp(4.0));
173 shouldEqual(exec(log(Arg1()), 4.0) , VIGRA_CSTD::log(4.0));
174 shouldEqual(exec(log10(Arg1()), 4.0) , VIGRA_CSTD::log10(4.0));
175 shouldEqual(exec(sin(Arg1()), 4.0) , VIGRA_CSTD::sin(4.0));
176 shouldEqual(exec(asin(Arg1()), 0.5) , VIGRA_CSTD::asin(0.5));
177 shouldEqual(exec(cos(Arg1()), 4.0) , VIGRA_CSTD::cos(4.0));
178 shouldEqual(exec(acos(Arg1()), 0.5) , VIGRA_CSTD::acos(0.5));
179 shouldEqual(exec(tan(Arg1()), 4.0) , VIGRA_CSTD::tan(4.0));
180 shouldEqual(exec(atan(Arg1()), 0.5) , VIGRA_CSTD::atan(0.5));
181 shouldEqual(exec(abs(Arg1()), -0.5) , 0.5);
182 shouldEqual(exec(norm(Arg1()), -0.5) , 0.5);
183 shouldEqual(exec(squaredNorm(Arg1()), -0.5) , 0.25);
184 shouldEqual(exec(floor(Arg1()), -0.5) , -1.0);
185 shouldEqual(exec(ceil(Arg1()), 0.5) , 1.0);
186 shouldEqual(exec(-Arg1(), -0.5) , 0.5);
187 shouldEqual(exec(!Arg1(), true) , false);
188 shouldEqual(exec(~Arg1(),(vigra::UInt32)0xff) , (vigra::UInt32)0xffffff00);
189 }
190
testBinaryFunctorExpressionTest191 void testBinary()
192 {
193 should(exec(Arg1() + Arg2(), 1, 2.5) == 3.5);
194 should(exec(Arg1() - Arg2(), 1, 2.5) == -1.5);
195 should(exec(Arg1() * Arg2(), 1, 2.5) == 2.5);
196 should(exec(Arg1() / Arg2(), 1, 2.0) == 0.5);
197 should(exec(Arg1() == Arg2(), 1, 2.0) == false);
198 should(exec(Arg1() != Arg2(), 1, 2.0) == true);
199 should(exec(Arg1() < Arg2(), 1, 2.0) == true);
200 should(exec(Arg1() <= Arg2(), 1, 2.0) == true);
201 should(exec(Arg1() > Arg2(), 1, 2.0) == false);
202 should(exec(Arg1() >= Arg2(), 1, 2.0) == false);
203 should(exec(Arg1() && Arg2(), true, true) == true);
204 should(exec(Arg1() || Arg2(), true, false) == true);
205 should(exec(Arg1() & Arg2(), 0xff, 0xf) == 0xf);
206 should(exec(Arg1() | Arg2(), 0xff, 0xf) == 0xff);
207 should(exec(Arg1() ^ Arg2(), 0xff, 0xf) == 0xf0);
208 should(exec(pow(Arg1(), Arg2()), 2.0, 3) == VIGRA_CSTD::pow(2.0, 3.0));
209 shouldEqualTolerance(exec(atan2(Arg1(), Arg2()), 2.0, 3.0), VIGRA_CSTD::atan2(2.0, 3.0), 1e-16);
210 should(exec(fmod(Arg1(), Arg2()), 2.0, 3.0) == VIGRA_CSTD::fmod(2.0, 3.0));
211 should(exec(min(Arg1(), Arg2()), 2, 3.5) == 2.0);
212 should(exec(max(Arg1(), Arg2()), 2, 3.5) == 3.5);
213 }
214
testCombineFunctorExpressionTest215 void testCombine()
216 {
217 should(exec(sqrt(Arg1() * Arg2() + Arg3()), 1.5, 2, 1) == 2.0);
218 }
219
testCommaFunctorExpressionTest220 void testComma()
221 {
222 double v1 = 0.0;
223 int v2 = 0;
224 bool v3 = false;
225
226 exec((Var(v1) = Arg1(), Var(v2) = Arg2(), Var(v3) = Arg3()),
227 1.5, 2, true);
228 should(v1 == 1.5);
229 should(v2 == 2);
230 should(v3 == true);
231
232 should(exec((Var(v1) = Arg3(), Arg2()), true, 2.5, 3.5) == 2.5);
233 should(v1 == 3.5);
234
235 double count = 0.0;
236 should(exec((Var(count) += Param(1), Var(count))) == 1.0);
237 }
238
testApplyFunctorExpressionTest239 void testApply()
240 {
241 should(exec(applyFct((double (*)(double))&VIGRA_CSTD::sqrt, Arg1()), 4.0) == 2.0);
242 should(exec(applyFct((double (*)(double, double))&VIGRA_CSTD::pow,
243 Arg1(), Arg2()), 4.0, 2) == 16.0);
244 }
245
testSequenceFunctorExpressionTest246 void testSequence()
247 {
248 unsigned char data[] = { 1, 2, 3, 4, 5, 250};
249 int res[6];
250 int sum = 0;
251 int count = 0;
252
253 std::for_each(data, data+6,
254 (
255 Var(count) += Param(1),
256 Var(sum) += Arg1()
257 ));
258
259 should(count == 6);
260 should(sum == 265);
261
262 std::transform(data, data+6, res,
263 (
264 Var(count) = Var(count) - Param(1),
265 Param(2) * Arg1()
266 ));
267
268 should(count == 0);
269
270 for(int i=0; i<6; ++i) should(res[i] == 2*data[i]);
271 }
272 };
273
274 struct FunctorRGBExpressionTest
275 {
276 vigra::RGBValue<double> v1_5, v2_5, v3_0, v_1_5;
277 vigra::RGBValue<int> v0, v1, v2;
278
FunctorRGBExpressionTestFunctorRGBExpressionTest279 FunctorRGBExpressionTest()
280 : v1_5(1.5),
281 v2_5(2.5),
282 v3_0(3.0),
283 v_1_5(-1.5),
284 v0(0),
285 v1(1),
286 v2(2)
287 {}
288
testArg1FunctorRGBExpressionTest289 void testArg1()
290 {
291 should(exec(Arg1(), v1_5) == v1_5);
292 should(exec(Arg1(), v1_5, v2) == v1_5);
293 should(exec(Arg1(), v1_5, v2, true) == v1_5);
294 }
295
testArg2FunctorRGBExpressionTest296 void testArg2()
297 {
298 should(exec(Arg2(), v1, v2_5) == v2_5);
299 should(exec(Arg2(), v1, v2_5, false) == v2_5);
300 }
301
testArg3FunctorRGBExpressionTest302 void testArg3()
303 {
304 should(exec(Arg3(), 1, true, v2_5) == v2_5);
305 }
306
testParamFunctorRGBExpressionTest307 void testParam()
308 {
309 should(exec(Param(v2_5), 1) == v2_5);
310 should(exec(Param(v2_5), 1, true) == v2_5);
311 should(exec(Param(v2_5), 1, true, 3) == v2_5);
312 }
313
testVarFunctorRGBExpressionTest314 void testVar()
315 {
316 should(exec(Var(v2_5), 1) == v2_5);
317 should(exec(Var(v2_5), 1, true) == v2_5);
318 should(exec(Var(v2_5), 1, true, 3) == v2_5);
319 }
320
testAssignmentFunctorRGBExpressionTest321 void testAssignment()
322 {
323 vigra::RGBValue<double> v(0.0);
324 exec(Var(v) = Arg1(), v1_5);
325 should(v == v1_5);
326 exec(Var(v) = Arg2(), 1, v2_5);
327 should(v == v2_5);
328 exec(Var(v) = Arg3(), 1, 2, v1_5);
329 should(v == v1_5);
330 exec(Var(v) += Arg1(), v1);
331 should(v == v2_5);
332 exec(Var(v) -= Arg1(), v1);
333 should(v == v1_5);
334 exec(Var(v) *= Arg1(), 2.0);
335 should(v == v3_0);
336 exec(Var(v) /= Arg1(), 2.0);
337 should(v == v1_5);
338 exec(Var(v) *= Arg1(), v2);
339 should(v == v3_0);
340 }
341
testIfThenFunctorRGBExpressionTest342 void testIfThen()
343 {
344 vigra::RGBValue<double> v(v3_0);
345 exec(ifThen(Arg1(), Var(v) = Param(v1_5)), false);
346 should(v == v3_0);
347 exec(ifThen(Arg1(), Var(v) = Param(v1_5)), true);
348 should(v == v1_5);
349 exec(ifThen(Arg2(), Var(v) = Arg1()), v2_5, false);
350 should(v == v1_5);
351 exec(ifThen(Arg2(), Var(v) = Arg1()), v2_5, true);
352 should(v == v2_5);
353 exec(ifThen(Arg3(), Var(v) = Arg2()), 1, v1_5, false);
354 should(v == v2_5);
355 exec(ifThen(Arg3(), Var(v) = Arg2()), 1, v1_5, true);
356 should(v == v1_5);
357 }
358
testIfThenElseFunctorRGBExpressionTest359 void testIfThenElse()
360 {
361 should(exec(ifThenElse(Arg1(), Arg2(), Arg3()), true, v2, v1_5) == v2);
362 should(exec(ifThenElse(Arg1(), Arg2(), Arg3()), false, v2, v1_5) == v1_5);
363 }
364
testUnaryFunctorRGBExpressionTest365 void testUnary()
366 {
367 should(exec(abs(Arg1()), v_1_5) == v1_5);
368 should(exec(floor(Arg1()), vigra::RGBValue<double>(1.4)) == v1);
369 should(exec(ceil(Arg1()), vigra::RGBValue<double>(1.6)) == v2);
370 should(exec(-Arg1(), v_1_5) == v1_5);
371 }
372
testBinaryFunctorRGBExpressionTest373 void testBinary()
374 {
375 should(exec(Arg1() + Arg2(), v1, v1_5) == v2_5);
376 should(exec(Arg1() - Arg2(), v2_5, v1) == v1_5);
377 should(exec(Arg1() * Arg2(), v2, v1_5) == v3_0);
378 should(exec(Arg1() * Arg2(), v1_5, 2.0) == v3_0);
379 should(exec(Arg1() * Arg2(), 2.0, v1_5) == v3_0);
380 should(exec(Arg1() / Arg2(), v3_0, 2.0) == v1_5);
381 should(exec(Arg1() == Arg2(), v1, v1_5) == false);
382 should(exec(Arg1() != Arg2(), v1, v1_5) == true);
383 }
384
testCombineFunctorRGBExpressionTest385 void testCombine()
386 {
387 should(exec((Arg1() * Arg2() + Arg3()) / Param(2.0), v1_5, v2, v1) == v2);
388 }
389
testCommaFunctorRGBExpressionTest390 void testComma()
391 {
392 exec((Var(v0) = Arg1(), Var(v3_0) = Arg2()),
393 v1, v1_5);
394 should(v0 == v1);
395 should(v3_0 == v1_5);
396
397 should(exec((Var(v0) = Arg2(), Arg3()), true, v2, v2_5) == v2_5);
398 should(v0 == v2);
399 }
400
testApplyFunctorRGBExpressionTest401 void testApply()
402 {
403 should(exec(applyFct(
404 (vigra::RGBValue<double> (*)(vigra::RGBValue<double> const &))&vigra::abs, Arg1()),
405 v_1_5) == v1_5);
406 }
407
testSequenceFunctorRGBExpressionTest408 void testSequence()
409 {
410 vigra::RGBValue<int> data[] = { v0, v1, v2, vigra::RGBValue<int>(3)};
411 vigra::RGBValue<int> sum(0);
412 int count = 0;
413
414 std::for_each(data, data+4,
415 (
416 Var(count) += Param(1),
417 Var(sum) += Arg1()
418 ));
419
420 should(count == 4);
421 should(sum == vigra::RGBValue<int>(6));
422 }
423 };
424
425 struct FunctorTestSuite
426 : public vigra::test_suite
427 {
FunctorTestSuiteFunctorTestSuite428 FunctorTestSuite()
429 : vigra::test_suite("FunctorTestSuite")
430 {
431 add( testCase(&FunctorExpressionTest::testArg1));
432 add( testCase(&FunctorExpressionTest::testArg2));
433 add( testCase(&FunctorExpressionTest::testArg3));
434 add( testCase(&FunctorExpressionTest::testParam));
435 add( testCase(&FunctorExpressionTest::testVar));
436 add( testCase(&FunctorExpressionTest::testAssignment));
437 add( testCase(&FunctorExpressionTest::testIfThen));
438 add( testCase(&FunctorExpressionTest::testIfThenElse));
439 add( testCase(&FunctorExpressionTest::testUnary));
440 add( testCase(&FunctorExpressionTest::testBinary));
441 add( testCase(&FunctorExpressionTest::testCombine));
442 add( testCase(&FunctorExpressionTest::testComma));
443 add( testCase(&FunctorExpressionTest::testApply));
444 add( testCase(&FunctorExpressionTest::testSequence));
445
446 add( testCase(&FunctorRGBExpressionTest::testArg1));
447 add( testCase(&FunctorRGBExpressionTest::testArg2));
448 add( testCase(&FunctorRGBExpressionTest::testArg3));
449 add( testCase(&FunctorRGBExpressionTest::testParam));
450 add( testCase(&FunctorRGBExpressionTest::testVar));
451 add( testCase(&FunctorRGBExpressionTest::testAssignment));
452 add( testCase(&FunctorRGBExpressionTest::testIfThen));
453 add( testCase(&FunctorRGBExpressionTest::testIfThenElse));
454 add( testCase(&FunctorRGBExpressionTest::testUnary));
455 add( testCase(&FunctorRGBExpressionTest::testBinary));
456 add( testCase(&FunctorRGBExpressionTest::testCombine));
457 add( testCase(&FunctorRGBExpressionTest::testComma));
458 add( testCase(&FunctorRGBExpressionTest::testApply));
459 add( testCase(&FunctorRGBExpressionTest::testSequence));
460 }
461 };
462
main(int argc,char ** argv)463 int main(int argc, char ** argv)
464 {
465 FunctorTestSuite test;
466
467 int failed = test.run(vigra::testsToBeExecuted(argc, argv));
468
469 std::cout << test.report() << std::endl;
470
471 return (failed != 0);
472 }
473