#ifndef CONFIG_HXX
#define CONFIG_HXX

/// \file config.cxx configuration file for OpenGM
/// 
/// this header should be generated by cmake (from config.hxx.cmake)
/// \warning if cmake is not used to configure opengm config.hxx can be wrong.
/// Since this header is used to get the size of fundamental types from cmake one
/// may has to corret the OPENGM_SIZE_OF_UNSIGNED_* definitions by hand or call cmake
/// to configure this header.

// \def OPENGM_ASSERT
/// opengm assertion
/// if NDEBUG is not set OPENGM_ASSERT will check the
/// assertion, if NDEBUG is not set OPENGM_ASSERT will do nothing
#ifdef NDEBUG
#  define OPENGM_ASSERT(expression)
#else
#  define OPENGM_ASSERT(expression) if(!(expression)) { \
   std::stringstream s; \
   s << "OpenGM assertion " << #expression \
   << " failed in file " << __FILE__ \
   << ", line " << __LINE__ << std::endl; \
   throw std::runtime_error(s.str()); \
}
#endif
// meta-assert
/// opengm compile time assertion
#define OPENGM_META_ASSERT(assertion, msg){ \
   meta::Assert<   meta::Compare< meta::Bool<(assertion)> , meta::Bool<true> >::value    >  \
   OPENGM_COMPILE_TIME_ASSERTION_FAILED_____REASON_____##msg; \
   (void) OPENGM_COMPILE_TIME_ASSERTION_FAILED_____REASON_____##msg; \
}
// has no typedef ? (TODO make this a option in cmake  list or
// find out in cmake if this define should be active or not
#ifdef OPENGM_NO_TYPENAME 
#  define typename 
#endif
#include "opengm/utilities/metaprogramming.hxx"

#ifndef OPENGM_USED_CMAKE
   // assume all types have been detected
#else
   // has cmake detected a type?
   #cmakedefine OPENGM_NO_CHAR  
   #cmakedefine OPENGM_NO_SIGNED_CHAR  
   #cmakedefine OPENGM_NO_UNSIGNED_CHAR  
   #cmakedefine OPENGM_NO_WCHAR_T  
   #cmakedefine OPENGM_NO_SHORT  
   #cmakedefine OPENGM_NO_UNSIGNED_SHORT  
   #cmakedefine OPENGM_NO_INT  
   #cmakedefine OPENGM_NO_UNSIGNED_INT  
   #cmakedefine OPENGM_NO_LONG  
   #cmakedefine OPENGM_NO_UNSIGNED_LONG  
   #cmakedefine OPENGM_NO_LONG_LONG  
   #cmakedefine OPENGM_NO_UNSIGNED_LONG_LONG  
   #cmakedefine OPENGM_NO_FLOAT  
   #cmakedefine OPENGM_NO_DOUBLE  
   #cmakedefine OPENGM_NO_LONG_DOUBLE
#endif
//
#ifndef OPENGM_USED_CMAKE
   #define OPENGM_WORD_LENGTH                   sizeof(void *)
   #define OPENGM_SIZE_OF_BOOL                  1
   #define OPENGM_SIZE_OF_CHAR                  sizeof(char)
   #define OPENGM_SIZE_OF_SIGNED_CHAR           sizeof(unsigned char)
   #define OPENGM_SIZE_OF_UNSIGNED_CHAR         sizeof(unsigned char)
   #define OPENGM_SIZE_OF_WCHAR_T               sizeof(wchar_t) 
   #define OPENGM_SIZE_OF_SHORT                 sizeof(short)
   #define OPENGM_SIZE_OF_UNSIGNED_SHORT        sizeof(unsigned short)
   #define OPENGM_SIZE_OF_INT                   sizeof(int)
   #define OPENGM_SIZE_OF_UNSIGNED_INT          sizeof(unsigned int)
   #define OPENGM_SIZE_OF_LONG                  sizeof(long)
   #define OPENGM_SIZE_OF_UNSIGNED_LONG         sizeof(unsigned long)
   #define OPENGM_SIZE_OF_LONG_LONG             sizeof(long long)
   #define OPENGM_SIZE_OF_UNSIGNED_LONG_LONG    sizeof(unsigned long long)
   #define OPENGM_SIZE_OF_FLOAT                 sizeof(float)
   #define OPENGM_SIZE_OF_DOUBLE                sizeof(double)
   #define OPENGM_SIZE_OF_LONG_DOUBLE           sizeof(long double)
