
// this file is a slightly edited version of
// PrimitivePolynomialsModuloTwoUpToDegree27.h
// © 2002 "Monte Carlo Methods in Finance"
// as provided ready for compilation in the directory
// "PrimitivePolynomialsModuloTwo" on the CD accompanying the book
// "Monte Carlo Methods in Finance" by Peter Jäckel.
//
// the original copyright is:
// ===========================================================================
// Copyright (C) 2002 "Monte Carlo Methods in Finance". All rights reserved.
//
// Permission to use, copy, modify, and distribute this software is freely
// granted, provided that this notice is preserved.
// ===========================================================================

#ifndef primitivepolynomials_h
#define primitivepolynomials_h

// This file is provided for the use with Sobol' sequences of higher
// dimensions. The dimensionality of the Sobol' sequence can be extended to
// virtually any size you ever might need by the aid of the table of
// primitive polynomials modulo two.
// It is up to you to define a macro PPMT_MAX_DIM to a positive integer
// less than or equal to 8129334. If you don't define it, it will be set
// below to N_PRIMITIVES_UP_TO_DEGREE_18 which is 21200. That's how many
// primitive polynomials are provided by the standard primitivepolynomial.c
// distributed with QuantLib and that will be compiled into a static array.
// Should you need more, another version of primitivepolynomial.c is available
// for download from quantlib.org which provide polynomials up to degree 27
// for a grand total of 8129334 dimensions.
// Since 8129334 longs compile into an object file of at least 32517336 byte
// size (in fact, gcc -c -O0 PrimitivePolynomialsModuloTwoUpToDegree27.c
// produced a file PrimitivePolynomialsModuloTwoUpToDegree27.o with 32519920
// bytes), it is recommended to only compile as many as you may ever need.
// Worse even than the output file size is the virtual memory requirement
// for the compilation. For Visual C++ 6 you will need to use the /Zm compiler
// option to set the compiler's memory allocation limit (/Zm1500 should work)
// So really only take the maximum of what you think you might ever need.
// After all, you can always recompile with more, should you need it.


//	PPMT : Primitive Polynomials Modulo Two
//
//
// The encoding is as follows:
//
// The coefficients of each primitive polynomial are the bits of the given
// integer. The leading and trailing coefficients, which are 1 for all of the
// polynomials, have been omitted.
//
// Example: The polynomial
//
//      4    2
//     x  + x  + 1
//
// is encoded as  2  in the array of polynomials of degree 4 because the
// binary sequence of coefficients
//
//   10101
//
// becomes
//
//    0101
//
// after stripping off the top bit, and this is converted to
//
//     010
//
// by right-shifting and losing the rightmost bit. Similarly, we have
//
//   5    4    2
//  x  + x  + x  + x + 1
//
// encoded as  13  [ (1)1101(1) ]  in the array for degree 5.


// Example: replace primitivepolynomials.c provided by QuantLib standard
// distribution with the 8129334 polinomials version and
// comment out the line below if you want absolutely all of the
// provided primitive polynomials modulo two.
//
// #define PPMT_MAX_DIM 8129334

// Note that PPMT_MAX_DIM will be redefined to be the nearest equal or larger
// number of polynomials up to one of the predefined macros
// N_PRIMITIVES_UP_TO_DEGREE_XX
// below.


