/*
 *  A rng module implementation which can return a sample as an array.
 *  Author : Pierre Schnizer <schnizer@users.sourceforge.net>
 *  Date   : 1. July. 2003
 *
 */

#include <pygsl/error_helpers.h>
#include <pygsl/block_helpers.h>
#include <pygsl/utils.h>

#ifdef PyGSL_NO_IMPORT_API
#undef PyGSL_NO_IMPORT_API
#endif
#include <pygsl/rng_helpers.h>
#include <pygsl/rng.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

/*
 * All doc strings
 */
static PyObject *module = NULL;

#include "rng_helpers.c"
#include "rngmodule_docs.h"

static void rng_delete(PyGSL_rng *self);
static PyObject * rng_call(PyGSL_rng *self, PyObject *args);

#undef PyGSL_RNG_Check

#define PyGSL_RNG_Check(op) ((op)->ob_type == &PyGSL_rng_pytype)

static PyObject *		/* on "instance.attr" */
rng_getattr (PyGSL_rng *self, char *name);

PyTypeObject PyGSL_rng_pytype = {
  PyObject_HEAD_INIT(NULL)	/* fix up the type slot in initcrng */
  0,				/* ob_size */
  "PyGSL_rng",			/* tp_name */
  sizeof(PyGSL_rng),	        /* tp_basicsize */
  0,				/* tp_itemsize */

  /* standard methods */
  (destructor)  rng_delete,       /* tp_dealloc  ref-count==0  */
  (printfunc)   0,		   /* tp_print    "print x"     */
  (getattrfunc) rng_getattr,       /* tp_getattr  "x.attr"      */
  (setattrfunc) 0,		   /* tp_setattr  "x.attr=v"    */
  (cmpfunc)     0,		   /* tp_compare  "x > y"       */
  (reprfunc)    0,                 /* tp_repr     `x`, print x  */

  /* type categories */
  0,				/* tp_as_number   +,-,*,/,%,&,>>,pow...*/
  0,				/* tp_as_sequence +,[i],[i:j],len, ...*/
  0,				/* tp_as_mapping  [key], len, ...*/

  /* more methods */
  (hashfunc)     0,		/* tp_hash    "dict[x]" */
  (ternaryfunc)  rng_call,      /* tp_call    "x()"     */
  (reprfunc)     0,             /* tp_str     "str(x)"  */
  (getattrofunc) 0,		/* tp_getattro */
  (setattrofunc) 0,		/* tp_setattro */
  0,				/* tp_as_buffer */
  0L,				/* tp_flags */
  rng_type_doc		/* tp_doc */
};

static PyObject *
PyGSL_rng_init(PyObject *self, PyObject *args, const gsl_rng_type * rng_type)
{

     PyGSL_rng *rng = NULL;

     FUNC_MESS_BEGIN();
     rng =  (PyGSL_rng *) PyObject_NEW(PyGSL_rng, &PyGSL_rng_pytype);
     if(rng == NULL){
	  return NULL;
     }
     if(rng_type == NULL){
	  rng->rng = gsl_rng_alloc(gsl_rng_default);
	  gsl_rng_set(rng->rng, gsl_rng_default_seed);
     }else{
	  rng->rng = gsl_rng_alloc(rng_type);
     }
     FUNC_MESS_END();
     return (PyObject *) rng;
}

