main.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
00005 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
00006 //
00007 // Eigen is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU Lesser General Public
00009 // License as published by the Free Software Foundation; either
00010 // version 3 of the License, or (at your option) any later version.
00011 //
00012 // Alternatively, you can redistribute it and/or
00013 // modify it under the terms of the GNU General Public License as
00014 // published by the Free Software Foundation; either version 2 of
00015 // the License, or (at your option) any later version.
00016 //
00017 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00018 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00019 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00020 // GNU General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Lesser General Public
00023 // License and a copy of the GNU General Public License along with
00024 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00025 
00026 #define min(A,B) please_protect_your_min_with_parentheses
00027 #define max(A,B) please_protect_your_max_with_parentheses
00028 
00029 #include <cstdlib>
00030 #include <cerrno>
00031 #include <ctime>
00032 #include <iostream>
00033 #include <string>
00034 #include <vector>
00035 #include <typeinfo>
00036 
00037 #ifdef NDEBUG
00038 #undef NDEBUG
00039 #endif
00040 
00041 // bounds integer values for AltiVec
00042 #ifdef __ALTIVEC__
00043 #define EIGEN_MAKING_DOCS
00044 #endif
00045 
00046 #ifndef EIGEN_TEST_FUNC
00047 #error EIGEN_TEST_FUNC must be defined
00048 #endif
00049 
00050 #define DEFAULT_REPEAT 10
00051 
00052 #ifdef __ICC
00053 // disable warning #279: controlling expression is constant
00054 #pragma warning disable 279
00055 #endif
00056 
00057 namespace Eigen
00058 {
00059   static std::vector<std::string> g_test_stack;
00060   static int g_repeat;
00061   static unsigned int g_seed;
00062   static bool g_has_set_repeat, g_has_set_seed;
00063 }
00064 
00065 #define EI_PP_MAKE_STRING2(S) #S
00066 #define EI_PP_MAKE_STRING(S) EI_PP_MAKE_STRING2(S)
00067 
00068 #define EIGEN_DEFAULT_IO_FORMAT IOFormat(4, 0, "  ", "\n", "", "", "", "")
00069 
00070 #ifndef EIGEN_NO_ASSERTION_CHECKING
00071 
00072   namespace Eigen
00073   {
00074     static const bool should_raise_an_assert = false;
00075 
00076     // Used to avoid to raise two exceptions at a time in which
00077     // case the exception is not properly caught.
00078     // This may happen when a second exceptions is triggered in a destructor.
00079     static bool no_more_assert = false;
00080     static bool report_on_cerr_on_assert_failure = true;
00081 
00082     struct eigen_assert_exception
00083     {
00084       eigen_assert_exception(void) {}
00085       ~eigen_assert_exception() { Eigen::no_more_assert = false; }
00086     };
00087   }
00088   // If EIGEN_DEBUG_ASSERTS is defined and if no assertion is triggered while
00089   // one should have been, then the list of excecuted assertions is printed out.
00090   //
00091   // EIGEN_DEBUG_ASSERTS is not enabled by default as it
00092   // significantly increases the compilation time
00093   // and might even introduce side effects that would hide
00094   // some memory errors.
00095   #ifdef EIGEN_DEBUG_ASSERTS
00096 
00097     namespace Eigen
00098     {
00099       namespace internal
00100       {
00101         static bool push_assert = false;
00102       }
00103       static std::vector<std::string> eigen_assert_list;
00104     }
00105     #define eigen_assert(a)                       \
00106       if( (!(a)) && (!no_more_assert) )     \
00107       { \
00108         if(report_on_cerr_on_assert_failure) \
00109           std::cerr <<  #a << " " __FILE__ << "(" << __LINE__ << ")\n"; \
00110         Eigen::no_more_assert = true;       \
00111         throw Eigen::eigen_assert_exception(); \
00112       }                                     \
00113       else if (Eigen::internal::push_assert)       \
00114       {                                     \
00115         eigen_assert_list.push_back(std::string(EI_PP_MAKE_STRING(__FILE__)" ("EI_PP_MAKE_STRING(__LINE__)") : "#a) ); \
00116       }
00117 
00118     #define VERIFY_RAISES_ASSERT(a)                                                   \
00119       {                                                                               \
00120         Eigen::no_more_assert = false;                                                \
00121         Eigen::eigen_assert_list.clear();                                                \
00122         Eigen::internal::push_assert = true;                                                 \
00123         Eigen::report_on_cerr_on_assert_failure = false;                              \
00124         try {                                                                         \
00125           a;                                                                          \
00126           std::cerr << "One of the following asserts should have been triggered:\n";  \
00127           for (uint ai=0 ; ai<eigen_assert_list.size() ; ++ai)                           \
00128             std::cerr << "  " << eigen_assert_list[ai] << "\n";                          \
00129           VERIFY(Eigen::should_raise_an_assert && # a);                               \
00130         } catch (Eigen::eigen_assert_exception) {                                        \
00131           Eigen::internal::push_assert = false; VERIFY(true);                                \
00132         }                                                                             \
00133         Eigen::report_on_cerr_on_assert_failure = true;                               \
00134         Eigen::internal::push_assert = false;                                                \
00135       }
00136 
00137   #else // EIGEN_DEBUG_ASSERTS
00138     // see bug 89. The copy_bool here is working around a bug in gcc <= 4.3
00139     #define eigen_assert(a) \
00140       if( (!Eigen::internal::copy_bool(a)) && (!no_more_assert) )\
00141       {                                       \
00142         Eigen::no_more_assert = true;         \
00143         if(report_on_cerr_on_assert_failure)  \
00144           eigen_plain_assert(a);              \
00145         else                                  \
00146           throw Eigen::eigen_assert_exception(); \
00147       }
00148     #define VERIFY_RAISES_ASSERT(a) {                             \
00149         Eigen::no_more_assert = false;                            \
00150         Eigen::report_on_cerr_on_assert_failure = false;          \
00151         try {                                                     \
00152           a;                                                      \
00153           VERIFY(Eigen::should_raise_an_assert && # a);           \
00154         }                                                         \
00155         catch (Eigen::eigen_assert_exception&) { VERIFY(true); }     \
00156         Eigen::report_on_cerr_on_assert_failure = true;           \
00157       }
00158 
00159   #endif // EIGEN_DEBUG_ASSERTS
00160 
00161   #define EIGEN_USE_CUSTOM_ASSERT
00162 
00163 #else // EIGEN_NO_ASSERTION_CHECKING
00164 
00165   #define VERIFY_RAISES_ASSERT(a) {}
00166 
00167 #endif // EIGEN_NO_ASSERTION_CHECKING
00168 
00169 
00170 #define EIGEN_INTERNAL_DEBUGGING
00171 #include <Eigen/QR> // required for createRandomPIMatrixOfRank
00172 
00173 static void verify_impl(bool condition, const char *testname, const char *file, int line, const char *condition_as_string)
00174 {
00175   if (!condition)
00176   {
00177     std::cerr << "Test " << testname << " failed in " << file << " (" << line << ")" \
00178       << std::endl << "    " << condition_as_string << std::endl << std::endl; \
00179     abort();
00180   }
00181 }
00182 
00183 #define VERIFY(a) verify_impl(a, g_test_stack.back().c_str(), __FILE__, __LINE__, EI_PP_MAKE_STRING(a))
00184 
00185 #define VERIFY_IS_EQUAL(a, b) VERIFY(test_is_equal(a, b))
00186 #define VERIFY_IS_APPROX(a, b) VERIFY(test_isApprox(a, b))
00187 #define VERIFY_IS_NOT_APPROX(a, b) VERIFY(!test_isApprox(a, b))
00188 #define VERIFY_IS_MUCH_SMALLER_THAN(a, b) VERIFY(test_isMuchSmallerThan(a, b))
00189 #define VERIFY_IS_NOT_MUCH_SMALLER_THAN(a, b) VERIFY(!test_isMuchSmallerThan(a, b))
00190 #define VERIFY_IS_APPROX_OR_LESS_THAN(a, b) VERIFY(test_isApproxOrLessThan(a, b))
00191 #define VERIFY_IS_NOT_APPROX_OR_LESS_THAN(a, b) VERIFY(!test_isApproxOrLessThan(a, b))
00192 
00193 #define VERIFY_IS_UNITARY(a) VERIFY(test_isUnitary(a))
00194 
00195 #define CALL_SUBTEST(FUNC) do { \
00196     g_test_stack.push_back(EI_PP_MAKE_STRING(FUNC)); \
00197     FUNC; \
00198     g_test_stack.pop_back(); \
00199   } while (0)
00200 
00201 #ifdef EIGEN_TEST_PART_1
00202 #define CALL_SUBTEST_1(FUNC) CALL_SUBTEST(FUNC)
00203 #else
00204 #define CALL_SUBTEST_1(FUNC)
00205 #endif
00206 
00207 #ifdef EIGEN_TEST_PART_2
00208 #define CALL_SUBTEST_2(FUNC) CALL_SUBTEST(FUNC)
00209 #else
00210 #define CALL_SUBTEST_2(FUNC)
00211 #endif
00212 
00213 #ifdef EIGEN_TEST_PART_3
00214 #define CALL_SUBTEST_3(FUNC) CALL_SUBTEST(FUNC)
00215 #else
00216 #define CALL_SUBTEST_3(FUNC)
00217 #endif
00218 
00219 #ifdef EIGEN_TEST_PART_4
00220 #define CALL_SUBTEST_4(FUNC) CALL_SUBTEST(FUNC)
00221 #else
00222 #define CALL_SUBTEST_4(FUNC)
00223 #endif
00224 
00225 #ifdef EIGEN_TEST_PART_5
00226 #define CALL_SUBTEST_5(FUNC) CALL_SUBTEST(FUNC)
00227 #else
00228 #define CALL_SUBTEST_5(FUNC)
00229 #endif
00230 
00231 #ifdef EIGEN_TEST_PART_6
00232 #define CALL_SUBTEST_6(FUNC) CALL_SUBTEST(FUNC)
00233 #else
00234 #define CALL_SUBTEST_6(FUNC)
00235 #endif
00236 
00237 #ifdef EIGEN_TEST_PART_7
00238 #define CALL_SUBTEST_7(FUNC) CALL_SUBTEST(FUNC)
00239 #else
00240 #define CALL_SUBTEST_7(FUNC)
00241 #endif
00242 
00243 #ifdef EIGEN_TEST_PART_8
00244 #define CALL_SUBTEST_8(FUNC) CALL_SUBTEST(FUNC)
00245 #else
00246 #define CALL_SUBTEST_8(FUNC)
00247 #endif
00248 
00249 #ifdef EIGEN_TEST_PART_9
00250 #define CALL_SUBTEST_9(FUNC) CALL_SUBTEST(FUNC)
00251 #else
00252 #define CALL_SUBTEST_9(FUNC)
00253 #endif
00254 
00255 #ifdef EIGEN_TEST_PART_10
00256 #define CALL_SUBTEST_10(FUNC) CALL_SUBTEST(FUNC)
00257 #else
00258 #define CALL_SUBTEST_10(FUNC)
00259 #endif
00260 
00261 #ifdef EIGEN_TEST_PART_11
00262 #define CALL_SUBTEST_11(FUNC) CALL_SUBTEST(FUNC)
00263 #else
00264 #define CALL_SUBTEST_11(FUNC)
00265 #endif
00266 
00267 #ifdef EIGEN_TEST_PART_12
00268 #define CALL_SUBTEST_12(FUNC) CALL_SUBTEST(FUNC)
00269 #else
00270 #define CALL_SUBTEST_12(FUNC)
00271 #endif
00272 
00273 #ifdef EIGEN_TEST_PART_13
00274 #define CALL_SUBTEST_13(FUNC) CALL_SUBTEST(FUNC)
00275 #else
00276 #define CALL_SUBTEST_13(FUNC)
00277 #endif
00278 
00279 #ifdef EIGEN_TEST_PART_14
00280 #define CALL_SUBTEST_14(FUNC) CALL_SUBTEST(FUNC)
00281 #else
00282 #define CALL_SUBTEST_14(FUNC)
00283 #endif
00284 
00285 #ifdef EIGEN_TEST_PART_15
00286 #define CALL_SUBTEST_15(FUNC) CALL_SUBTEST(FUNC)
00287 #else
00288 #define CALL_SUBTEST_15(FUNC)
00289 #endif
00290 
00291 #ifdef EIGEN_TEST_PART_16
00292 #define CALL_SUBTEST_16(FUNC) CALL_SUBTEST(FUNC)
00293 #else
00294 #define CALL_SUBTEST_16(FUNC)
00295 #endif
00296 
00297 namespace Eigen {
00298 
00299 template<typename T> inline typename NumTraits<T>::Real test_precision() { return NumTraits<T>::dummy_precision(); }
00300 template<> inline float test_precision<float>() { return 1e-3f; }
00301 template<> inline double test_precision<double>() { return 1e-6; }
00302 template<> inline float test_precision<std::complex<float> >() { return test_precision<float>(); }
00303 template<> inline double test_precision<std::complex<double> >() { return test_precision<double>(); }
00304 template<> inline long double test_precision<long double>() { return 1e-6; }
00305 
00306 inline bool test_isApprox(const int& a, const int& b)
00307 { return internal::isApprox(a, b, test_precision<int>()); }
00308 inline bool test_isMuchSmallerThan(const int& a, const int& b)
00309 { return internal::isMuchSmallerThan(a, b, test_precision<int>()); }
00310 inline bool test_isApproxOrLessThan(const int& a, const int& b)
00311 { return internal::isApproxOrLessThan(a, b, test_precision<int>()); }
00312 
00313 inline bool test_isApprox(const float& a, const float& b)
00314 { return internal::isApprox(a, b, test_precision<float>()); }
00315 inline bool test_isMuchSmallerThan(const float& a, const float& b)
00316 { return internal::isMuchSmallerThan(a, b, test_precision<float>()); }
00317 inline bool test_isApproxOrLessThan(const float& a, const float& b)
00318 { return internal::isApproxOrLessThan(a, b, test_precision<float>()); }
00319 inline bool test_isApprox(const double& a, const double& b)
00320 { return internal::isApprox(a, b, test_precision<double>()); }
00321 
00322 inline bool test_isMuchSmallerThan(const double& a, const double& b)
00323 { return internal::isMuchSmallerThan(a, b, test_precision<double>()); }
00324 inline bool test_isApproxOrLessThan(const double& a, const double& b)
00325 { return internal::isApproxOrLessThan(a, b, test_precision<double>()); }
00326 
00327 inline bool test_isApprox(const std::complex<float>& a, const std::complex<float>& b)
00328 { return internal::isApprox(a, b, test_precision<std::complex<float> >()); }
00329 inline bool test_isMuchSmallerThan(const std::complex<float>& a, const std::complex<float>& b)
00330 { return internal::isMuchSmallerThan(a, b, test_precision<std::complex<float> >()); }
00331 
00332 inline bool test_isApprox(const std::complex<double>& a, const std::complex<double>& b)
00333 { return internal::isApprox(a, b, test_precision<std::complex<double> >()); }
00334 inline bool test_isMuchSmallerThan(const std::complex<double>& a, const std::complex<double>& b)
00335 { return internal::isMuchSmallerThan(a, b, test_precision<std::complex<double> >()); }
00336 
00337 inline bool test_isApprox(const long double& a, const long double& b)
00338 {
00339     bool ret = internal::isApprox(a, b, test_precision<long double>());
00340     if (!ret) std::cerr
00341         << std::endl << "    actual   = " << a
00342         << std::endl << "    expected = " << b << std::endl << std::endl;
00343     return ret;
00344 }
00345 
00346 inline bool test_isMuchSmallerThan(const long double& a, const long double& b)
00347 { return internal::isMuchSmallerThan(a, b, test_precision<long double>()); }
00348 inline bool test_isApproxOrLessThan(const long double& a, const long double& b)
00349 { return internal::isApproxOrLessThan(a, b, test_precision<long double>()); }
00350 
00351 template<typename Type1, typename Type2>
00352 inline bool test_isApprox(const Type1& a, const Type2& b)
00353 {
00354   return a.isApprox(b, test_precision<typename Type1::Scalar>());
00355 }
00356 
00357 // The idea behind this function is to compare the two scalars a and b where
00358 // the scalar ref is a hint about the expected order of magnitude of a and b.
00359 // Therefore, if for some reason a and b are very small compared to ref,
00360 // we won't issue a false negative.
00361 // This test could be: abs(a-b) <= eps * ref
00362 // However, it seems that simply comparing a+ref and b+ref is more sensitive to true error.
00363 template<typename Scalar,typename ScalarRef>
00364 inline bool test_isApproxWithRef(const Scalar& a, const Scalar& b, const ScalarRef& ref)
00365 {
00366   return test_isApprox(a+ref, b+ref);
00367 }
00368 
00369 template<typename Derived1, typename Derived2>
00370 inline bool test_isMuchSmallerThan(const MatrixBase<Derived1>& m1,
00371                                    const MatrixBase<Derived2>& m2)
00372 {
00373   return m1.isMuchSmallerThan(m2, test_precision<typename internal::traits<Derived1>::Scalar>());
00374 }
00375 
00376 template<typename Derived>
00377 inline bool test_isMuchSmallerThan(const MatrixBase<Derived>& m,
00378                                    const typename NumTraits<typename internal::traits<Derived>::Scalar>::Real& s)
00379 {
00380   return m.isMuchSmallerThan(s, test_precision<typename internal::traits<Derived>::Scalar>());
00381 }
00382 
00383 template<typename Derived>
00384 inline bool test_isUnitary(const MatrixBase<Derived>& m)
00385 {
00386   return m.isUnitary(test_precision<typename internal::traits<Derived>::Scalar>());
00387 }
00388 
00389 template<typename T, typename U>
00390 bool test_is_equal(const T& actual, const U& expected)
00391 {
00392     if (actual==expected)
00393         return true;
00394     // false:
00395     std::cerr
00396         << std::endl << "    actual   = " << actual
00397         << std::endl << "    expected = " << expected << std::endl << std::endl;
00398     return false;
00399 }
00400 
00406 template<typename MatrixType>
00407 void createRandomPIMatrixOfRank(typename MatrixType::Index desired_rank, typename MatrixType::Index rows, typename MatrixType::Index cols, MatrixType& m)
00408 {
00409   typedef typename internal::traits<MatrixType>::Index Index;
00410   typedef typename internal::traits<MatrixType>::Scalar Scalar;
00411   enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
00412 
00413   typedef Matrix<Scalar, Dynamic, 1> VectorType;
00414   typedef Matrix<Scalar, Rows, Rows> MatrixAType;
00415   typedef Matrix<Scalar, Cols, Cols> MatrixBType;
00416 
00417   if(desired_rank == 0)
00418   {
00419     m.setZero(rows,cols);
00420     return;
00421   }
00422 
00423   if(desired_rank == 1)
00424   {
00425     // here we normalize the vectors to get a partial isometry
00426     m = VectorType::Random(rows).normalized() * VectorType::Random(cols).normalized().transpose();
00427     return;
00428   }
00429 
00430   MatrixAType a = MatrixAType::Random(rows,rows);
00431   MatrixType d = MatrixType::Identity(rows,cols);
00432   MatrixBType  b = MatrixBType::Random(cols,cols);
00433 
00434   // set the diagonal such that only desired_rank non-zero entries reamain
00435   const Index diag_size = (std::min)(d.rows(),d.cols());
00436   if(diag_size != desired_rank)
00437     d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank);
00438 
00439   HouseholderQR<MatrixAType> qra(a);
00440   HouseholderQR<MatrixBType> qrb(b);
00441   m = qra.householderQ() * d * qrb.householderQ();
00442 }
00443 
00444 } // end namespace Eigen
00445 
00446 template<typename T> struct GetDifferentType;
00447 
00448 template<> struct GetDifferentType<float> { typedef double type; };
00449 template<> struct GetDifferentType<double> { typedef float type; };
00450 template<typename T> struct GetDifferentType<std::complex<T> >
00451 { typedef std::complex<typename GetDifferentType<T>::type> type; };
00452 
00453 template<typename T> std::string type_name() { return "other"; }
00454 template<> std::string type_name<float>() { return "float"; }
00455 template<> std::string type_name<double>() { return "double"; }
00456 template<> std::string type_name<int>() { return "int"; }
00457 template<> std::string type_name<std::complex<float> >() { return "complex<float>"; }
00458 template<> std::string type_name<std::complex<double> >() { return "complex<double>"; }
00459 template<> std::string type_name<std::complex<int> >() { return "complex<int>"; }
00460 
00461 // forward declaration of the main test function
00462 void EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
00463 
00464 using namespace Eigen;
00465 
00466 void set_repeat_from_string(const char *str)
00467 {
00468   errno = 0;
00469   g_repeat = int(strtoul(str, 0, 10));
00470   if(errno || g_repeat <= 0)
00471   {
00472     std::cout << "Invalid repeat value " << str << std::endl;
00473     exit(EXIT_FAILURE);
00474   }
00475   g_has_set_repeat = true;
00476 }
00477 
00478 void set_seed_from_string(const char *str)
00479 {
00480   errno = 0;
00481   g_seed = strtoul(str, 0, 10);
00482   if(errno || g_seed == 0)
00483   {
00484     std::cout << "Invalid seed value " << str << std::endl;
00485     exit(EXIT_FAILURE);
00486   }
00487   g_has_set_seed = true;
00488 }
00489 
00490 int main(int argc, char *argv[])
00491 {
00492     g_has_set_repeat = false;
00493     g_has_set_seed = false;
00494     bool need_help = false;
00495 
00496     for(int i = 1; i < argc; i++)
00497     {
00498       if(argv[i][0] == 'r')
00499       {
00500         if(g_has_set_repeat)
00501         {
00502           std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
00503           return 1;
00504         }
00505         set_repeat_from_string(argv[i]+1);
00506       }
00507       else if(argv[i][0] == 's')
00508       {
00509         if(g_has_set_seed)
00510         {
00511           std::cout << "Argument " << argv[i] << " conflicting with a former argument" << std::endl;
00512           return 1;
00513         }
00514          set_seed_from_string(argv[i]+1);
00515       }
00516       else
00517       {
00518         need_help = true;
00519       }
00520     }
00521 
00522     if(need_help)
00523     {
00524       std::cout << "This test application takes the following optional arguments:" << std::endl;
00525       std::cout << "  rN     Repeat each test N times (default: " << DEFAULT_REPEAT << ")" << std::endl;
00526       std::cout << "  sN     Use N as seed for random numbers (default: based on current time)" << std::endl;
00527       std::cout << std::endl;
00528       std::cout << "If defined, the environment variables EIGEN_REPEAT and EIGEN_SEED" << std::endl;
00529       std::cout << "will be used as default values for these parameters." << std::endl;
00530       return 1;
00531     }
00532 
00533     char *env_EIGEN_REPEAT = getenv("EIGEN_REPEAT");
00534     if(!g_has_set_repeat && env_EIGEN_REPEAT)
00535       set_repeat_from_string(env_EIGEN_REPEAT);
00536     char *env_EIGEN_SEED = getenv("EIGEN_SEED");
00537     if(!g_has_set_seed && env_EIGEN_SEED)
00538       set_seed_from_string(env_EIGEN_SEED);
00539 
00540     if(!g_has_set_seed) g_seed = (unsigned int) time(NULL);
00541     if(!g_has_set_repeat) g_repeat = DEFAULT_REPEAT;
00542 
00543     std::cout << "Initializing random number generator with seed " << g_seed << std::endl;
00544     srand(g_seed);
00545     std::cout << "Repeating each test " << g_repeat << " times" << std::endl;
00546 
00547     Eigen::g_test_stack.push_back(EI_PP_MAKE_STRING(EIGEN_TEST_FUNC));
00548 
00549     EIGEN_CAT(test_,EIGEN_TEST_FUNC)();
00550     return 0;
00551 }


libicr
Author(s): Robert Krug
autogenerated on Mon Jan 6 2014 11:32:59