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