#else
   // size of types detected by cmake
   #define OPENGM_WORD_LENGTH                   @OPENGM_WORD_LENGTH@
   #define OPENGM_SIZE_OF_BOOL                  1
   #define OPENGM_SIZE_OF_CHAR                  @OPENGM_SIZE_OF_CHAR@ 
   #define OPENGM_SIZE_OF_SIGNED_CHAR           @OPENGM_SIZE_OF_SIGNED_CHAR@
   #define OPENGM_SIZE_OF_UNSIGNED_CHAR         @OPENGM_SIZE_OF_UNSIGNED_CHAR@
   #define OPENGM_SIZE_OF_WCHAR_T               @OPENGM_SIZE_OF_WCHAR_T@  
   #define OPENGM_SIZE_OF_SHORT                 @OPENGM_SIZE_OF_SHORT@ 
   #define OPENGM_SIZE_OF_UNSIGNED_SHORT        @OPENGM_SIZE_OF_UNSIGNED_SHORT@ 
   #define OPENGM_SIZE_OF_INT                   @OPENGM_SIZE_OF_INT@  
   #define OPENGM_SIZE_OF_UNSIGNED_INT          @OPENGM_SIZE_OF_UNSIGNED_INT@  
   #define OPENGM_SIZE_OF_LONG                  @OPENGM_SIZE_OF_LONG@  
   #define OPENGM_SIZE_OF_UNSIGNED_LONG         @OPENGM_SIZE_OF_UNSIGNED_LONG@
   #define OPENGM_SIZE_OF_LONG_LONG             @OPENGM_SIZE_OF_LONG_LONG@  
   #define OPENGM_SIZE_OF_UNSIGNED_LONG_LONG    @OPENGM_SIZE_OF_UNSIGNED_LONG_LONG@  
   #define OPENGM_SIZE_OF_FLOAT                 @OPENGM_SIZE_OF_FLOAT@  
   #define OPENGM_SIZE_OF_DOUBLE                @OPENGM_SIZE_OF_DOUBLE@
   #define OPENGM_SIZE_OF_LONG_DOUBLE           @OPENGM_SIZE_OF_LONG_DOUBLE@