#define N_PRIMITIVES_UP_TO_DEGREE_01         1
#define N_PRIMITIVES_UP_TO_DEGREE_02         2
#define N_PRIMITIVES_UP_TO_DEGREE_03         4
#define N_PRIMITIVES_UP_TO_DEGREE_04         6
#define N_PRIMITIVES_UP_TO_DEGREE_05        12
#define N_PRIMITIVES_UP_TO_DEGREE_06        18
#define N_PRIMITIVES_UP_TO_DEGREE_07        36
#define N_PRIMITIVES_UP_TO_DEGREE_08        52
#define N_PRIMITIVES_UP_TO_DEGREE_09       100
#define N_PRIMITIVES_UP_TO_DEGREE_10       160
#define N_PRIMITIVES_UP_TO_DEGREE_11       336
#define N_PRIMITIVES_UP_TO_DEGREE_12       480
#define N_PRIMITIVES_UP_TO_DEGREE_13      1110
#define N_PRIMITIVES_UP_TO_DEGREE_14      1866
#define N_PRIMITIVES_UP_TO_DEGREE_15      3666
#define N_PRIMITIVES_UP_TO_DEGREE_16      5714
#define N_PRIMITIVES_UP_TO_DEGREE_17     13424
#define N_PRIMITIVES_UP_TO_DEGREE_18     21200
#define N_PRIMITIVES_UP_TO_DEGREE_19     48794
#define N_PRIMITIVES_UP_TO_DEGREE_20     72794
#define N_PRIMITIVES_UP_TO_DEGREE_21    157466
#define N_PRIMITIVES_UP_TO_DEGREE_22    277498
#define N_PRIMITIVES_UP_TO_DEGREE_23    634458
#define N_PRIMITIVES_UP_TO_DEGREE_24    910938
#define N_PRIMITIVES_UP_TO_DEGREE_25   2206938
#define N_PRIMITIVES_UP_TO_DEGREE_26   3926838
#define N_PRIMITIVES_UP_TO_DEGREE_27   8129334

#define N_PRIMITIVES N_PRIMITIVES_UP_TO_DEGREE_27

#ifndef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_18
#endif

#if      PPMT_MAX_DIM > N_PRIMITIVES
# error  PPMT_MAX_DIM cannot be greater than N_PRIMITIVES
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_01
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_01
# define N_MAX_DEGREE 01
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_02
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_02
# define N_MAX_DEGREE 02
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_03
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_03
# define N_MAX_DEGREE 03
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_04
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_04
# define N_MAX_DEGREE 04
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_05
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_05
# define N_MAX_DEGREE 05
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_06
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_06
# define N_MAX_DEGREE 06
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_07
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_07
# define N_MAX_DEGREE 07
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_08
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_08
# define N_MAX_DEGREE 08
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_09
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_09
# define N_MAX_DEGREE 09
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_10
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_10
# define N_MAX_DEGREE 10
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_11
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_11
# define N_MAX_DEGREE 11
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_12
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_12
# define N_MAX_DEGREE 12
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_13
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_13
# define N_MAX_DEGREE 13
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_14
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_14
# define N_MAX_DEGREE 14
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_15
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_15
# define N_MAX_DEGREE 15
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_16
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_16
# define N_MAX_DEGREE 16
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_17
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_17
# define N_MAX_DEGREE 17
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_18
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_18
# define N_MAX_DEGREE 18
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_19
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_19
# define N_MAX_DEGREE 19
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_20
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_20
# define N_MAX_DEGREE 20
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_21
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_21
# define N_MAX_DEGREE 21
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_22
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_22
# define N_MAX_DEGREE 22
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_23
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_23
# define N_MAX_DEGREE 23
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_24
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_24
# define N_MAX_DEGREE 24
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_25
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_25
# define N_MAX_DEGREE 25
#elif    PPMT_MAX_DIM <= N_PRIMITIVES_UP_TO_DEGREE_26
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_26
# define N_MAX_DEGREE 26
#else
# undef  PPMT_MAX_DIM
# define PPMT_MAX_DIM N_PRIMITIVES_UP_TO_DEGREE_27
# define N_MAX_DEGREE 27
#endif

// Microsoft Visual C++ 6.0
#if defined(_MSC_VER)
    // disable useless warning C4049
    // compiler limit : terminating line number emission
    // No line number support is available for file with more
    // than 64K source lines.
    #pragma warning(disable: 4049)
#endif


#ifdef __cplusplus

extern "C"

#endif

/*! You can access the following array as in PrimitivePolynomials[i][j]
    with i and j counting from 0 in C convention. PrimitivePolynomials[i][j]
    will get you the j-th (counting from zero) primitive polynomial of degree
    i+1. Each one-dimensional array of primitive polynomials of a given
    degree is terminated with an entry of -1. Accessing beyond this entry
    will result in a memory violation and must be avoided.  */
const long *const PrimitivePolynomials[N_MAX_DEGREE];

#endif
