PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/scythestat/error.h

https://bitbucket.org/tristanz/openirt
C Header | 603 lines | 366 code | 52 blank | 185 comment | 8 complexity | 8e2a5e1e884ef5dd8486920ce3646f30 MD5 | raw file
  1. /*
  2. * Scythe Statistical Library Copyright (C) 2000-2002 Andrew D. Martin
  3. * and Kevin M. Quinn; 2002-present Andrew D. Martin, Kevin M. Quinn,
  4. * and Daniel Pemstein. All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify under the terms of the GNU General Public License as
  8. * published by Free Software Foundation; either version 2 of the
  9. * License, or (at your option) any later version. See the text files
  10. * COPYING and LICENSE, distributed with this source code, for further
  11. * information.
  12. * --------------------------------------------------------------------
  13. * scythestat/error.h
  14. */
  15. /*! \file error.h
  16. *
  17. * \brief Definitions of Scythe exception classes.
  18. *
  19. * This file contains the class definitions for
  20. * scythe::scythe_exception and its children. These exception classes
  21. * describe all of the error conditions generated by Scythe library
  22. * routines.
  23. *
  24. * Furthermore, error.h contains a series of macro definitions that
  25. * regulate the inclusion of the library's error checking code in
  26. * compiled code. These macros are controlled by the compiler flag
  27. * SCYTHE_DEBUG and define four levels of scythe debug
  28. * info, SCYTHE_DEBUG = 0, 1, 2, or 3. The library uses these macros to
  29. * specify the debug level of thrown exceptions. If we are at level
  30. * three, all throws are expanded into actual code, at level 2 only
  31. * SCYTHE_THROW_10 AND SCYTHE_THROW_20 calls are expanded, and so on.
  32. * Scythe developers should balance exception importance and
  33. * efficiency costs when making exception level choices. For example,
  34. * bounds checking in matrices is done at level three primarily
  35. * because the added branch results in high performance penalties and
  36. * out-of-bounds errors shouldn't occur in well-written code, while
  37. * conformance checks in matrix multiplication are level 1 because the
  38. * checks result in little overhead relative to the cost of matrix
  39. * multiplication and conformation errors are easy to introduce by
  40. * accident. At level 0, the library performs virtually no error
  41. * checking.
  42. *
  43. * While the various SCYTHE_THROW, SCYTHE_CHECK, and SCYTHE_WARN
  44. * macros will only typically be used by library developers, users
  45. * should make extensive use the tiered error reporting in Scythe by
  46. * setting the compiler flag SCYTHE_DEBUG. If not explicitly set by
  47. * the user, the SCYTHE_DEBUG level is automatically set to 3.
  48. */
  49. #ifndef SCYTHE_ERROR_H
  50. #define SCYTHE_ERROR_H
  51. #include <exception>
  52. #include <string>
  53. #include <sstream>
  54. #include <iostream>
  55. #include <vector>
  56. /*! @cond */
  57. #ifdef SCYTHE_DEBUG_LIB
  58. #define SCYTHE_DEBUG_MSG(MSG) \
  59. { std::cout << "SCYTHE_DEBUG_LIB: " << MSG << std::endl; }
  60. #else
  61. #define SCYTHE_DEBUG_MSG(MSG)
  62. #endif
  63. /*! @endcond */
  64. #define SCYTHE_THROW(EXCEP,MSG) \
  65. { \
  66. std::stringstream _SCYTHE_DEBUG_ss; \
  67. _SCYTHE_DEBUG_ss << MSG; \
  68. throw EXCEP(__FILE__, __func__, __LINE__, \
  69. _SCYTHE_DEBUG_ss.str()); \
  70. }
  71. #define SCYTHE_CHECK(CHECK,EXCEP,MSG) \
  72. { \
  73. if (CHECK) \
  74. SCYTHE_THROW(EXCEP,MSG) \
  75. }
  76. /*! @cond */
  77. #ifndef SCYTHE_DEBUG
  78. #define SCYTHE_DEBUG 3
  79. #endif
  80. /*! @endcond */
  81. #if SCYTHE_DEBUG > 0
  82. #define SCYTHE_CHECK_10(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG)
  83. #else
  84. #define SCYTHE_CHECK_10(CHECK, EXCEP, MSG)
  85. #endif
  86. #if SCYTHE_DEBUG > 1
  87. #define SCYTHE_CHECK_20(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG)
  88. #else
  89. #define SCYTHE_CHECK_20(CHECK, EXCEP, MSG)
  90. #endif
  91. #if SCYTHE_DEBUG > 2
  92. #define SCYTHE_CHECK_30(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG)
  93. #else
  94. #define SCYTHE_CHECK_30(CHECK, EXCEP, MSG)
  95. #endif
  96. #if SCYTHE_DEBUG > 0
  97. #define SCYTHE_THROW_10(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG)
  98. #else
  99. #define SCYTHE_THROW_10(EXCEP,MSG)
  100. #endif
  101. #if SCYTHE_DEBUG > 1
  102. #define SCYTHE_THROW_20(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG)
  103. #else
  104. #define SCYTHE_THROW_20(EXCEP,MSG)
  105. #endif
  106. #if SCYTHE_DEBUG > 2
  107. #define SCYTHE_THROW_30(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG)
  108. #else
  109. #define SCYTHE_THROW_30(EXCEP,MSG)
  110. #endif
  111. #define SCYTHE_WARN(MSG) \
  112. { \
  113. std::cerr << "WARNING in " << __FILE__ << ", " \
  114. << __func__ << ", " << __LINE__ << ": " \
  115. << MSG << "\n"; \
  116. }
  117. #define SCYTHE_CHECK_WARN(CHECK,MSG) \
  118. { \
  119. if (CHECK) \
  120. SCYTHE_WARN(MSG) \
  121. }
  122. namespace scythe
  123. {
  124. /* Forward declaration for serr */
  125. class scythe_exception;
  126. /**** This file-local variable holds the output of the last
  127. * scythe_exception constructed.
  128. ****/
  129. #ifdef __MINGW32__
  130. static scythe_exception *serr;
  131. #else
  132. namespace
  133. {
  134. scythe_exception *serr;
  135. }
  136. #endif
  137. /**** A replacement for the default terminate handler. This outputs
  138. * the string held in serr before calling abort, thereby notifying
  139. * the user of why the program crashed.
  140. ****/
  141. inline void scythe_terminate ();
  142. /**** The scythe exception abstract base class ****/
  143. /*!
  144. * \brief The Scythe exception abstract base class.
  145. *
  146. * The is the base class in Scythe's error handling class tree.
  147. * This class extends std::exception and provides fields for
  148. * information about the exception, including where the exception
  149. * occurred in the library and a message describing the error.
  150. */
  151. class scythe_exception:public std::exception
  152. {
  153. public:
  154. scythe_exception (const std::string & head,
  155. const std::string & file,
  156. const std::string & function,
  157. const unsigned int &line,
  158. const std::string & message = "",
  159. const bool & halt = false) throw ()
  160. : exception (),
  161. head_ (head),
  162. file_ (file),
  163. function_ (function),
  164. line_ (line),
  165. message_ (message),
  166. call_files_ (),
  167. call_funcs_ (),
  168. call_lines_ ()
  169. {
  170. std::ostringstream os;
  171. os << head_ << " in " << file_ << ", " << function_ << ", "
  172. << line_ << ": " << message_ << "!\n\n";
  173. serr = this;
  174. std::set_terminate (scythe_terminate);
  175. if (halt)
  176. std::terminate ();
  177. }
  178. scythe_exception (const scythe_exception & e) throw ()
  179. : exception (),
  180. head_ (e.head_),
  181. file_ (e.file_),
  182. function_ (e.function_),
  183. line_ (e.line_),
  184. message_ (e.message_),
  185. call_files_ (e.call_files_),
  186. call_funcs_ (e.call_funcs_),
  187. call_lines_ (e.call_lines_)
  188. {
  189. }
  190. scythe_exception & operator= (const scythe_exception & e) throw ()
  191. {
  192. head_ = e.head_;
  193. file_ = e.file_;
  194. function_ = e.function_;
  195. line_ = e.line_;
  196. message_ = e.message_;
  197. return *this;
  198. }
  199. virtual ~ scythe_exception () throw ()
  200. {
  201. }
  202. virtual const char *what () const throw ()
  203. {
  204. std::ostringstream os;
  205. for (int i = call_files_.size() - 1; i > -1; ++i) {
  206. os << "Called from " << call_files_[i] << ", "
  207. << call_funcs_[i] << ", " << call_lines_[i] << std::endl;
  208. }
  209. os << head_ << " in " << file_ << ", " << function_ << ", "
  210. << line_ << ": " << message_ << "!";
  211. return os.str ().c_str ();
  212. }
  213. virtual std::string message () const throw ()
  214. {
  215. return message_;
  216. }
  217. virtual void add_caller (const std::string &file,
  218. const std::string &function, const unsigned int &line) throw ()
  219. {
  220. /* This if allows one to catch and rethrow an error in the same
  221. * function w/out messing things up. Nice to keep try-catch
  222. * blocks to a minimum
  223. */
  224. if (file != file_ && function != function_) {
  225. call_files_.push_back(file);
  226. call_funcs_.push_back(function);
  227. call_lines_.push_back(line);
  228. }
  229. }
  230. private:
  231. std::string head_;
  232. std::string file_;
  233. std::string function_;
  234. unsigned int line_;
  235. std::string message_;
  236. std::vector<std::string> call_files_;
  237. std::vector<std::string> call_funcs_;
  238. std::vector<unsigned int> call_lines_;
  239. };
  240. /**** Exception class types, added as needed ****/
  241. /*!
  242. * \brief Memory allocation error.
  243. *
  244. * Library members throw this exception in response to insufficient
  245. * memory conditions, such as when one attempts to create a Matrix
  246. * object that is bigger than available memory.
  247. */
  248. class scythe_alloc_error:public scythe_exception
  249. {
  250. public:
  251. scythe_alloc_error (const std::string & file,
  252. const std::string & function,
  253. const unsigned int &line,
  254. const std::string & message = "",
  255. const bool & halt = false) throw ()
  256. : scythe_exception ("SCYTHE_ALLOCATION_ERROR", file, function,
  257. line, message, halt)
  258. {
  259. }
  260. };
  261. /*!
  262. * \brief Invalid function argument.
  263. *
  264. * Library members throw this exception when callers pass incorrect
  265. * arguments to a function, such as when one calls the factorial
  266. * method with an argument less than 0.
  267. */
  268. class scythe_invalid_arg:public scythe_exception
  269. {
  270. public:
  271. scythe_invalid_arg (const std::string & file,
  272. const std::string & function,
  273. const unsigned int &line,
  274. const std::string & message = "",
  275. const bool & halt = false) throw ()
  276. : scythe_exception ("SCYTHE_INVALID ARGUMENT", file, function,
  277. line, message, halt)
  278. {
  279. }
  280. };
  281. /*!
  282. * \brief File i/o error.
  283. *
  284. * Library members throw this exception when errors occur during
  285. * file reading, writing, or creation, such as when one passes an
  286. * invalid file name to the Matrix class's save method.
  287. */
  288. class scythe_file_error:public scythe_exception
  289. {
  290. public:
  291. scythe_file_error(const std::string & file,
  292. const std::string & function,
  293. const unsigned int &line,
  294. const std::string & message = "",
  295. const bool & halt = false) throw ()
  296. : scythe_exception ("SCYTHE FILE ERROR", file, function, line,
  297. message, halt)
  298. {
  299. }
  300. };
  301. /*! \brief Matrix conformation error.
  302. *
  303. * Library members throw this exception when a caller passes
  304. * non-conforming matrices (matrices of incompatible dimensions) to
  305. * a routine, such as when one attempt two row vectors.
  306. */
  307. class scythe_conformation_error:public scythe_exception
  308. {
  309. public:
  310. scythe_conformation_error(const std::string & file,
  311. const std::string & function,
  312. const unsigned int &line,
  313. const std::string & message = "",
  314. const bool & halt = false) throw ()
  315. : scythe_exception ("SCYTHE CONFORMATION ERROR", file, function,
  316. line, message, halt)
  317. {
  318. }
  319. };
  320. /*! \brief Matrix dimension error.
  321. *
  322. * Library members throw this exception when a caller passes a
  323. * Matrix of the wrong size or shape to a routine. For example,
  324. * trying to take the Cholesky decomposition of a non-square Matrix
  325. * causes this error.
  326. */
  327. class scythe_dimension_error:public scythe_exception
  328. {
  329. public:
  330. scythe_dimension_error (const std::string & file,
  331. const std::string & function,
  332. const unsigned int &line,
  333. const std::string & message = "",
  334. const bool & halt = false) throw ()
  335. : scythe_exception ("SCYTHE DIMENSION ERROR", file, function,
  336. line, message, halt)
  337. {
  338. }
  339. };
  340. /*! \brief Null Matrix error.
  341. *
  342. * Library members throw this exception when a caller passes a null
  343. * Matrix to a routine when it expects a non-null argument. For
  344. * example, taking the inverse of a null Matrix is impossible,
  345. * resulting in this exception.
  346. */
  347. class scythe_null_error:public scythe_exception
  348. {
  349. public:
  350. scythe_null_error(const std::string & file,
  351. const std::string & function,
  352. const unsigned int &line,
  353. const std::string & message = "",
  354. const bool & halt = false) throw ()
  355. : scythe_exception ("SCYTHE NULL ERROR", file, function, line,
  356. message, halt)
  357. {
  358. }
  359. };
  360. /*! \brief Matrix type error.
  361. *
  362. * Library members throw this exception when a caller passes a
  363. * Matrix that does not satisfy some required property to a routine.
  364. * For example, Cholesky decomposition is designed to work on
  365. * positive definite matrices; trying to perform Cholesky
  366. * decomposition on a Matrix that does not satisfy this requirement
  367. * causes this exception.
  368. */
  369. class scythe_type_error:public scythe_exception
  370. {
  371. public:
  372. scythe_type_error(const std::string & file,
  373. const std::string & function,
  374. const unsigned int &line,
  375. const std::string & message = "",
  376. const bool & halt = false) throw ()
  377. : scythe_exception ("SCYTHE TYPE ERROR", file, function, line,
  378. message, halt)
  379. {
  380. }
  381. };
  382. /*! \brief Element out of bounds error.
  383. *
  384. * Library members throw this exception when a caller attempts to
  385. * access an element outside the bounds of a data structure, such as
  386. * when one tries to access the 1000th element of a 200-element
  387. * Matrix.
  388. */
  389. class scythe_bounds_error:public scythe_exception
  390. {
  391. public:
  392. scythe_bounds_error(const std::string & file,
  393. const std::string & function,
  394. const unsigned int &line,
  395. const std::string & message = "",
  396. const bool & halt = false) throw ()
  397. : scythe_exception ("SCYTHE BOUNDS ERROR", file, function,
  398. line, message, halt)
  399. {
  400. }
  401. };
  402. /*! \brief Numerical convergence error.
  403. *
  404. * Library members throw this exception when a numerical algorithm
  405. * fails to converge to a stable value. For example, the BFGS
  406. * optimization routine throws this exception when it cannot locate
  407. * the minimum of a function to a given tolerance.
  408. */
  409. class scythe_convergence_error:public scythe_exception
  410. {
  411. public:
  412. scythe_convergence_error (const std::string & file,
  413. const std::string & function,
  414. const unsigned int &line,
  415. const std::string & message = "",
  416. const bool & halt = false) throw ()
  417. : scythe_exception ("SCYTHE CONVERGENCE ERROR", file, function,
  418. line, message, halt)
  419. {
  420. }
  421. };
  422. /*! \brief Numerical underflow or overflow error.
  423. *
  424. * Library members throw this exception when the result of a
  425. * calculation, assignment, or other operation is to small or large
  426. * for the data type holding the value. For example, passing
  427. * certain values to the gammafn function can result in underflow or
  428. * overflow conditions in the resulting calculations.
  429. */
  430. class scythe_range_error:public scythe_exception
  431. {
  432. public:
  433. scythe_range_error (const std::string & file,
  434. const std::string & function,
  435. const unsigned int &line,
  436. const std::string & message = "",
  437. const bool & halt = false) throw ()
  438. : scythe_exception ("SCYTHE RANGE ERROR", file, function, line,
  439. message, halt)
  440. {
  441. }
  442. };
  443. /*! \brief Numerical precision error.
  444. *
  445. * Library members throw this exception when a routine cannot
  446. * complete a computation effectively and will sacrifice reasonable
  447. * precision as a consequence. For example, passing a value too
  448. * close to a negative integer to the gammafn function renders the
  449. * function incapable of returning an accurate result and thus
  450. * generates this exception.
  451. */
  452. class scythe_precision_error:public scythe_exception
  453. {
  454. public:
  455. scythe_precision_error (const std::string & file,
  456. const std::string & function,
  457. const unsigned int &line,
  458. const std::string & message = "",
  459. const bool & halt = false) throw ()
  460. : scythe_exception ("SCYTHE PRECISION ERROR", file, function,
  461. line, message, halt)
  462. {
  463. }
  464. };
  465. /*! \brief Random number seed error.
  466. *
  467. * Library members throw this exception when a random number
  468. * generator is provided with an illegitimate starting seed value.
  469. * For example, the lecuyer class requires seeds within a certain
  470. * range to operate properly and will throw this exception when
  471. * seeded with a number outside of that range.
  472. */
  473. class scythe_randseed_error:public scythe_exception
  474. {
  475. public:
  476. scythe_randseed_error(const std::string & file,
  477. const std::string & function,
  478. const unsigned int &line,
  479. const std::string & message = "",
  480. const bool & halt = false) throw ()
  481. : scythe_exception ("SCYTHE RANDOM SEED ERROR", file, function,
  482. line, message, halt)
  483. {
  484. }
  485. };
  486. /*! \brief Matrix style error.
  487. *
  488. * Library members throw this exception when they are asked to
  489. * operate on a Matrix of the incorrect style. Some routines
  490. * require specifically a concrete Matrix or view to work correctly.
  491. * For example, only views may reference other matrices; invoking
  492. * the reference function on a concrete Matrix will generate this
  493. * exception.
  494. */
  495. class scythe_style_error:public scythe_exception
  496. {
  497. public:
  498. scythe_style_error(const std::string& file,
  499. const std::string& function,
  500. const unsigned int& line,
  501. const std::string& message = "",
  502. const bool& halt = false) throw ()
  503. : scythe_exception("SCYTHE STYLE ERROR", file, function,
  504. line, message, halt)
  505. {}
  506. };
  507. /*! \brief LAPACK Internal Error
  508. *
  509. * Library members throw this exception when an underlying LAPACK or
  510. * BLAS routine indicates that an internal error has occurred.
  511. *
  512. */
  513. class scythe_lapack_internal_error:public scythe_exception
  514. {
  515. public:
  516. scythe_lapack_internal_error(const std::string& file,
  517. const std::string& function,
  518. const unsigned int& line,
  519. const std::string& message = "",
  520. const bool& halt = false) throw ()
  521. : scythe_exception("SCYTHE LAPACK/BLAS INTERNAL ERROR", file,
  522. function, line, message, halt)
  523. {}
  524. };
  525. /*! \brief Unexpected call to default error.
  526. *
  527. * This error should not occur. If it occurs in your code, please
  528. * contact the Scythe developers to report the problem.
  529. *
  530. */
  531. class scythe_unexpected_default_error:public scythe_exception
  532. {
  533. public:
  534. scythe_unexpected_default_error(const std::string& file,
  535. const std::string& function,
  536. const unsigned int& line,
  537. const std::string& message = "",
  538. const bool& halt = false) throw ()
  539. : scythe_exception("SCYTHE UNEXPECTED DEFAULT ERROR", file,
  540. function, line, message, halt)
  541. {}
  542. };
  543. // The definition of our terminate handler described above
  544. inline void scythe_terminate ()
  545. {
  546. std::cerr << serr->what() << std::endl;
  547. std::cerr << std::endl;
  548. abort ();
  549. }
  550. } // end namspace SCYTHE
  551. #endif /* SCYTHE_ERROR_H */