#endif
namespace opengm{
   
#ifndef OPENGM_USED_CMAKE
/// major version number of opengm
const unsigned int  VERSION_MAJOR = 2;
/// minor version number of opengm
const unsigned int  VERSION_MINOR = 0;
/// patch version number of opengm
const unsigned int  VERSION_PATCH = 2;
#else
/// major version number of opengm
const unsigned int  VERSION_MAJOR = @OPENGM_VERSION_MAJOR@;
/// minor version number of opengm
const unsigned int  VERSION_MINOR = @OPENGM_VERSION_MINOR@;
/// patch version number of opengm
const unsigned int  VERSION_PATCH = @OPENGM_VERSION_PATCH@;
#endif
/// usual factor order
///
/// this size indicates how many values (usualy the variables indices
/// of a factor ) can be stored on the stack. This value is only used
/// in opengm::FastSequence (as second template parameter )
const size_t USUAL_MAX_FACTOR_ORDER=5;

/// \var NO_DEBUG true if NDEBUG is true
#ifdef NDEBUG
const bool NO_DEBUG = true;
#else
const bool NO_DEBUG = false;
#endif
/// \cond HIDDEN_SYMBOLS
namespace detail_types{
// structs to identify if am system
// does not have a certain type   
struct NoCharOnSystem;
struct NoUnsignedCharOnSystem;
struct NoSignedCharOnSystem;
struct NoWCharTOnSystem;
struct NoShortOnSystem;
struct NoUnsignedShortOnSystem;
struct NoIntOnSystem;
struct NoUnsignedIntOnSystem;
struct NoLongOnSystem;
struct NoUnsignedLongOnSystem;
struct NoUnsignedLongLongOnSystem;
struct NoLongLongOnSystem;
struct NoFloatOnSystem;
struct NoDoubleOnSystem;
struct NoLongDoubleOnSystem;
struct NoUIntTypeOnSystem;
struct NoIntTypeOnSystem;
struct NoFloatTypeOnSystem;
struct NoUInt8OnSystem;
struct NoUInt16OnSystem;
struct NoUInt32OnSystem;
struct NoUInt64OnSystem;
struct NoInt8OnSystem;
struct NoInt16OnSystem;
struct NoInt32OnSystem;
struct NoInt64OnSystem;
struct NoFloat32OnSystem;
struct NoFloat64OnSystem;
struct NoFloat128OnSystem;
// typedefs to types to identify if am system
// does not have a certain type
#ifdef OPENGM_NO_CHAR
typedef opengm::meta::InvalideType<NoCharOnSystem> Char;
#else
typedef char Char;
#endif
#ifdef OPENGM_NO_UNSIGNED_CHAR
typedef opengm::meta::InvalideType<NoUnsignedCharOnSystem> UnsignedChar;
#else
typedef unsigned char UnsignedChar;
#endif
#ifdef OPENGM_NO_SIGNED_CHAR
typedef opengm::meta::InvalideType<NoSignedCharOnSystem> SignedChar;
#else
typedef signed char SignedChar;
#endif
#ifdef OPENGM_NO_WCHAR_T
typedef opengm::meta::InvalideType<NoWCharTOnSystem> WCharT;
#else
typedef wchar_t WCharT;
#endif
#ifdef OPENGM_NO_SHORT
typedef NoShortOnSystem Short;
#else
typedef short Short;
#endif
#ifdef OPENGM_NO_UNSIGNED_SHORT
typedef opengm::meta::InvalideType<NoUnsignedShortOnSystem> UnsignedShort;
#else
typedef unsigned short UnsignedShort;
#endif
#ifdef OPENGM_NO_INT
typedef opengm::meta::InvalideType<NoIntOnSystem> Int;
#else
typedef int Int;
#endif
#ifdef OPENGM_NO_UNSIGNED_INT
typedef opengm::meta::InvalideType<NoUnsignedIntOnSystem> UnsignedInt;
#else
typedef unsigned int UnsignedInt; 
#endif
#ifdef OPENGM_NO_LONG
typedef opengm::meta::InvalideType<NoLongOnSystem> Long;
#else
typedef long Long;
#endif
#ifdef OPENGM_NO_UNSIGNED_LONG
typedef opengm::meta::InvalideType<NoUnsignedLongOnSystem> UnsignedLong;
#else
typedef unsigned long UnsignedLong;
#endif
#ifdef OPENGM_NO_LONG_LONG
typedef opengm::meta::InvalideType<NoLongLongOnSystem> LongLong;
#else
typedef long long LongLong;
#endif
#ifdef OPENGM_NO_UNSIGNED_LONG
typedef opengm::meta::InvalideType<NoUnsignedLongLongOnSystem> UnsignedLongLong;
#else
typedef unsigned long long UnsignedLongLong;
#endif
#ifdef OPENGM_NO_Float
typedef opengm::meta::InvalideType<NoFloatOnSystem> Float;
#else
typedef float Float;
#endif
#ifdef OPENGM_NO_DOUBLE
typedef opengm::meta::InvalideType<NoDoubleOnSystem> Double;
#else
typedef double Double;
#endif
#ifdef OPENGM_NO_LONG_DOUBLE
typedef opengm::meta::InvalideType<NoLongDoubleOnSystem> LongDouble;
#else
typedef long double LongDouble;
#endif
typedef bool Bool ;
// typelists of the basic c++ types
// Floats:
typedef opengm::meta::TypeListGenerator<
   Float,Double , LongDouble
>::type StdFloatingPointTypesTypeList;
// UInt:
typedef opengm::meta::TypeListGenerator<
   UnsignedChar,UnsignedShort, UnsignedInt, UnsignedLong, UnsignedLongLong
>::type StdUnsignedIntegerTypesTypeList;
// Int:
typedef opengm::meta::TypeListGenerator<
   Char, SignedChar, Short, Int, Long,LongLong
>::type StdSignedIntegerTypesTypeList;
// typelists of the sizes of the basic c++ types
// Float sizes:
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SizeT<OPENGM_SIZE_OF_FLOAT>,meta::SizeT<OPENGM_SIZE_OF_DOUBLE>,
   opengm::meta::SizeT<OPENGM_SIZE_OF_LONG_DOUBLE>
>::type StdFloatingPointSizesTypeList;
// UInt sizes:
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SizeT<OPENGM_SIZE_OF_UNSIGNED_CHAR>, opengm::meta::SizeT<OPENGM_SIZE_OF_UNSIGNED_SHORT>,
   opengm::meta::SizeT<OPENGM_SIZE_OF_UNSIGNED_INT>, opengm::meta::SizeT<OPENGM_SIZE_OF_UNSIGNED_LONG>, 
   opengm::meta::SizeT<OPENGM_SIZE_OF_UNSIGNED_LONG_LONG>
>::type StdUnsignedIntegerSizesTypeList;
// Int sizes:
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SizeT<OPENGM_SIZE_OF_CHAR>, opengm::meta::SizeT<OPENGM_SIZE_OF_SIGNED_CHAR>, 
   opengm::meta::SizeT<OPENGM_SIZE_OF_SHORT>,opengm::meta::SizeT<OPENGM_SIZE_OF_INT>,
   opengm::meta::SizeT<OPENGM_SIZE_OF_LONG>,opengm::meta::SizeT<OPENGM_SIZE_OF_LONG_LONG>
>::type StdSignedIntegerSizesTypeList;
// platform independent
// UInt :
typedef opengm::meta::FindSizedType<StdUnsignedIntegerTypesTypeList,StdUnsignedIntegerSizesTypeList,
   1,meta::InvalidType<NoUInt8OnSystem > >::type UInt8Type ;
typedef opengm::meta::FindSizedType<StdUnsignedIntegerTypesTypeList,StdUnsignedIntegerSizesTypeList,
   2,meta::InvalidType<NoUInt16OnSystem> >::type  UInt16Type ;
typedef opengm::meta::FindSizedType<StdUnsignedIntegerTypesTypeList,StdUnsignedIntegerSizesTypeList,
   4,meta::InvalidType<NoUInt32OnSystem> >::type  UInt32Type ;
typedef opengm::meta::FindSizedType<StdUnsignedIntegerTypesTypeList,StdUnsignedIntegerSizesTypeList,
   8,meta::InvalidType<NoUInt64OnSystem> >::type  UInt64Type ;
//Int :
typedef opengm::meta::FindSizedType<StdSignedIntegerTypesTypeList,StdSignedIntegerSizesTypeList,
   1,meta::InvalidType<NoInt8OnSystem > >::type  Int8Type ;
typedef opengm::meta::FindSizedType<StdSignedIntegerTypesTypeList,StdSignedIntegerSizesTypeList,
   2,meta::InvalidType<NoInt16OnSystem> >::type  Int16Type ;
typedef opengm::meta::FindSizedType<StdSignedIntegerTypesTypeList,StdSignedIntegerSizesTypeList,
   4,meta::InvalidType<NoInt32OnSystem> >::type  Int32Type ;
typedef opengm::meta::FindSizedType<StdSignedIntegerTypesTypeList,StdSignedIntegerSizesTypeList,
   8,meta::InvalidType<NoInt64OnSystem> >::type  Int64Type ;
// Float :
typedef opengm::meta::FindSizedType<StdFloatingPointTypesTypeList,StdFloatingPointSizesTypeList,
   4,meta::InvalidType<NoFloat32OnSystem> >::type  Float32Type ;
typedef opengm::meta::FindSizedType<StdFloatingPointTypesTypeList,StdFloatingPointSizesTypeList,
   8,meta::InvalidType<NoFloat64OnSystem> >::type  Float64Type ;
typedef opengm::meta::FindSizedType<StdFloatingPointTypesTypeList,StdFloatingPointSizesTypeList,
   16,meta::InvalidType<NoFloat128OnSystem> >::type  Float128Type ;
// opengm::meta-"switch-cases" typelists to find out the
// biggest and smallest uint, int and float type
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt64Type >::value >::value ,UInt64Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt32Type >::value >::value ,UInt32Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt16Type >::value >::value ,UInt16Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt8Type  >::value >::value ,UInt8Type>
>::type UIntSwitchCasesBiggest;
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int64Type >::value >::value ,Int64Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int32Type >::value >::value ,Int32Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int16Type >::value >::value ,Int16Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int8Type  >::value >::value ,Int8Type>
>::type IntSwitchCasesBiggest;
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float128Type >::value >::value ,Float128Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float64Type  >::value >::value ,Float64Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float32Type  >::value >::value ,Float32Type>
>::type FloatSwitchCasesBiggest;
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt8Type  >::value >::value ,UInt8Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt16Type >::value >::value ,UInt16Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt32Type >::value >::value ,UInt32Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< UInt64Type >::value >::value ,UInt64Type>
>::type UIntSwitchCasesSmallest;
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int8Type >::value >::value ,Int8Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int16Type >::value >::value ,Int16Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int32Type >::value >::value ,Int32Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Int64Type  >::value >::value ,Int64Type>
>::type IntSwitchCasesSmallest;
typedef opengm::meta::TypeListGenerator<
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float32Type  >::value >::value,Float32Type >,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float64Type  >::value >::value ,Float64Type>,
   opengm::meta::SwitchCase< opengm::meta::Not< opengm::meta::IsInvalidType< Float128Type  >::value >::value ,Float128Type>
>::type FloatSwitchCasesSmallest;
// biggest type
typedef opengm::meta::Switch< UIntSwitchCasesBiggest  ,
   NoUIntTypeOnSystem  >::type BiggestUIntType;
typedef opengm::meta::Switch< IntSwitchCasesBiggest   , 
   NoIntTypeOnSystem   >::type BiggestIntType;
typedef opengm::meta::Switch< FloatSwitchCasesBiggest , 
   NoFloatTypeOnSystem >::type BiggestFloatType;
// smallest types
typedef opengm::meta::Switch< UIntSwitchCasesSmallest  ,
   NoUIntTypeOnSystem  >::type SmallestUIntType;
typedef opengm::meta::Switch< IntSwitchCasesSmallest   ,
   NoIntTypeOnSystem   >::type SmallestIntType;
typedef opengm::meta::Switch< FloatSwitchCasesSmallest ,
   NoFloatTypeOnSystem >::type SmallestFloatType;
} // end namespace detail_types
/// \endcond
// UInt Types:
/// uint8
typedef detail_types::UInt8Type           UInt8Type;
/// uint16
typedef detail_types::UInt16Type          UInt16Type;
/// uint32
typedef detail_types::UInt32Type          UInt32Type;
/// uint64
typedef detail_types::UInt64Type          UInt64Type;
// Int Types:
typedef detail_types::Int8Type            Int8Type;
/// int8
typedef detail_types::Int16Type           Int16Type;
/// int16
typedef detail_types::Int32Type           Int32Type;
/// int32
typedef detail_types::Int64Type           Int64Type;
// Float Types:
/// float32
typedef detail_types::Float32Type         Float32Type;
/// float64
typedef detail_types::Float64Type         Float64Type;
/// biggest / longest uint
typedef detail_types::BiggestUIntType     BiggestUIntType;
/// biggest / longest int
typedef detail_types::BiggestIntType      BiggestIntType;
typedef detail_types::BiggestFloatType    BiggestFloatType;
// smallest Types:
/// smallest / shortest int
typedef detail_types::SmallestUIntType    SmallestUIntType;
typedef detail_types::SmallestIntType     SmallestIntType;
typedef detail_types::SmallestFloatType   SmallestFloatType;
// default Types:
/// default uint (biggest / longest uint)
typedef BiggestUIntType                   UIntType;
/// default uint (biggest / longest int)
typedef BiggestIntType                    IntType;
/// default uint (biggest / longest float)
typedef SmallestFloatType                 FloatType;
} // end namespace opengm
#endif	/* CONFIG_HXX */

