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