#define RNG_ARNG(name)                                                       \
static PyObject* PyGSL_rng_init_ ## name (PyObject *self, PyObject *args)    \
{                                                                            \
     PyObject *tmp = NULL;                                                   \
     FUNC_MESS_BEGIN();                                                      \
     tmp = PyGSL_rng_init(self, args,  gsl_rng_ ## name);                    \
     if (tmp == NULL){                                                       \
	  PyGSL_add_traceback(module, __FILE__, __FUNCTION__, __LINE__);     \
     }                                                                       \
     FUNC_MESS_END();                                                        \
     return tmp;                                                             \
}

#include "rng_list.h"

static PyObject *
PyGSL_rng_init_default(PyObject *self, PyObject *args)
{
     PyObject *tmp = NULL;
     FUNC_MESS_BEGIN();
     tmp = PyGSL_rng_init(self, args,  NULL);
     if (tmp == NULL){
	  PyGSL_add_traceback(module, __FILE__, __FUNCTION__, __LINE__ - 1);
     }
     FUNC_MESS_END();
     return tmp;
}

static void
rng_delete(PyGSL_rng *self)
{
     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(self->rng != NULL){
	  DEBUG_MESS(5, "Freeing gsl_rng @ %p", self->rng);
	  gsl_rng_free(self->rng);
	  self->rng = NULL;
     }
     DEBUG_MESS(1, " self %p\n",(void *) self);
     PyObject_Del(self);
     self = NULL;
     FUNC_MESS_END();
}

static PyObject *		/* on "instance.uniform()" and "instance()" */
rng_call (PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     tmp = PyGSL_rng_to_double(self, args, gsl_rng_uniform);
     if(!tmp)
	  PyGSL_add_traceback(module, __FILE__, "rng.__call__", __LINE__ - 2);
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_uniform_pos (PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     tmp = PyGSL_rng_to_double(self, args, gsl_rng_uniform_pos);
     if(!tmp)
	  PyGSL_add_traceback(module, __FILE__, "rng.uniform_pos", __LINE__-2);
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_uniform_int (PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp = NULL;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     tmp = PyGSL_rng_ul_to_ulong(self, args, gsl_rng_uniform_int);
     if(!tmp)
	  PyGSL_add_traceback(module, __FILE__, "rng.uniform_int", __LINE__-2);
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_get(PyGSL_rng *self, PyObject *args)
{
     PyObject  *tmp = NULL;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     tmp = PyGSL_rng_to_ulong(self, args, gsl_rng_get);
     if(!tmp)
	  PyGSL_add_traceback(module, __FILE__, "rng.get", __LINE__ - 2);
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_set(PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp = NULL, *seed = NULL;
     unsigned long int useed;
     int lineno;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(0 == PyArg_ParseTuple(args, "O", &tmp)){
	  lineno = __LINE__; goto fail;
     }
     assert(tmp != NULL);
     seed = PyNumber_Long(tmp);
     if(!seed){lineno = __LINE__ - 1; goto fail;}
     useed =  PyLong_AsUnsignedLong(seed);
     gsl_rng_set(self->rng, useed);

     Py_INCREF(Py_None);
     FUNC_MESS_END();
     return Py_None;

 fail:
     FUNC_MESS("FAIL");
     PyGSL_add_traceback(module, __FILE__, "rng.set", lineno);
     return NULL;
}

static PyObject *
rng_name(PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp = NULL;
     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(0 == PyArg_ParseTuple(args, ":name"))
	  return NULL;
     tmp = PyString_FromString(gsl_rng_name(self->rng));
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_max(PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp = NULL;
     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(0 == PyArg_ParseTuple(args, ":max"))
	  return NULL;
     tmp = PyLong_FromUnsignedLong(gsl_rng_max(self->rng));
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_min(PyGSL_rng *self, PyObject *args)
{
     PyObject *tmp = NULL;
     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(0 == PyArg_ParseTuple(args, ":min"))
	  return NULL;
     tmp = PyLong_FromUnsignedLong(gsl_rng_min(self->rng));
     FUNC_MESS_END();
     return tmp;
}

static PyObject *
rng_clone(PyGSL_rng *self, PyObject *args)
{
     PyGSL_rng * rng = NULL;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));
     if(0 == PyArg_ParseTuple(args, ":clone"))
	  return NULL;
     rng =  (PyGSL_rng *) PyObject_NEW(PyGSL_rng, &PyGSL_rng_pytype);
     rng->rng = gsl_rng_clone(self->rng);
     FUNC_MESS_END();
     return (PyObject *) rng;
}

/*
 * Is #name a standard macro definition?
 */
#define RNG_DISTRIBUTION(name, function)                                     \
static PyObject* rng_ ## name (PyGSL_rng *self, PyObject *args)              \
{                                                                            \
     PyObject *tmp = NULL;                                                   \
     FUNC_MESS_BEGIN();                                                      \
     tmp = PyGSL_rng_ ## function (self, args,  gsl_ran_ ## name);           \
     if (tmp == NULL){                                                       \
       /* PyGSL_add_traceback(module, __FILE__, "rng." #name, __LINE__); */  \
	  PyGSL_add_traceback(module, __FILE__, __FUNCTION__, __LINE__);     \
     }                                                                       \
     FUNC_MESS_END();                                                        \
     return tmp;                                                             \
}

#include "rng_distributions.h"

/* Redefine to trigger emacs into correct coloring */
/*
 * This list is not optimized. I guess... Do you know how to optimize it?
 */
static struct PyMethodDef rng_methods[] = {
  {"get", (PyCFunction) rng_get, METH_VARARGS, rng_get_doc},
  {"set", (PyCFunction) rng_set, METH_VARARGS, rng_set_doc},
  {"uniform", (PyCFunction) rng_call, METH_VARARGS, rng_uniform_doc},
  {"uniform_pos", (PyCFunction) rng_uniform_pos, METH_VARARGS, rng_uniform_pos_doc},
  {"uniform_int", (PyCFunction) rng_uniform_int, METH_VARARGS, rng_uniform_int_doc},
  {"name", (PyCFunction) rng_name, METH_VARARGS, NULL},
  {"max", (PyCFunction) rng_max, METH_VARARGS, rng_max_doc},
  {"min", (PyCFunction) rng_min, METH_VARARGS, rng_min_doc},
  {"clone", (PyCFunction) rng_clone, METH_VARARGS, rng_clone_doc},
#if  (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION == 3)
  /* RNG clone can not be used to copy a rng type in python 2.3 No idea how to do that correctly */
#else
  {"__copy__", (PyCFunction) rng_clone, METH_VARARGS, rng_clone_doc},
#endif
  /* distributions */
  {"gaussian", (PyCFunction) rng_gaussian,METH_VARARGS, rng_gaussian_doc},
  {"gaussian_ratio_method", (PyCFunction) rng_gaussian_ratio_method,METH_VARARGS, rng_gaussian_ratio_doc},
  {"ugaussian", (PyCFunction) rng_ugaussian,METH_VARARGS, rng_ugaussian_doc},
  {"ugaussian_ratio_method",(PyCFunction) rng_ugaussian_ratio_method,METH_VARARGS, rng_ugaussian_ratio_doc},
  {"gaussian_tail", (PyCFunction) rng_gaussian_tail,METH_VARARGS, rng_gaussian_tail_doc},
  {"ugaussian_tail",(PyCFunction) rng_ugaussian_tail,METH_VARARGS, rng_ugaussian_tail_doc},
  {"bivariate_gaussian", (PyCFunction) rng_bivariate_gaussian,METH_VARARGS, rng_bivariate_gaussian_doc},
  {"exponential",(PyCFunction)rng_exponential,METH_VARARGS, rng_exponential_doc},
  {"laplace",(PyCFunction)rng_laplace,METH_VARARGS, rng_laplace_doc},
  {"exppow",(PyCFunction)rng_exppow,METH_VARARGS, rng_exppow_doc},
  {"cauchy",(PyCFunction)rng_cauchy,METH_VARARGS, rng_cauchy_doc},
  {"rayleigh",(PyCFunction)rng_rayleigh,METH_VARARGS, rng_rayleigh_doc},
  {"rayleigh_tail",(PyCFunction)rng_rayleigh_tail,METH_VARARGS, rng_rayleigh_tail_doc},
  {"levy",(PyCFunction)rng_levy,METH_VARARGS, rng_levy_doc},
  {"levy_skew",(PyCFunction)rng_levy_skew,METH_VARARGS, rng_levy_skew_doc},
  {"gamma",(PyCFunction)rng_gamma,METH_VARARGS, rng_gamma_doc},
  {"gamma_int",(PyCFunction)rng_gamma_int,METH_VARARGS, NULL},
  {"flat",(PyCFunction)rng_flat,METH_VARARGS, rng_flat_doc},
  {"lognormal",(PyCFunction)rng_lognormal,METH_VARARGS, rng_lognormal_doc},
  {"chisq",(PyCFunction)rng_chisq,METH_VARARGS, rng_chisq_doc},
  {"fdist",(PyCFunction)rng_fdist,METH_VARARGS, rng_fdist_doc},
  {"tdist",(PyCFunction)rng_tdist,METH_VARARGS, rng_tdist_doc},
  {"beta",(PyCFunction)rng_beta,METH_VARARGS, rng_beta_doc},
  {"logistic",(PyCFunction)rng_logistic,METH_VARARGS, rng_logistic_doc},
  {"pareto",(PyCFunction)rng_pareto,METH_VARARGS, rng_pareto_doc},
  {"dir_2d",(PyCFunction)rng_dir_2d,METH_VARARGS, rng_dir_2d_doc},
  {"dir_2d_trig_method",(PyCFunction)rng_dir_2d_trig_method,METH_VARARGS, rng_dir_2d_trig_method_doc},
  {"dir_3d",(PyCFunction)rng_dir_3d,METH_VARARGS, rng_dir_3d_doc},
  {"dir_nd",(PyCFunction)rng_dir_nd,METH_VARARGS, rng_dir_nd_doc},
  {"weibull",(PyCFunction)rng_weibull,METH_VARARGS, rng_weibull_doc},
  {"gumbel1",(PyCFunction)rng_gumbel1,METH_VARARGS, rng_gumbel1_doc},
  {"gumbel2",(PyCFunction)rng_gumbel2,METH_VARARGS, rng_gumbel2_doc},
  {"poisson",(PyCFunction)rng_poisson,METH_VARARGS, rng_poisson_doc},
  {"bernoulli",(PyCFunction)rng_bernoulli,METH_VARARGS, rng_bernoulli_doc},
  {"binomial",(PyCFunction)rng_binomial,METH_VARARGS, rng_binomial_doc},
  {"negative_binomial",(PyCFunction)rng_negative_binomial,METH_VARARGS, rng_negative_binomial_doc},
  {"pascal",(PyCFunction)rng_pascal,METH_VARARGS, rng_pascal_doc},
  {"geometric",(PyCFunction)rng_geometric,METH_VARARGS, rng_geometric_doc},
  {"hypergeometric",(PyCFunction)rng_hypergeometric,METH_VARARGS, rng_hypergeometric_doc},
  {"logarithmic",(PyCFunction)rng_logarithmic,METH_VARARGS, rng_logarithmic_doc},
  {"landau",(PyCFunction)rng_landau,METH_VARARGS, rng_landau_doc},
  {"erlang",(PyCFunction)rng_erlang,METH_VARARGS, NULL},
  {"multinomial",(PyCFunction)rng_multinomial,METH_VARARGS, multinomial_doc},
  {"dirichlet",(PyCFunction)rng_dirichlet,METH_VARARGS, rng_dirichlet_doc},
  {NULL, NULL,}
};

static PyObject *
rng_getattr(PyGSL_rng *self, char *name)
{
     PyObject *tmp = NULL;

     FUNC_MESS_BEGIN();
     assert(PyGSL_RNG_Check(self));

     tmp = Py_FindMethod(rng_methods, (PyObject *) self, name);
     if(NULL == tmp){
	  PyGSL_add_traceback(module, __FILE__, "rng.__attr__", __LINE__ - 1);
	  return NULL;
     }
     return tmp;
}

static PyObject *
rng_create_list(PyObject *self, PyObject *args)
{
     const gsl_rng_type** thisRNGType=gsl_rng_types_setup();
     PyObject* list = NULL, *item=NULL;

     FUNC_MESS_BEGIN();
     /* provide other rng types as subclasses of rng */

     list = PyList_New(0);
     while ((*thisRNGType)!=NULL) {
	  item = PyString_FromString((*thisRNGType)->name);
	  Py_INCREF(item);
	  assert(item);
	  PyGSL_clear_name(PyString_AsString(item), PyString_Size(item));
	  if(PyList_Append(list, item) != 0)
	       goto fail;
	  thisRNGType++;
     }
     FUNC_MESS_END();
     return list;
 fail:
     Py_XDECREF(list);
     Py_XDECREF(item);
     return NULL;
}

/*---------------------------------------------------------------------------*/
/* Module set up */
#define RNG_GENERATE_PDF
#undef RNG_DISTRIBUTION
#define RNG_DISTRIBUTION(name, function)                                   \
static PyObject* rng_ ## name ## _pdf (PyObject *self, PyObject *args)     \
{                                                                          \
     PyObject * tmp;                                                       \
     FUNC_MESS_BEGIN();                                                    \
     tmp =  PyGSL_pdf_ ## function (self, args, gsl_ran_ ## name ## _pdf); \
     if (tmp == NULL){                                                     \
	  PyGSL_add_traceback(module, __FILE__, #name  "_pdf", __LINE__);  \
     }                                                                     \
     FUNC_MESS_END();                                                      \
     return tmp;                                                           \
}

#include "rng_distributions.h"

static PyObject* rng_dirichlet_lnpdf (PyObject *self, PyObject *args)
{
     PyObject *tmp;
     FUNC_MESS_BEGIN();
     tmp = PyGSL_pdf_dA_to_dA(self, args, gsl_ran_dirichlet_lnpdf);
     FUNC_MESS_END();
     return tmp;
}

static PyObject* rng_multinomial_lnpdf (PyObject *self, PyObject *args)
{
     PyObject *tmp;
     FUNC_MESS_BEGIN();
     tmp = PyGSL_pdf_uidA_to_uiA(self, args, gsl_ran_multinomial_lnpdf);
     FUNC_MESS_END();
     return tmp;
}

static const char rng_env_setup_doc[] =
"This function reads the environment variables `GSL_RNG_TYPE' and\n\
`GSL_RNG_SEED'.\n\
The environment variable `GSL_RNG_TYPE' should be the name of a\n\
generator, such as `taus' or `mt19937'. The environment variable\n\
`GSL_RNG_SEED' should contain the desired seed value. It is\n\
converted to an `unsigned long int' using the C library function\n\
`strtoul'.\n";

static PyObject *
PyGSL_rng_env_setup(PyObject *self, PyObject *args)
{
     gsl_rng_env_setup();
     Py_INCREF(Py_None);
     return Py_None;
}

static PyMethodDef PyGSL_rng_module_functions[] = {
     {"borosh13"        , PyGSL_rng_init_borosh13        , METH_NOARGS, NULL},
     {"cmrg"            , PyGSL_rng_init_cmrg            , METH_NOARGS, NULL},
     {"coveyou"         , PyGSL_rng_init_coveyou         , METH_NOARGS, NULL},
     {"fishman18"       , PyGSL_rng_init_fishman18       , METH_NOARGS, NULL},
     {"fishman20"       , PyGSL_rng_init_fishman20       , METH_NOARGS, NULL},
     {"fishman2x"       , PyGSL_rng_init_fishman2x       , METH_NOARGS, NULL},
     {"gfsr4"           , PyGSL_rng_init_gfsr4           , METH_NOARGS, NULL},
     {"knuthran"        , PyGSL_rng_init_knuthran        , METH_NOARGS, NULL},
     {"knuthran2"       , PyGSL_rng_init_knuthran2       , METH_NOARGS, NULL},
#ifdef  _PYGSL_GSL_HAS_RNG_KNUTHRAN2002
     {"knuthran2002"    , PyGSL_rng_init_knuthran2002    , METH_NOARGS, NULL},
#endif
     {"lecuyer21"       , PyGSL_rng_init_lecuyer21       , METH_NOARGS, NULL},
     {"minstd"          , PyGSL_rng_init_minstd          , METH_NOARGS, NULL},
     {"mrg"             , PyGSL_rng_init_mrg             , METH_NOARGS, NULL},
     {"mt19937"         , PyGSL_rng_init_mt19937         , METH_NOARGS, NULL},
     {"mt19937_1999"    , PyGSL_rng_init_mt19937_1999    , METH_NOARGS, NULL},
     {"mt19937_1998"    , PyGSL_rng_init_mt19937_1998    , METH_NOARGS, NULL},
     {"r250"	        , PyGSL_rng_init_r250            , METH_NOARGS, NULL},
     {"ran0"	        , PyGSL_rng_init_ran0            , METH_NOARGS, NULL},
     {"ran1"	        , PyGSL_rng_init_ran1            , METH_NOARGS, NULL},
     {"ran2"	        , PyGSL_rng_init_ran2            , METH_NOARGS, NULL},
     {"ran3"	        , PyGSL_rng_init_ran3            , METH_NOARGS, NULL},
     {"rand"	        , PyGSL_rng_init_rand            , METH_NOARGS, NULL},
     {"rand48"          , PyGSL_rng_init_rand48          , METH_NOARGS, NULL},
     {"random128_bsd"   , PyGSL_rng_init_random128_bsd   , METH_NOARGS, NULL},
     {"random128_glibc2", PyGSL_rng_init_random128_glibc2, METH_NOARGS, NULL},
     {"random128_libc5" , PyGSL_rng_init_random128_libc5 , METH_NOARGS, NULL},
     {"random256_bsd"   , PyGSL_rng_init_random256_bsd   , METH_NOARGS, NULL},
     {"random256_glibc2", PyGSL_rng_init_random256_glibc2, METH_NOARGS, NULL},
     {"random256_libc5" , PyGSL_rng_init_random256_libc5 , METH_NOARGS, NULL},
     {"random32_bsd"    , PyGSL_rng_init_random32_bsd    , METH_NOARGS, NULL},
     {"random32_glibc2" , PyGSL_rng_init_random32_glibc2 , METH_NOARGS, NULL},
     {"random32_libc5"  , PyGSL_rng_init_random32_libc5  , METH_NOARGS, NULL},
     {"random64_bsd"    , PyGSL_rng_init_random64_bsd    , METH_NOARGS, NULL},
     {"random64_glibc2" , PyGSL_rng_init_random64_glibc2 , METH_NOARGS, NULL},
     {"random64_libc5"  , PyGSL_rng_init_random64_libc5  , METH_NOARGS, NULL},
     {"random8_bsd"     , PyGSL_rng_init_random8_bsd     , METH_NOARGS, NULL},
     {"random8_glibc2"  , PyGSL_rng_init_random8_glibc2  , METH_NOARGS, NULL},
     {"random8_libc5"   , PyGSL_rng_init_random8_libc5   , METH_NOARGS, NULL},
     {"random_bsd"      , PyGSL_rng_init_random_bsd      , METH_NOARGS, NULL},
     {"random_glibc2"   , PyGSL_rng_init_random_glibc2   , METH_NOARGS, NULL},
     {"random_libc5"    , PyGSL_rng_init_random_libc5    , METH_NOARGS, NULL},
     {"randu"           , PyGSL_rng_init_randu           , METH_NOARGS, NULL},
     {"ranf"            , PyGSL_rng_init_ranf            , METH_NOARGS, NULL},
     {"ranlux"          , PyGSL_rng_init_ranlux          , METH_NOARGS, NULL},
     {"ranlux389"       , PyGSL_rng_init_ranlux389       , METH_NOARGS, NULL},
     {"ranlxd1"         , PyGSL_rng_init_ranlxd1         , METH_NOARGS, NULL},
     {"ranlxd2"         , PyGSL_rng_init_ranlxd2         , METH_NOARGS, NULL},
     {"ranlxs0"         , PyGSL_rng_init_ranlxs0         , METH_NOARGS, NULL},
     {"ranlxs1"         , PyGSL_rng_init_ranlxs1         , METH_NOARGS, NULL},
     {"ranlxs2"         , PyGSL_rng_init_ranlxs2         , METH_NOARGS, NULL},
     {"ranmar"          , PyGSL_rng_init_ranmar          , METH_NOARGS, NULL},
     {"slatec"          , PyGSL_rng_init_slatec          , METH_NOARGS, NULL},
     {"taus"            , PyGSL_rng_init_taus            , METH_NOARGS, NULL},
     {"taus2"           , PyGSL_rng_init_taus2           , METH_NOARGS, NULL},
     {"taus113"         , PyGSL_rng_init_taus113         , METH_NOARGS, NULL},
     {"transputer"      , PyGSL_rng_init_transputer      , METH_NOARGS, NULL},
     {"tt800"           , PyGSL_rng_init_tt800           , METH_NOARGS, NULL},
     {"uni"             , PyGSL_rng_init_uni             , METH_NOARGS, NULL},
     {"uni32"           , PyGSL_rng_init_uni32           , METH_NOARGS, NULL},
     {"vax"             , PyGSL_rng_init_vax             , METH_NOARGS, NULL},
     {"waterman14"      , PyGSL_rng_init_waterman14      , METH_NOARGS, NULL},
     {"zuf"             , PyGSL_rng_init_zuf             , METH_NOARGS, NULL},
     {"rng", PyGSL_rng_init_default, METH_NOARGS, rng_doc},
     {"list_available_rngs", rng_create_list, METH_VARARGS},
     /*densities*/
     {"gaussian_pdf",rng_gaussian_pdf,METH_VARARGS, rng_gaussian_pdf_doc},
     {"ugaussian_pdf",rng_ugaussian_pdf,METH_VARARGS, rng_ugaussian_pdf_doc},
     {"gaussian_tail_pdf",rng_gaussian_tail_pdf,METH_VARARGS, rng_gaussian_tail_pdf_doc},
     {"ugaussian_tail_pdf",rng_ugaussian_tail_pdf,METH_VARARGS, rng_ugaussian_tail_pdf_doc},
     {"bivariate_gaussian_pdf",rng_bivariate_gaussian_pdf,METH_VARARGS, rng_bivariate_gaussian_pdf_doc},
     {"exponential_pdf",rng_exponential_pdf,METH_VARARGS, rng_exponential_pdf_doc},
     {"laplace_pdf",rng_laplace_pdf,METH_VARARGS, rng_laplace_pdf_doc},
     {"exppow_pdf",rng_exppow_pdf,METH_VARARGS, rng_exppow_pdf_doc},
     {"cauchy_pdf",rng_cauchy_pdf,METH_VARARGS, rng_cauchy_pdf_doc},
     {"rayleigh_pdf",rng_rayleigh_pdf,METH_VARARGS, rng_rayleigh_pdf_doc},
     {"rayleigh_tail_pdf",rng_rayleigh_tail_pdf,METH_VARARGS, rng_rayleigh_tail_pdf_doc},
     {"gamma_pdf",rng_gamma_pdf,METH_VARARGS, rng_gamma_pdf_doc},
     {"flat_pdf",rng_flat_pdf,METH_VARARGS, rng_flat_pdf_doc},
     {"lognormal_pdf",rng_lognormal_pdf,METH_VARARGS, rng_lognormal_pdf_doc},
     {"chisq_pdf",rng_chisq_pdf,METH_VARARGS, rng_chisq_pdf_doc},
     {"fdist_pdf",rng_fdist_pdf,METH_VARARGS, rng_fdist_pdf_doc},
     {"tdist_pdf",rng_tdist_pdf,METH_VARARGS, rng_tdist_pdf_doc},
     {"beta_pdf",rng_beta_pdf,METH_VARARGS, rng_beta_pdf_doc},
     {"logistic_pdf",rng_logistic_pdf,METH_VARARGS, rng_logistic_pdf_doc},
     {"pareto_pdf",rng_pareto_pdf,METH_VARARGS, rng_pareto_pdf_doc},
     {"weibull_pdf",rng_weibull_pdf,METH_VARARGS, rng_weibull_pdf_doc},
     {"gumbel1_pdf",rng_gumbel1_pdf,METH_VARARGS, rng_gumbel1_pdf_doc},
     {"gumbel2_pdf",rng_gumbel2_pdf,METH_VARARGS, rng_gumbel2_pdf_doc},
     {"poisson_pdf",rng_poisson_pdf,METH_VARARGS, rng_poisson_pdf_doc},
     {"bernoulli_pdf",rng_bernoulli_pdf,METH_VARARGS, rng_bernoulli_pdf_doc},
     {"binomial_pdf",rng_binomial_pdf,METH_VARARGS,  rng_binomial_pdf_doc},
     {"negative_binomial_pdf",rng_negative_binomial_pdf,METH_VARARGS, rng_negative_binomial_pdf_doc},
     {"pascal_pdf",rng_pascal_pdf,METH_VARARGS, rng_pascal_pdf_doc},
     {"geometric_pdf",rng_geometric_pdf,METH_VARARGS, rng_geometric_pdf_doc},
     {"hypergeometric_pdf",rng_hypergeometric_pdf,METH_VARARGS, rng_hypergeometric_pdf_doc},
     {"logarithmic_pdf",rng_logarithmic_pdf,METH_VARARGS, rng_logarithmic_pdf_doc},
     {"landau_pdf",rng_landau_pdf,METH_VARARGS, rng_landau_pdf_doc},
     {"erlang_pdf",rng_erlang_pdf,METH_VARARGS, NULL},
     {"multinomial_pdf",rng_multinomial_pdf,METH_VARARGS,multinomial_pdf_doc},
     {"dirichlet_pdf",rng_dirichlet_pdf,METH_VARARGS, rng_dirichlet_pdf_doc},
     {"multinomial_lnpdf",rng_multinomial_lnpdf,METH_VARARGS, NULL},
     {"dirichlet_lnpdf",rng_dirichlet_lnpdf,METH_VARARGS, rng_dirichlet_lnpdf_doc},
     {"env_setup",PyGSL_rng_env_setup,METH_NOARGS, (char*) rng_env_setup_doc},
     {NULL, NULL, 0}        /* Sentinel */
};

static void
set_api_pointer(void)
{

     FUNC_MESS_BEGIN();
     PyGSL_API[PyGSL_RNG_ObjectType_NUM] = (void *) &PyGSL_rng_pytype;
     DEBUG_MESS(2, "__PyGSL_RNG_API   @ %p,  ", (void *) PyGSL_API);
     DEBUG_MESS(2, "PyGSL_rng_pytype  @ %p,  ", (void *) &PyGSL_rng_pytype);
     /* fprintf(stderr, "__PyGSL_RNG_API @ %p\n", (void *) __PyGSL_RNG_API); */
     FUNC_MESS_END();
}

void
initrng(void)
{
     PyObject *m=NULL, *item=NULL, *dict=NULL;
     PyObject *api=NULL;

     m = Py_InitModule("rng", PyGSL_rng_module_functions);
     assert(m);
     /* import_array(); */
     init_pygsl();

     /* create_rng_types(m); */
     module = m;

     dict = PyModule_GetDict(m);
     if(!dict)
	  goto fail;

     if (!(item = PyString_FromString(rng_module_doc))){
	  PyErr_SetString(PyExc_ImportError,
			  "I could not generate module doc string!");
	  goto fail;
     }
     if (PyDict_SetItemString(dict, "__doc__", item) != 0){
	  PyErr_SetString(PyExc_ImportError,
			  "I could not init doc string!");
	  goto fail;
     }

     PyGSL_rng_pytype.ob_type = &PyType_Type;

     set_api_pointer();
     api = PyCObject_FromVoidPtr((void *) PyGSL_API, NULL);
     assert(api);
     if (PyDict_SetItemString(dict, "_PYGSL_RNG_API", api) != 0){
	  PyErr_SetString(PyExc_ImportError,
			  "I could not add  _PYGSL_RNG_API!");
	  goto fail;
     }

     return;

 fail:
     if(!PyErr_Occurred()){
	  PyErr_SetString(PyExc_ImportError, "I could not init rng module!");
     }

}


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include <map>
#include "DrawableGameComponent.h"
#include "FullScreenRenderTarget.h"
#include "FullScreenQuad.h"
#include "MatrixHelper.h"

namespace Library
{
	class Texture2D;
	class TexturedModelMaterial;
}

namespace Rendering
{
	class DistortionMaskingDemo final : public Library::DrawableGameComponent
	{
	public:
		DistortionMaskingDemo(Library::Game& game, const std::shared_ptr<Library::Camera>& camera);
		DistortionMaskingDemo(const DistortionMaskingDemo&) = delete;
		DistortionMaskingDemo(DistortionMaskingDemo&&) = default;
		DistortionMaskingDemo& operator=(const DistortionMaskingDemo&) = default;
		DistortionMaskingDemo& operator=(DistortionMaskingDemo&&) = default;
		~DistortionMaskingDemo();

		bool DrawCutoutModeEnabled() const;
		void SetDrawCutoutModeEnabled(bool enabled);
		void ToggledDrawCutoutModeEnabled();

		float DisplacementScale() const;
		void SetDisplacementScale(float displacementScale);

		virtual void Initialize() override;
		virtual void Draw(const Library::GameTime& gameTime) override;

	private:
		struct PixelCBufferPerObject
		{
			float DisplacementScale{ 1.0f };
			DirectX::XMFLOAT3 Padding;
		};

		enum class DistortionShaderClass
		{
			Cutout = 0,
			Composite,
			NoDistortion
		};

		inline static const DirectX::XMVECTORF32 CutoutZeroColor{ DirectX::Colors::Black };

		DirectX::XMFLOAT4X4 mWorldMatrix{ Library::MatrixHelper::Identity };
		std::shared_ptr<Library::TexturedModelMaterial> mTexturedModelMaterial;
		Library::FullScreenRenderTarget mSceneRenderTarget;
		Library::FullScreenRenderTarget mCutoutRenderTarget;
		Library::FullScreenQuad mFullScreenQuad;
		winrt::com_ptr<ID3D11Buffer> mPixelCBufferPerObject;
		PixelCBufferPerObject mPixelCBufferPerObjectData;
		std::shared_ptr<Library::Texture2D> mDistortionMap;
		std::map<DistortionShaderClass, winrt::com_ptr<ID3D11ClassInstance>> mShaderClassInstances;
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		bool mDrawCutoutModeEnabled{ false };
		bool mUpdateMaterial{ true };
	};
}


#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/block/gsl_block.h>

#define BASE_DOUBLE
#include <gsl/templates_on.h>
#include <gsl/block/fwrite_source.c>
#include <gsl/block/fprintf_source.c>
#include <gsl/templates_off.h>
#undef BASE_DOUBLE


/*
Copyright (c) 2003-2008 Rudi Cilibrasi, Rulers of the RHouse
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE RULERS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE RULERS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
#include <glib.h>
#include <libintl.h>
#include <locale.h>
#include "complearn/newcomplearn.h"
#include "complearn/clconfig.h"

#define _(O) gettext(O)

#define clStringstackPush(a,v) {void*_u=(void*)v;g_array_append(a,_u);}while(0)

GString *complearn_matrix_prettyprint_text(LabeledMatrix *result) {
  int i, j;
  int html = complearn_ncd_get_html_output(complearn_ncd_top());
  char *rowstart = "", *rowend = "\n", *numstart = "", *numend = "", *labstart = "", *labend = " ", *lastcellstart="", *lastcellend ="";
  GString *toWrite = g_string_new("");
  CompLearnNcd *top = complearn_ncd_top();
  gsl_matrix *goodmat =gsl_matrix_alloc(result->mat->size1, result->mat->size2);
  gsl_matrix_memcpy(goodmat, result->mat);
  if (html) {
    g_string_append(toWrite, "
\n");
      rowstart = "
\n"; rowend = "
\n";
      lastcellstart = ""; lastcellend = "	";
      numstart = ""; numend = "	";
      labstart = ""; labend = "	";
    }
    for (j = 0; j < goodmat->size2; j += 1) {
      g_string_append(toWrite, rowstart);
      if (complearn_ncd_get_show_labels(top)) {
        g_string_append(toWrite, labstart);
        if (result->labels2[j] == NULL)
          g_error("bad labels2 %d with mat size2 %d", j, goodmat->size2);
        g_string_append(toWrite, result->labels2[j]);
        g_string_append(toWrite, labend);
      }
      for (i = 0; i < goodmat->size1; i += 1) {
        char buf[256];
        sprintf(buf, "%f ", gsl_matrix_get(goodmat, i, j));
        g_string_append(toWrite, i == goodmat->size1-1 ? lastcellstart : numstart);
        g_string_append(toWrite, buf);
        g_string_append(toWrite, i == goodmat->size1-1 ? lastcellend : numend);
      }
      g_string_append(toWrite, rowend);
    }
  if (html)
    g_string_append(toWrite, "
\n");
  gsl_matrix_free(goodmat);
  return toWrite;
}

#include <complearn/complearn.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlwriter.h>
#include <libxml/encoding.h>

#define MY_ENCODING "ISO-8859-1"

#include <gsl/gsl_linalg.h>

#define PWD_RDY 1
#define UTS_RDY 1

#ifndef __MINGW32__

#if PWD_RDY
#include <pwd.h>
#endif

#if UTS_RDY
#include <sys/utsname.h>
#endif

#endif

GArray *clDefaultLabels(int i);

static void complearn_handle_string_list(xmlDocPtr doc, xmlNodePtr node, GArray *ss,
                             const char *tagname) {
  node = node->xmlChildrenNode;
  while (node != NULL) {
    if (strcmp(tagname, (char *) node->name) == 0) {
      guchar *v = xmlNodeListGetString(doc, node->xmlChildrenNode,1);
      g_array_append_val(ss, v);
    }
    node = node->next;
  }
}

static void handleDM(xmlDocPtr doc, xmlNodePtr node, GArray *ss,
struct CLDistMatrix *result) {
  result->title = (char *) xmlGetProp(node, (unsigned char *) "title");
  result->creationTime = (char *) xmlGetProp(node, (unsigned char *) "creationtime");
  node = node->xmlChildrenNode;
  GArray *numa, *lab1a, *lab2a;
  numa = result->numa;
  lab1a = result->labels1a;
  lab2a = result->labels2a;
  while (node != NULL) {
    do {
        if (strcmp("entries", (char *) node->name) == 0) {
          complearn_handle_string_list(doc, node, numa, "number");
          continue;
        }
        if (strcmp((char *) node->name, "axis1") == 0) {
          complearn_handle_string_list(doc, node, lab1a, "name");
          continue;
        }
        if (strcmp((char *) node->name, "axis2") == 0) {
          complearn_handle_string_list(doc, node, lab2a, "name");
          continue;
        }
      } while(0);
    node = node->next;
  }
}

static void complearn_write_string_list(xmlTextWriterPtr tw, char **ss, const char *topname, const char *itemname) {
  int rc;
  int i;
  rc = xmlTextWriterStartElement(tw, (unsigned char *) topname);
  for (i = 0; i < complearn_count_strings((const char * const * )ss); i += 1)
    rc = xmlTextWriterWriteElement(tw, (unsigned char *) itemname, (unsigned char *) ss[i]);
  rc = xmlTextWriterEndElement(tw);
}

static char *getTimestrNow(void)
{
  static char buf[32];
  sprintf(buf, "%lu", (unsigned long) time(NULL));
  return buf;
}

static struct CLDistMatrix *fill_in_blanks(struct CLDistMatrix *clb)
{
  if (clb->m == NULL) {
    g_error(_("Cannot write NULL gsl_matrix, exitting."));
  }
  if (clb->m->mat->size1 < 1 || clb->m->mat->size2 < 1) {
    g_error(_("Invalid gsl_matrix size, cannot write.  Exitting."));
  }
  if (clb->fileverstr == NULL)
    clb->fileverstr = g_strdup("1.0");
  if (clb->cllibver == NULL)
    clb->cllibver = g_strdup(complearn_package_version);
  if (clb->username == NULL)
    clb->username = g_strdup(g_get_user_name());
  if (clb->hostname == NULL)
    clb->hostname = g_strdup(complearn_get_hostname());
  if (clb->title == NULL)
    clb->title = g_strdup(_("untitled"));
  if (clb->compressor == NULL)
    clb->compressor = g_strdup(_("unknown"));
  if (clb->creationTime == NULL)
    clb->creationTime = g_strdup(getTimestrNow());
  return clb;
}

struct CLDistMatrix *complearn_clone_cldm(struct CLDistMatrix *clb)
{
  struct CLDistMatrix *r = calloc(sizeof(*r), 1);
  if (clb->m == NULL) {
    g_error(_("Cannot write NULL gsl_matrix, exitting."));
  }
#define DUPSTR(s) if (clb->s) r->s = g_strdup(clb->s)
  DUPSTR(cllibver);
  DUPSTR(username);
  DUPSTR(hostname);
  DUPSTR(title);
  DUPSTR(compressor);
  DUPSTR(creationTime);
  r->m = calloc(sizeof(*(r->m)), 1);
  r->m->mat = gsl_matrix_alloc(clb->m->mat->size1, clb->m->mat->size2);
  gsl_matrix_memcpy(r->m->mat, clb->m->mat);
  r->m->labels1 = complearn_dupe_strings((const char * const *)clb->m->labels1);
  r->m->labels2 = complearn_dupe_strings((const char * const *)clb->m->labels2);
  r->cmds = complearn_dupe_strings((const char * const *)clb->cmds);
  r->cmdtimes = complearn_dupe_strings((const char * const *)clb->cmdtimes);
  return r;
}

void complearn_free_cldm(struct CLDistMatrix *clb)
{
  if (clb->cllibver) g_free(clb->cllibver);
  if (clb->username) g_free(clb->username);
  if (clb->hostname) g_free(clb->hostname);
  if (clb->title) g_free(clb->title);
  if (clb->compressor) g_free(clb->compressor);
  if (clb->creationTime) g_free(clb->creationTime);
  if (clb->m->mat) gsl_matrix_free(clb->m->mat);
  g_strfreev(clb->m->labels1);
  g_strfreev(clb->m->labels2);
  g_strfreev(clb->cmdtimes);
  g_strfreev(clb->cmds);
  g_free(clb->m);
  memset(clb, 0, sizeof(*clb));
  g_free(clb);
}

static char *clXMLQuoteStr(char *inp)
{
  int i, c, j;
  static char *outstr;
  if (outstr != NULL)
    g_free(outstr);
  outstr = calloc(strlen(inp) * 10, 1);
  j = 0;
  for (i = 0; inp[i]; i += 1) {
    c = inp[i];
    switch(c) {
      case '&':
        outstr[j++] = '&'; outstr[j++] = 'a'; outstr[j++] = 'm';
        outstr[j++] = 'p'; outstr[j++] = ';'; break;
      case '>':
        outstr[j++] = '&'; outstr[j++] = 'g'; outstr[j++] = 't';
        outstr[j++] = ';'; break;
      case '<':
        outstr[j++] = '&'; outstr[j++] = 'l'; outstr[j++] = 't';
        outstr[j++] = ';'; break;
      case '"':
        outstr[j++] = '&'; outstr[j++] = 'q'; outstr[j++] = 'o';
        outstr[j++] = 'o'; outstr[j++] = 't'; outstr[j++] = ';'; break;
      case '\'':
        outstr[j++] = '&'; outstr[j++] = 'a'; outstr[j++] = 'p';
        outstr[j++] = 'o'; outstr[j++] = 's'; outstr[j++] = ';'; break;
//      case '\\':
 //     case '#':
//        outstr[j++] = '\\'; outstr[j++] = c; break;
      default:
        outstr[j++] = c;
    }
  }
  outstr[j++] = 0;
  return outstr;
}

static GString *clRealWriteCLBDistMatrix(struct CLDistMatrix *clb)
{
  int rc;
  GString *result, *cres;
  int dim1, dim2, i, j;
  gsl_matrix *m = clb->m->mat;
  xmlBufferPtr b;
  xmlTextWriterPtr tw;
  clb = fill_in_blanks(complearn_clone_cldm(clb));
  b = xmlBufferCreate();
  tw =xmlNewTextWriterMemory(b, 0);
  rc = xmlTextWriterStartDocument(tw, NULL, MY_ENCODING, NULL);
  rc = xmlTextWriterStartElement(tw, (unsigned char *) "clb");
  rc = xmlTextWriterWriteAttribute(tw, (unsigned char *) "version", (unsigned char *) clb->fileverstr);

    rc = xmlTextWriterWriteElement(tw, (unsigned char *) "cllibver", (unsigned char *) clb->cllibver);
    rc = xmlTextWriterWriteElement(tw, (unsigned char *) "username", (unsigned char *) clb->username);
    rc = xmlTextWriterWriteElement(tw, (unsigned char *) "hostname", (unsigned char *) clb->hostname);
    rc = xmlTextWriterWriteElement(tw, (unsigned char *) "compressor", (unsigned char *) clb->compressor);
    rc = xmlTextWriterStartElement(tw,(unsigned char *)  "distmatrix");
    rc = xmlTextWriterWriteAttribute(tw,(unsigned char *)  "creationtime", (unsigned char *) clb->creationTime);
    rc = xmlTextWriterWriteAttribute(tw, (unsigned char *) "title",(unsigned char *)  clb->title);
    complearn_write_string_list(tw, clb->m->labels1,  "axis1",  "name");
    complearn_write_string_list(tw, clb->m->labels2,  "axis2",  "name");
    dim1 = complearn_count_strings((const char * const *) clb->m->labels1);
    dim2 = complearn_count_strings((const char * const *) clb->m->labels2);
      rc = xmlTextWriterStartElement(tw,(unsigned char *)  "entries");
      for (i = 0; i < dim1; i += 1) {
        for (j = 0; j < dim2; j += 1) {
          double g = gsl_matrix_get(m, i, j);
            xmlTextWriterWriteFormatElement(tw, (unsigned char *) "number", (char *) "%f", g);
        }
      }
      rc = xmlTextWriterEndElement(tw);
    rc = xmlTextWriterEndElement(tw);
    if (clb->cmds) {
      char *str;
      rc = xmlTextWriterStartElement(tw,(unsigned char *)  "commands");
      for (i = 0; i < complearn_count_strings((const char * const *) clb->cmds); i += 1) {
        char *t = clb->cmdtimes ? (clb->cmdtimes[i]) : NULL;
        rc = xmlTextWriterStartElement(tw,(unsigned char *)  "cmdstring");
        if (t)
          rc = xmlTextWriterWriteAttribute(tw,(unsigned char *)  "creationtime", (unsigned char *) t);
        str = clb->cmds[i];
        xmlTextWriterWriteRaw(tw, (unsigned char *)  clXMLQuoteStr(str));
        rc = xmlTextWriterEndElement(tw);
      }
      rc = xmlTextWriterEndElement(tw);
    }
  rc = xmlTextWriterEndElement(tw);
  rc = xmlTextWriterEndDocument(tw);
  xmlFreeTextWriter(tw);
  result = g_string_new((char *) b->content);
  xmlBufferFree(b);
  /* TODO: remove more mem leaks from above func */
  complearn_free_cldm(clb);
  CompLearnRealCompressor *bz = COMPLEARN_REAL_COMPRESSOR(complearn_environment_get_nameable("bzlib"));
  if (bz == NULL)
    g_error(_("Cannot load bzlib"));
  cres = real_compressor_compress(bz, result);
  g_string_free(result, TRUE);
  return cres;
}

gsl_matrix *complearn_clb_dist_matrix(const GString *db)
{
  return complearn_read_clb_dist_matrix(db)->m->mat;
}

struct CLDistMatrix *complearn_read_clb_dist_matrix(const GString *udb)
{
  struct CLDistMatrix *result = calloc(sizeof(struct CLDistMatrix), 1);
  GArray *ents = g_array_new(FALSE, TRUE, sizeof(gpointer));
  GString *db;
  int dim1, dim2;
  xmlDocPtr doc;
  xmlNodePtr node;
  CompLearnRealCompressor *bz = COMPLEARN_REAL_COMPRESSOR(complearn_environment_get_nameable("bzlib"));
  if (bz == NULL)
    g_error(_("Cannot load bzlib compressor."));
  if (real_compressor_is_decompressible(bz, udb))
    db = real_compressor_decompress(bz, udb);
  else
    db = g_string_new_len(udb->str, udb->len);
  if (db == NULL || db->len < 1)
    return NULL;
  if (db->str[0] != '<')
    return NULL;
  result->fileverstr = "";
  result->username = "";
  result->title = "";
  result->creationTime = "";
  result->cmdsa = g_array_new(FALSE, TRUE, sizeof(gpointer));
  result->cmdtimesa = g_array_new(FALSE, TRUE, sizeof(gpointer));
  result->labels1a = g_array_new(FALSE, TRUE, sizeof(gpointer));
  result->labels2a = g_array_new(FALSE, TRUE, sizeof(gpointer));
  result->numa = g_array_new(FALSE, TRUE, sizeof(gpointer));
  result->m = calloc(sizeof(*result->m), 1);
  doc = xmlReadMemory((char *)db->str, db->len, "noname.xml",
                      NULL, 0);
  if (doc == NULL) {
    g_error(_("Failed to parse document."));
    g_string_free(db, TRUE);
    free(result);
    return NULL;
  }
  node = doc->children;
  if (strcmp((char *) node->name, "clb") != 0) {
    free(result);
    g_string_free(db, TRUE);
    return NULL;
  }
  result->fileverstr = (char *) xmlGetProp(node, (unsigned char *) "version");
  node = node->xmlChildrenNode;
 while (node != NULL) {
    do {
      if (strcmp((char *) node->name, "commands") == 0) {
        complearn_handle_string_list(doc, node, result->cmdsa, "cmdstring");
        continue;
      }
      if (strcmp((char *) node->name, "distmatrix") == 0) {
        handleDM(doc, node, ents, result);
  result->m->mat = gsl_matrix_alloc(result->labels1a->len, result->labels2a->len);
  int i, x=0, y=0;
  for (i = 0; i < result->numa->len; i += 1) {
    gsl_matrix_set(result->m->mat,x,y,atof(g_array_index(result->numa, char *, i)));
    g_assert(y < result->m->mat->size2);
    x += 1;
    if (x == result->m->mat->size1) {
      x = 0; y += 1;
    }
  }
        continue;
      }
      if (strcmp((char *) node->name, "cllibver") == 0) {
        result->cllibver = (char *) g_strdup((char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
        continue;
      }
      if (strcmp((char *) node->name, "compressor") == 0) {
        result->compressor = (char *) g_strdup((char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
        continue;
      }
      if (strcmp((char *) node->name, "username") == 0) {
        result->username = (char *) g_strdup((char *) xmlNodeListGetString(doc, node->xmlChildrenNode, 1));
        continue;
      }
    } while (0);
    node = node->next;
    }

  dim1 = result->labels1a->len;
  if (dim1 <= 0) {
    g_error(_("Error, no labels for dimension 1."));
    exit(1);
  }
  dim2 = result->labels2a->len;
  if (dim2 <= 0) {
    g_error(_("Error, no labels for dimension 2."));
    exit(1);
  }
  g_array_free(ents, TRUE);
  g_string_free(db, TRUE);
  result->m->labels1 = calloc(result->labels1a->len+1, sizeof(gpointer));
  result->m->labels2 = calloc(result->labels2a->len+1, sizeof(gpointer));
  memcpy(result->m->labels1, result->labels1a->data, sizeof(gpointer)*(result->labels1a->len));
  memcpy(result->m->labels2, result->labels2a->data, sizeof(gpointer)*(result->labels2a->len));
  return result;
}

const char *complearn_complearn_get_hostname(void)
{
  static char hostname[1024];
#ifdef __MINGW32__
	strcpy(hostname, "localhost");
#else
  gethostname(hostname, 1024);
#endif
  return hostname;
}

const char *complearn_get_uts_name(void)
{
  static char utsname[1024];
#if UTS_RDY
#ifdef __MINGW32__
	strcpy(utsname, "mingw32");
#else
  struct utsname uts;
  uname(&uts);
  sprintf(utsname, "[%s (%s), %s]", uts.sysname, uts.release, uts.machine);
#endif
#else
  strcpy(utsname, "[unknown]");
#endif
  return utsname;
}

GString *complearn_matrix_prettyprint_clb(LabeledMatrix *dm) {
  struct CLDistMatrix inp;
  memset(&inp, 0, sizeof(inp));
  inp.m = dm;
  char *old_locale = setlocale(LC_NUMERIC, NULL);
  setlocale(LC_NUMERIC, "C");
  GString *result = clRealWriteCLBDistMatrix(&inp);
  setlocale(LC_NUMERIC, old_locale);
  return result;
}

LabeledMatrix *complearn_load_any_matrix(const GString *inp)
{
  complearn_environment_top();
  if (complearn_is_nexus_file(inp))
    return complearn_load_nexus_matrix(inp);
  struct CLDistMatrix *cld;
  cld = complearn_read_clb_dist_matrix(inp);
  if (cld) {
    return cld->m;
  }
  if (complearn_is_text_matrix(inp)) {
    return complearn_load_text_matrix(inp);
  }
  return NULL;
}


/****************************************************************************
 *                                                                          *
 *  Author : lukasz.iwaszkiewicz@gmail.com                                  *
 *  ~~~~~~~~                                                                *
 *  License : see COPYING file for details.                                 *
 *  ~~~~~~~~~                                                               *
 ****************************************************************************/

#pragma once

/**
 * This file is for maintaining compatibility with systems where C++ standard library is
 * not available i.e. for Arduino. I was totally unaware, that there is no C++ standard
 * library implemented for this toy platform.
 */

#if defined(__GNUC__) && (defined(AVR) || defined(ARDUINO) || defined (ARDUINO_ARCH_AVR))
#include <assert.h>
#include <stddef.h>
#include <stdint.h>

#include <etl/array.h>
#include <etl/map.h>
#include <etl/optional.h>

#if !defined Expects
#define Expects(x) assert (x)
#endif

namespace gsl {

template <class T, std::size_t N> constexpr T &at (T (&arr)[N], const int i)
{
        Expects (i >= 0 && i < static_cast<int> (N));
        return arr[static_cast<size_t> (i)];
}

template <class Cont> constexpr auto at (Cont &cont, const int i) -> decltype (cont[cont.size ()])
{
        Expects (i >= 0 && i < static_cast<int> (cont.size ()));
        using size_type = decltype (cont.size ());
        return cont[static_cast<size_type> (i)];
}
} // namespace gsl

namespace std {
template <typename _Tp, typename _Up = _Tp &&> _Up __declval (int);

template <typename _Tp> _Tp __declval (long);

template <typename _Tp> auto declval () noexcept -> decltype (__declval<_Tp> (0));

template <typename _Tp> struct __declval_protector {
        static const bool __stop = false;
};

template <typename _Tp> auto declval () noexcept -> decltype (__declval<_Tp> (0))
{
        static_assert (__declval_protector<_Tp>::__stop, "declval() must not be used!");
        return __declval<_Tp> (0);
}
} // namespace std
#else
#include <cstdint>
#include <gsl/gsl>
#endif

#include <etl/map.h>
#include <etl/optional.h>


/* matrix/gsl_matrix_complex_long_double.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__
#define __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__

#if !defined( GSL_FUN )
#  if !defined( GSL_DLL )
#    define GSL_FUN extern
#  elif defined( BUILD_GSL_DLL )
#    define GSL_FUN extern __declspec(dllexport)
#  else
#    define GSL_FUN extern __declspec(dllimport)
#  endif
#endif

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_complex_long_double.h>

#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* empty */
# define __END_DECLS /* empty */
#endif

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  long double * data;
  gsl_block_complex_long_double * block;
  int owner;
} gsl_matrix_complex_long_double ;

typedef struct
{
  gsl_matrix_complex_long_double matrix;
} _gsl_matrix_complex_long_double_view;

typedef _gsl_matrix_complex_long_double_view gsl_matrix_complex_long_double_view;

typedef struct
{
  gsl_matrix_complex_long_double matrix;
} _gsl_matrix_complex_long_double_const_view;

typedef const _gsl_matrix_complex_long_double_const_view gsl_matrix_complex_long_double_const_view;

/* Allocation */

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc_from_block (gsl_block_complex_long_double * b,
                                           const size_t offset,
                                           const size_t n1, const size_t n2, const size_t d2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc_from_matrix (gsl_matrix_complex_long_double * b,
                                            const size_t k1, const size_t k2,
                                            const size_t n1, const size_t n2);

GSL_FUN gsl_vector_complex_long_double *
gsl_vector_complex_long_double_alloc_row_from_matrix (gsl_matrix_complex_long_double * m,
                                                const size_t i);

GSL_FUN gsl_vector_complex_long_double *
gsl_vector_complex_long_double_alloc_col_from_matrix (gsl_matrix_complex_long_double * m,
                                                const size_t j);

GSL_FUN void gsl_matrix_complex_long_double_free (gsl_matrix_complex_long_double * m);

/* Views */

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_submatrix (gsl_matrix_complex_long_double * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_row (gsl_matrix_complex_long_double * m, const size_t i);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_column (gsl_matrix_complex_long_double * m, const size_t j);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_diagonal (gsl_matrix_complex_long_double * m);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subdiagonal (gsl_matrix_complex_long_double * m, const size_t k);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_superdiagonal (gsl_matrix_complex_long_double * m, const size_t k);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subrow (gsl_matrix_complex_long_double * m,
                                 const size_t i, const size_t offset,
                                 const size_t n);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subcolumn (gsl_matrix_complex_long_double * m,
                                    const size_t j, const size_t offset,
                                    const size_t n);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_array (long double * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_array_with_tda (long double * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_vector (gsl_vector_complex_long_double * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_vector_with_tda (gsl_vector_complex_long_double * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_submatrix (const gsl_matrix_complex_long_double * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_row (const gsl_matrix_complex_long_double * m,
                            const size_t i);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_column (const gsl_matrix_complex_long_double * m,
                               const size_t j);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_diagonal (const gsl_matrix_complex_long_double * m);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subdiagonal (const gsl_matrix_complex_long_double * m,
                                    const size_t k);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_superdiagonal (const gsl_matrix_complex_long_double * m,
                                      const size_t k);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subrow (const gsl_matrix_complex_long_double * m,
                                       const size_t i, const size_t offset,
                                       const size_t n);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subcolumn (const gsl_matrix_complex_long_double * m,
                                          const size_t j, const size_t offset,
                                          const size_t n);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_array (const long double * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_array_with_tda (const long double * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_vector (const gsl_vector_complex_long_double * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_vector_with_tda (const gsl_vector_complex_long_double * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_complex_long_double_set_zero (gsl_matrix_complex_long_double * m);
GSL_FUN void gsl_matrix_complex_long_double_set_identity (gsl_matrix_complex_long_double * m);
GSL_FUN void gsl_matrix_complex_long_double_set_all (gsl_matrix_complex_long_double * m, gsl_complex_long_double x);

GSL_FUN int gsl_matrix_complex_long_double_fread (FILE * stream, gsl_matrix_complex_long_double * m) ;
GSL_FUN int gsl_matrix_complex_long_double_fwrite (FILE * stream, const gsl_matrix_complex_long_double * m) ;
GSL_FUN int gsl_matrix_complex_long_double_fscanf (FILE * stream, gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_fprintf (FILE * stream, const gsl_matrix_complex_long_double * m, const char * format);

GSL_FUN int gsl_matrix_complex_long_double_memcpy(gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);
GSL_FUN int gsl_matrix_complex_long_double_swap(gsl_matrix_complex_long_double * m1, gsl_matrix_complex_long_double * m2);

GSL_FUN int gsl_matrix_complex_long_double_swap_rows(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_swap_columns(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_swap_rowcol(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);

GSL_FUN int gsl_matrix_complex_long_double_transpose (gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_transpose_memcpy (gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);

GSL_FUN int gsl_matrix_complex_long_double_isnull (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_ispos (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_isneg (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_isnonneg (const gsl_matrix_complex_long_double * m);

GSL_FUN int gsl_matrix_complex_long_double_add (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_sub (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_mul_elements (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_div_elements (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_scale (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);
GSL_FUN int gsl_matrix_complex_long_double_add_constant (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);
GSL_FUN int gsl_matrix_complex_long_double_add_diagonal (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_complex_long_double_get_row(gsl_vector_complex_long_double * v, const gsl_matrix_complex_long_double * m, const size_t i);
GSL_FUN int gsl_matrix_complex_long_double_get_col(gsl_vector_complex_long_double * v, const gsl_matrix_complex_long_double * m, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_set_row(gsl_matrix_complex_long_double * m, const size_t i, const gsl_vector_complex_long_double * v);
GSL_FUN int gsl_matrix_complex_long_double_set_col(gsl_matrix_complex_long_double * m, const size_t j, const gsl_vector_complex_long_double * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL gsl_complex_long_double gsl_matrix_complex_long_double_get(const gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void gsl_matrix_complex_long_double_set(gsl_matrix_complex_long_double * m, const size_t i, const size_t j, const gsl_complex_long_double x);

GSL_FUN INLINE_DECL gsl_complex_long_double * gsl_matrix_complex_long_double_ptr(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const gsl_complex_long_double * gsl_matrix_complex_long_double_const_ptr(const gsl_matrix_complex_long_double * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE

INLINE_FUN
gsl_complex_long_double
gsl_matrix_complex_long_double_get(const gsl_matrix_complex_long_double * m,
                     const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      gsl_complex_long_double zero = {{0,0}};

      if (i >= m->size1)
        {
          GSL_ERROR_VAL("first index out of range", GSL_EINVAL, zero) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VAL("second index out of range", GSL_EINVAL, zero) ;
        }
    }
#endif
  return *(gsl_complex_long_double *)(m->data + 2*(i * m->tda + j)) ;
}

INLINE_FUN
void
gsl_matrix_complex_long_double_set(gsl_matrix_complex_long_double * m,
                     const size_t i, const size_t j, const gsl_complex_long_double x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  *(gsl_complex_long_double *)(m->data + 2*(i * m->tda + j)) = x ;
}

INLINE_FUN
gsl_complex_long_double *
gsl_matrix_complex_long_double_ptr(gsl_matrix_complex_long_double * m,
                             const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (gsl_complex_long_double *)(m->data + 2*(i * m->tda + j)) ;
}

INLINE_FUN
const gsl_complex_long_double *
gsl_matrix_complex_long_double_const_ptr(const gsl_matrix_complex_long_double * m,
                                   const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      if (i >= m->size1)
        {
          GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
        }
    }
#endif
  return (const gsl_complex_long_double *)(m->data + 2*(i * m->tda + j)) ;
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__ */


#include <config.h>
#include <stddef.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <stdio.h>

#include <gsl/gsl_errno.h>
#include <gsl/gsl_complex.h>

#include <gsl/gsl_fft_complex.h>

#define BASE_DOUBLE
#include "templates_on.h"
#include "compare_source.c"
#include "templates_off.h"
#undef  BASE_DOUBLE

#define BASE_FLOAT
#include "templates_on.h"
#include "compare_source.c"
#include "templates_off.h"
#undef  BASE_FLOAT


/* rng/types.c
 *
 * Copyright (C) 2001, 2007 Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_rng.h>

#define N 100

const gsl_rng_type * gsl_rng_generator_types[N];

#define ADD(t) {if (i==N) abort(); gsl_rng_generator_types[i] = (t); i++; };

const gsl_rng_type **
gsl_rng_types_setup (void)
{
  int i = 0;

  ADD(gsl_rng_borosh13);
  ADD(gsl_rng_cmrg);
  ADD(gsl_rng_coveyou);
  ADD(gsl_rng_fishman18);
  ADD(gsl_rng_fishman20);
  ADD(gsl_rng_fishman2x);
  ADD(gsl_rng_gfsr4);
  ADD(gsl_rng_knuthran);
  ADD(gsl_rng_knuthran2);
  ADD(gsl_rng_knuthran2002);
  ADD(gsl_rng_lecuyer21);
  ADD(gsl_rng_minstd);
  ADD(gsl_rng_mrg);
  ADD(gsl_rng_mt19937);
  ADD(gsl_rng_mt19937_1999);
  ADD(gsl_rng_mt19937_1998);
  ADD(gsl_rng_r250);
  ADD(gsl_rng_ran0);
  ADD(gsl_rng_ran1);
  ADD(gsl_rng_ran2);
  ADD(gsl_rng_ran3);
  ADD(gsl_rng_rand);
  ADD(gsl_rng_rand48);
  ADD(gsl_rng_random128_bsd);
  ADD(gsl_rng_random128_glibc2);
  ADD(gsl_rng_random128_libc5);
  ADD(gsl_rng_random256_bsd);
  ADD(gsl_rng_random256_glibc2);
  ADD(gsl_rng_random256_libc5);
  ADD(gsl_rng_random32_bsd);
  ADD(gsl_rng_random32_glibc2);
  ADD(gsl_rng_random32_libc5);
  ADD(gsl_rng_random64_bsd);
  ADD(gsl_rng_random64_glibc2);
  ADD(gsl_rng_random64_libc5);
  ADD(gsl_rng_random8_bsd);
  ADD(gsl_rng_random8_glibc2);
  ADD(gsl_rng_random8_libc5);
  ADD(gsl_rng_random_bsd);
  ADD(gsl_rng_random_glibc2);
  ADD(gsl_rng_random_libc5);
  ADD(gsl_rng_randu);
  ADD(gsl_rng_ranf);
  ADD(gsl_rng_ranlux);
  ADD(gsl_rng_ranlux389);
  ADD(gsl_rng_ranlxd1);
  ADD(gsl_rng_ranlxd2);
  ADD(gsl_rng_ranlxs0);
  ADD(gsl_rng_ranlxs1);
  ADD(gsl_rng_ranlxs2);
  ADD(gsl_rng_ranmar);
  ADD(gsl_rng_slatec);
  ADD(gsl_rng_taus);
  ADD(gsl_rng_taus2);
  ADD(gsl_rng_taus113);
  ADD(gsl_rng_transputer);
  ADD(gsl_rng_tt800);
  ADD(gsl_rng_uni);
  ADD(gsl_rng_uni32);
  ADD(gsl_rng_vax);
  ADD(gsl_rng_waterman14);
  ADD(gsl_rng_zuf);
  ADD(0);

  return gsl_rng_generator_types;
}


#pragma once

#include <iosfwd>
#include <map>
#include <memory>
#include <vector>

#include <gsl/gsl>

namespace sframe {

struct openssl_error : std::runtime_error
{
  openssl_error();
};

struct unsupported_ciphersuite_error : std::runtime_error
{
  unsupported_ciphersuite_error();
};

struct authentication_error : std::runtime_error
{
  authentication_error();
};

struct buffer_too_small_error : std::runtime_error
{
  using parent = std::runtime_error;
  using parent::parent;
};

struct invalid_parameter_error : std::runtime_error
{
  using parent = std::runtime_error;
  using parent::parent;
};

enum class CipherSuite : uint16_t
{
  AES_CM_128_HMAC_SHA256_4 = 1,
  AES_CM_128_HMAC_SHA256_8 = 2,
  AES_GCM_128_SHA256 = 3,
  AES_GCM_256_SHA512 = 4,
};

constexpr size_t max_overhead = 17 + 16;

using bytes = std::vector<uint8_t>;
using input_bytes = gsl::span<const uint8_t>;
using output_bytes = gsl::span<uint8_t>;

std::ostream&
operator<<(std::ostream& str, const input_bytes data);

using KeyID = uint64_t;
using Counter = uint64_t;

class SFrame
{
protected:
  CipherSuite suite;

  SFrame(CipherSuite suite_in);
  virtual ~SFrame();

  struct KeyState
  {
    static KeyState from_base_key(CipherSuite suite, const bytes& base_key);

    bytes key;
    bytes salt;
    Counter counter;
  };

  output_bytes _protect(KeyID key_id,
                        output_bytes ciphertext,
                        input_bytes plaintext);
  output_bytes _unprotect(output_bytes ciphertext, input_bytes plaintext);

  virtual KeyState& get_state(KeyID key_id) = 0;
};

class Context : public SFrame
{
public:
  Context(CipherSuite suite);

  void add_key(KeyID kid, const bytes& key);

  output_bytes protect(KeyID key_id,
                       output_bytes ciphertext,
                       input_bytes plaintext);
  output_bytes unprotect(output_bytes plaintext, input_bytes ciphertext);

private:
  std::map<KeyID, KeyState> state;

  KeyState& get_state(KeyID key_id) override;
};

class MLSContext : public SFrame
{
public:
  using EpochID = uint64_t;
  using SenderID = uint32_t;

  MLSContext(CipherSuite suite_in, size_t epoch_bits_in);

  void add_epoch(EpochID epoch_id, const bytes& sframe_epoch_secret);
  void purge_before(EpochID keeper);

  output_bytes protect(EpochID epoch_id,
                       SenderID sender_id,
                       output_bytes ciphertext,
                       input_bytes plaintext);
  output_bytes unprotect(output_bytes plaintext, input_bytes ciphertext);

private:
  const size_t epoch_bits;
  const size_t epoch_mask;

  struct EpochKeys
  {
    const EpochID full_epoch;
    const bytes sframe_epoch_secret;
    std::map<SenderID, KeyState> sender_keys;

    EpochKeys(EpochID full_epoch_in, bytes sframe_epoch_secret_in);
    KeyState& get(CipherSuite suite, SenderID sender_id);
  };

  std::vector<std::unique_ptr<EpochKeys>> epoch_cache;
  KeyState& get_state(KeyID key_id) override;
};

} // namespace sframe


/* Author: G. Jungman
 */
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_errno.h>
#include "gsl_qrng.h"

gsl_qrng *
gsl_qrng_alloc (const gsl_qrng_type * T, unsigned int dimension)
{

  gsl_qrng * r = (gsl_qrng *) malloc (sizeof (gsl_qrng));

  if (r == 0)
    {
      GSL_ERROR_VAL ("allocation failed for qrng struct",
			GSL_ENOMEM, 0);
    };

  r->dimension = dimension;
  r->state_size = T->state_size(dimension);
  r->state = malloc (r->state_size);

  if (r->state == 0)
    {
      free (r);
      GSL_ERROR_VAL ("allocation failed for qrng state",
			GSL_ENOMEM, 0);
    };

  r->type = T;

  T->init_state(r->state, r->dimension);

  return r;
}

int
gsl_qrng_memcpy (gsl_qrng * dest, const gsl_qrng * src)
{
  if (dest->type != src->type)
    {
      GSL_ERROR ("generators must be of the same type", GSL_EINVAL);
    }

  dest->dimension = src->dimension;
  dest->state_size = src->state_size;
  memcpy (dest->state, src->state, src->state_size);

  return GSL_SUCCESS;
}

gsl_qrng *
gsl_qrng_clone (const gsl_qrng * q)
{
  gsl_qrng * r = (gsl_qrng *) malloc (sizeof (gsl_qrng));

  if (r == 0)
    {
      GSL_ERROR_VAL ("failed to allocate space for rng struct",
			GSL_ENOMEM, 0);
    };

  r->dimension = q->dimension;
  r->state_size = q->state_size;
  r->state = malloc (r->state_size);

  if (r->state == 0)
    {
      free (r);
      GSL_ERROR_VAL ("failed to allocate space for rng state",
			GSL_ENOMEM, 0);
    };

  r->type = q->type;

  memcpy (r->state, q->state, q->state_size);

  return r;
}

#ifndef HIDE_INLINE_STATIC
int
gsl_qrng_get (const gsl_qrng * r, double x[])
{
  return (r->type->get) (r->state, r->dimension, x);
}
#endif

const char *
gsl_qrng_name (const gsl_qrng * r)
{
  return r->type->name;
}

size_t
gsl_qrng_size (const gsl_qrng * r)
{
  return r->state_size;
}

void *
gsl_qrng_state (const gsl_qrng * r)
{
  return r->state;
}

void
gsl_qrng_free (gsl_qrng * r)
{
  if(r != 0) {
    if(r->state != 0) free (r->state);
    free (r);
  }
}


//Include guard
#ifndef SEQUENCE_H
#define SEQUENCE_H

//Forward declared dependencies

//Included dependencies
#include <vector>
#include <string>
#include <gsl/gsl_rng.h>

class Sequence{
private:
    //Internal variables
    std::vector<char> seq;

public:
    Sequence();
    Sequence(int length);
    Sequence(std::vector<char>& s);
    Sequence(std::string s);
    ~Sequence();

    void setSeq(std::vector<char>& s);
	std::string getSeqAsString();
    void setBase(int index, char b);
    void addBase(char b);
	void removeBase(int index);
    char getBase(int index);
    int getLength();
    void print();
    std::string printToString();
    std::string printToStringNoHyphens();
    Sequence subset(int start, int finish);
    void addBaseFront(char b);
};

#endif