#ifndef STK_Matrix_h
#define STK_Matrix_h

#include "common.h"
#include "Error.h"
#include "BasicVector.h"

#include <stddef.h>
#include <stdlib.h>
#include <stdexcept>
#include <iostream>

#ifdef HAVE_ATLAS
extern "C"{
  #ifdef USE_MKL
    #include "mkl.h"
  #else
    #include <cblas.h>
    #include <atlas/clapack.h>
  #endif
}
#endif

//#define TRACE_MATRIX_OPERATIONS
#define CHECKSIZE

namespace STK
{

  //  class matrix_error : public std::logic_error {};/
  //  class matrix_sizes_error : public matrix_error {};

  /// defines a storage type
  typedef enum
  {
    STORAGE_UNDEFINED = 0,
    STORAGE_REGULAR,
    STORAGE_TRANSPOSED
  } StorageType;

  // declare the class so the header knows about it
  template<typename _ElemT> class Matrix;
  template<typename _ElemT> class MatrixRange;

  // we need to declare the friend << operator here
  template<typename _ElemT>
    std::ostream & operator << (std::ostream & out, Matrix<_ElemT> & m);

  /** **************************************************************************
   ** **************************************************************************
   *  @brief Provides a matrix class
   *
   *  This class provides a way to work with matrices in STK.
   *  It encapsulates basic operations and memory optimizations.
   *
   */
  template<typename _ElemT>
    class Matrix
    {
    public:
      // HTK parameter file header (see HTK manual)
      typedef struct
      {
        int   nSamples;
        int   sampPeriod;
        short sampSize;
        short paramKind;
      } HtkHeader;

      /// defines a type of this
      typedef Matrix<_ElemT>    ThisType;

      // Constructors

      /// Empty constructor
      Matrix<_ElemT> ():
        mMRows(0), mMCols(0), mStride(0), mpData(NULL)
#ifdef STK_MEMALIGN_MANUAL
        , mpFreeData(NULL)
#endif
      {}

      /// Copy constructor
      Matrix<_ElemT> (const ThisType & t);

      /// Basic constructor
      Matrix<_ElemT> (const size_t r,
                      const size_t c);

      /// Destructor
      virtual
      ~Matrix<_ElemT> ();

      /// Initializes matrix (if not done by constructor)
      void
      Init(const size_t r,
           const size_t c);

      /**
       * @brief Dealocates the matrix from memory and resets the dimensions to (0, 0)
       */
      void
      Destroy();

      /**
       * @brief Returns @c true if matrix is initialized
       */
      const bool
      IsInitialized() const
      { return mpData != NULL; }

      /// Returns number of rows in the matrix
      const size_t
      Rows() const
      {
        return mMRows;
      }

      /// Returns number of columns in the matrix
      const size_t
      Cols() const
      {
        return mMCols;
      }

      /// Returns number of columns in the matrix memory
      const size_t
      Stride() const
      {
        return mStride;
      }

      /**
       *  @brief Gives access to a specified matrix row without range check
       *  @return Pointer to the const array
       */
      const _ElemT*
      cpData () const
      {
        return mpData;
      }

      /**
       *  @brief Gives access to a specified matrix row without range check
       *  @return Pointer to the non-const data array
       */
      _ElemT* __attribute__((aligned(16)))
      pData () const
      {
        return mpData;
      }

      /// Returns size of matrix in memory
      const size_t
      MSize() const
      {
        return mMRows * mStride * sizeof(_ElemT);
      }

      bool
      LoadHTK(const char* pFileName);

      //########################################################################
      //########################################################################
      // Math stuff
      /**
       * @brief Performs diagonal scaling
       * @param pDiagVector Array representing matrix diagonal
       * @return Refference to this
       */
      ThisType&
      DiagScale(const _ElemT* pDiagVector);

      ThisType&
      DiagScale(const BasicVector<_ElemT>& rDiagVector);

      /**
       *  @brief Performs vector multiplication on a and b and and adds the
       *         result to this (elem by elem)
       */
      ThisType &
      AddCMtMMul(const _ElemT& c, const ThisType& a, const ThisType& b);

      ThisType &
      AddMMMul(const ThisType& a, const ThisType& b);

      ThisType &
      AddMMtMul(const ThisType& a, const ThisType& b);

      ThisType &
      AddCMMtMul(const _ElemT& c, const ThisType& a, const ThisType& b);

      ThisType &
      AddCMMul(const _ElemT& c, const ThisType& a);

      ThisType &
      RepMMSub(const ThisType& a, const ThisType& b);

      ThisType &
      RepMMMul(const ThisType& a, const ThisType& b);

      ThisType &
      RepMtMMul(const ThisType& a, const ThisType& b);

      ThisType &
      AddCVVtMul(const _ElemT& c, const BasicVector<_ElemT>& rA,
                 const BasicVector<_ElemT>& rB);

      ThisType &
      AddCVVtMul(const _ElemT& c, const _ElemT* pA, const _ElemT* pB);

      ThisType &
      AddCVVt(const _ElemT& c, const BasicVector<_ElemT>& rA, const _ElemT* pB);

      ThisType &
      DivC(const _ElemT& c);

      //########################################################################
      //########################################################################

      ThisType &
      DotMul(const ThisType& a);

      ThisType&
      NormalizeRows();

      /**
       *  @brief Returns sum of all elements
       */
      const _ElemT&
      Sum() const;

      /**
       *  @brief Performs log on all elements
       *         result to this (elem by elem)
       */
      ThisType&
      Log();

      /**
       *  @brief Performs fast sigmoid on row vectors
       *         result to this (elem by elem)
       */
      ThisType &
      FastRowSigmoid();

      /**
       *  @brief Performs fast softmax on row vectors
       *         result to this (elem by elem)
       */
      ThisType &
      FastRowSoftmax();

      /**
       *  @brief Performs sigmoid on row vectors
       *         result to this (elem by elem)
       */
      ThisType &
      RowSigmoid();

      /**
       *  @brief Performs softmax on row vectors
       *         result to this (elem by elem)
       */
      ThisType &
      RowSoftmax();

      /**
       *  @brief Performs matrix inversion
       */
      ThisType &
      Invert();

      ThisType &
      Clear();

      /**
       *  @brief Gives access to a specified matrix row without range check
       *  @return pointer to the first field of the row
       */
      inline _ElemT*
      operator []  (size_t i) const
      {
        return mpData + (i * mStride);
      }

      /**
       *  @brief Gives access to a specified matrix row with range check
       *  @return pointer to the first field of the row
       */
      _ElemT*
      Row (const size_t r)
      {
        if (0 <= r && r < mMRows)
        {
          return this->operator[] (r);
        }
        else
        {
          throw std::out_of_range("Matrix row out of range");
        }
      }

      /**
       *  @brief Gives access to matrix elements (row, col)
       *  @return pointer to the desired field
       */
      _ElemT&
      operator () (const size_t r, const size_t c)
      { return *(mpData + r * mStride + c); }

      friend std::ostream &
      operator << <> (std::ostream & out, ThisType & m);

      void PrintOut(char *file);
      void ReadIn(char *file);

      /**
       * @brief Returns a matrix sub-range
       * @param ro Row offset
       * @param r  Rows in range
       * @param co Column offset
       * @param c  Coluns in range
       * See @c MatrixRange class for details
       */
      MatrixRange<_ElemT>
      Range(const size_t    ro, const size_t    r,
            const size_t    co, const size_t    c)
      { return MatrixRange<_ElemT>(*this, ro, r, co, c); }

    protected:
      inline void swap4b(void *a);
      inline void swap2b(void *a);

    protected:

      /// these atributes store the real matrix size as it is stored in memory
      /// including memalignment
      size_t    mMRows;       ///< Number of rows
      size_t    mMCols;       ///< Number of columns
      size_t    mStride;      ///< true number of columns for the internal matrix.
                              ///< This number may differ from M_cols as memory
                              ///< alignment might be used
      /// data memory area
      _ElemT*   mpData;

#ifdef STK_MEMALIGN_MANUAL
      /// data to be freed (in case of manual memalignment use, see common.h)
      _ElemT*   mpFreeData;
#endif
    }; // class Matrix

  /** **************************************************************************
   ** **************************************************************************
   *  @brief Provides a window matrix abstraction class
   *
   *  This class provides a way to work with matrix cutouts in STK.
   *  It encapsulates basic operations and memory optimizations.
   *
   */
  template<typename _ElemT>
    class WindowMatrix : public Matrix<_ElemT>
    {
    protected:
      /// points to the original begining of the data array
      /// The data atribute points now to the begining of the window
      _ElemT * mpOrigData;

      //@{
      /// these atributes store the real matrix size as it is stored in memory
      /// including memalignment
      size_t  mOrigMRows;       ///< Number of rows
      size_t  mOrigMCols;       ///< Number of columns
      size_t  mOrigMRealCols;   ///< true number of columns for the internal matrix.
                                ///< This number may differ from M_cols as memory
                                ///< alignment might be used
      size_t  mTRowOff;         ///< First row of the window
      size_t  mTColOff;         ///< First column of the window
      //@}

    public:
      /// defines a type of this
      typedef WindowMatrix<_ElemT>    ThisType;

      /// Empty constructor
      WindowMatrix() : Matrix<_ElemT>() {};

      /// Copy constructor
      WindowMatrix(const ThisType & rT);

      /// Basic constructor
      WindowMatrix(const size_t r, const size_t c):
        Matrix<_ElemT>(r, c), // create the base class
        mOrigMRows    (Matrix<_ElemT>::mMRows),
        mOrigMCols    (Matrix<_ElemT>::mMCols),
        mOrigMRealCols(Matrix<_ElemT>::mStride),
        mTRowOff(0), mTColOff(0)          // set the offset
      {
        mpOrigData = Matrix<_ElemT>::mpData;
      }

      /// The destructor
      ~WindowMatrix<_ElemT>()
      {
        Matrix<_ElemT>::mpData = this->mpOrigData;
      }

      /// sets the size of the window (whole rows)
      void
      SetSize(const size_t ro,
              const size_t r);

      /// sets the size of the window
      void
      SetSize(const size_t ro,
              const size_t r,
              const size_t co,
              const size_t c);

      /**
       *  @brief Resets the window to the default (full) size
       */
      void
      Reset ()
      {
        Matrix<_ElemT>::mpData    =  mpOrigData;
        Matrix<_ElemT>::mMRows    =  mOrigMRows;
        Matrix<_ElemT>::mMCols    =  mOrigMCols;
        Matrix<_ElemT>::mStride   =  mOrigMRealCols;

        mTRowOff = 0;
        mTColOff = 0;
      }
    };

  /** **************************************************************************
   ** **************************************************************************
   *  @brief Sub-matrix representation
   *
   *  This class provides a way to work with matrix cutouts in STK.
   *
   *
   */
  template<typename _ElemT>
    class MatrixRange : public Matrix<_ElemT>
    {
    public:
      /// Constructor
      MatrixRange(const Matrix<_ElemT>& rT,
                  const size_t    ro,
                  const size_t    r,
                  const size_t    co,
                  const size_t    c);

      /// The destructor
      virtual
      ~MatrixRange<_ElemT>()
      {
#ifndef STK_MEMALIGN_MANUAL
        Matrix<_ElemT>::mpData = NULL;
#else
        Matrix<_ElemT>::mpFreeData = NULL;
#endif
      }
    };
} // namespace STK

//*****************************************************************************
//*****************************************************************************
// we need to include the implementation
#include "Matrix.tcc"
//*****************************************************************************
//*****************************************************************************

/******************************************************************************
 ******************************************************************************
 * The following section contains specialized template definitions
 * whose implementation is in Matrix.cc
 */

namespace STK
{
  template<>
    Matrix<float> &
    Matrix<float>::
    FastRowSigmoid();

  template<>
    Matrix<double> &
    Matrix<double>::
    FastRowSigmoid();

  template<>
    Matrix<float> &
    Matrix<float>::
    RowSigmoid();

  template<>
    Matrix<double> &
    Matrix<double>::
    RowSigmoid();

  template<>
    Matrix<float> &
    Matrix<float>::
    DiagScale(const BasicVector<float>& rDiagVector);

  template<>
    Matrix<float> &
    Matrix<float>::
    DiagScale(const float* pDiagVector);

  template<>
    Matrix<float> &
    Matrix<float>::
    FastRowSoftmax();

  template<>
    Matrix<double> &
    Matrix<double>::
    FastRowSoftmax();

  template<>
    Matrix<float> &
    Matrix<float>::
    RowSoftmax();

  template<>
    Matrix<double> &
    Matrix<double>::
    RowSoftmax();

  template<>
    Matrix<float> &
    Matrix<float>::
    AddCMtMMul(const float& c, const Matrix<float>& a,
                               const Matrix<float>& b);

  template<>
    Matrix<double> &
    Matrix<double>::
    AddCMtMMul(const double& c, const Matrix<double>& a,
                                const Matrix<double>& b);

  template<>
    Matrix<float> &
    Matrix<float>::
    AddMMMul(const Matrix<float>& a, const Matrix<float>& b);

  template<>
    Matrix<double> &
    Matrix<double>::
    AddMMMul(const Matrix<double> & a, const Matrix<double>& b);

  template<>
    Matrix<float> &
    Matrix<float>::
    RepMMMul(const Matrix<float> & a, const Matrix<float>& b);

  template<>
    Matrix<float> &
    Matrix<float>::
    AddCMMtMul(const float& c, const Matrix<float>& a,
                               const Matrix<float>& b);

  template<>
    Matrix<double> &
    Matrix<double>::
    AddCMMtMul(const double& c, const Matrix<double>& a,
                                const Matrix<double>& b);

  template<>
    Matrix<float> &
    Matrix<float>::
    AddCVVtMul(const float& c, const BasicVector<float>& rA,
                               const BasicVector<float>& rB);

  template<>
    Matrix<double> &
    Matrix<double>::
    AddCVVtMul(const double& c, const BasicVector<double>& rA,
                                const BasicVector<double>& rB);

} // namespace STK

//#ifndef STK_Matrix_h
#endif


////////////////////////////////////////////////////////////
//
// Copyright (c) 2018 Jan Filipowicz, Filip Turobos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#ifndef GENETIC_ALGORITHM_LIBRARY_ROULETTE_WHEEL_SELECTION_H
#define GENETIC_ALGORITHM_LIBRARY_ROULETTE_WHEEL_SELECTION_H

#include <algorithm>
#include <cstddef>
#include <limits>
#include <random>
#include <utility>
#include <type_traits>
#include <vector>
#include <gsl/gsl_assert>
#include "identity.h"

template<class UniformRandomBitGenerator, class Function = identity>
class roulette_wheel_selection {
public:
	explicit roulette_wheel_selection(UniformRandomBitGenerator& g, const Function& f = Function()) noexcept(noexcept(Function(f)));
	template<class Specimen>
	void operator()(std::vector<Specimen>& specimens, std::size_t n);
private:
	UniformRandomBitGenerator& rand;
	Function probability_function;
};

template<class UniformRandomBitGenerator, class Function>
inline roulette_wheel_selection<UniformRandomBitGenerator, Function>::roulette_wheel_selection(UniformRandomBitGenerator& g, const Function& f) noexcept(noexcept(Function(f)))
	: rand(g), probability_function(f) {}

template<class UniformRandomBitGenerator, class Function>
template<class Specimen>
inline void roulette_wheel_selection<UniformRandomBitGenerator, Function>::operator()(std::vector<Specimen>& specimens, std::size_t n) {
	Expects(specimens.size() >= n);
	using sample_type = std::common_type_t<double, decltype(probability_function(std::declval<typename Specimen::rating_type>()))>;
	using iterator_type = typename std::vector<Specimen>::iterator;
	using pair_type = std::pair<sample_type, iterator_type>;
	std::vector<pair_type> samples;
	samples.reserve(specimens.size());
	for (iterator_type it = specimens.begin(); it != specimens.end(); ++it) {
		const sample_type probability = probability_function(it->rating());
		sample_type sample = std::numeric_limits<sample_type>::max();
		if (probability > 0.0) {
			const std::exponential_distribution<sample_type> distribution(probability);
			sample = distribution(rand);
		}
		samples.emplace_back(sample, it);
	}
	std::nth_element(samples.begin(), samples.begin() + n, samples.end());
	samples.resize(n);
	iterator_type it = specimens.begin();
	for (const auto& sample : samples) {
		std::iter_swap(it++, sample.second);
	}
	specimens.resize(n);
}

#endif


/*
 * halo.h
 *
 *  Created on: Oct 23, 2012
 *      Author: cgiocoli
 *
 *      This class implement the non-linear power spectrum using the Halo Model
 */

#ifndef POWERCDMHM_H_
#define POWERCDMHM_H_
#include <math.h>
#include <cosmo.h>
#include <halo.h>
#include <utilities.h>

#ifdef ENABLE_GSL

#include <gsl/gsl_errno.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_sf.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_spline.h>
#include <gsl/gsl_rng.h>

/**
 * \brief Class for calculating the non-linear power spectrum using ****** Halo Model.
 *  To use this class you must enable GSL.
 */
class POWERCDMHM{
  public:
  POWERCDMHM(COSMOLOGY *co, double redshift, double minHalomass, double sigma=0.25,int cmRelation=0,double slope=-0.1);

  double nonlinpowerCDMHM(double k);
  double nonlinpowerCDMHM1Halo(double k);
  double nonlinpowerCDMHM2Halo(double k);
  double nonlinKAPPApowerCDMHM(double l, double zs);
  double nonlinKAPPApowerCDMHM1Halo(double l, double zs);
  double nonlinKAPPApowerCDMHM2Halo(double l, double zs);
  double linKAPPApowerCDMHM(double l, double zs);
  double nonlinfitKAPPApowerCDMHM(double l, double zs);
  virtual ~POWERCDMHM ();

  protected:
  gsl_function intPk1,intPk2;
  double Pklin,Pk1,Pk2;
  double Pk20;
  double weight (double z1, double z2);
  double weight (double z0);

  struct weightfnc{
    std::vector<double> ai;
    std::vector<double> wi;
  };
  weightfnc wgf; // weight function
  void Initweight(double zs);
  private:
  float *xf,*wf;
};
#endif

#endif /* POWERCDMHM_H_ */


/*
 * neuro.c
 *
 *  Created on: Oct 9, 2019
 *      Author: alexey
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_rng.h>
#include <png.h>
#include <malloc.h>

#include "neuro.h"

typedef struct _neuro_skeleton {
	int input_l;
	int output_l;
	int hidden_l;
	int number_of_hidden;
	double alpha;
	gsl_matrix *input_m;
	gsl_matrix *output_m;
	gsl_matrix **hidden_m;
	gsl_matrix **dropuot;
	gsl_matrix **layers;
	gsl_matrix **layers_delta;
	gsl_matrix *temp;
	gsl_matrix *train;
	gsl_matrix *error;
	int layers_numb;
	activation activ;
	activation *activ_l;
} neuro_skeleton;

const gsl_rng_type * T;
gsl_rng * r;

extern unsigned long int gsl_rng_default_seed;

#define CLEAN_BLOB() bayrepo_clean_neuro((void *) blob); \
		return NULL
#define CLEAN_IF_NULL(x) if (!blob->x) { \
		CLEAN_BLOB(); \
	}

#define ISDEBUGINFO_BEG() if (getenv("MATRIXD") && !strcmp(getenv("MATRIXD"),"1")) {
#define ISDEBUGINFO_END() }
#define DEBUGINFO(A, B, C) ISDEBUGINFO_BEG()\
		bayrepo_print_matrix(A, B, C); \
		ISDEBUGINFO_END()

#define MAX_LAYER_NAME_LEN 1024
#define MAX_BUFFER_LEN 4096

static void bayrepo_print_matrix(gsl_matrix *a, const char *matrix_name,
		int index_matrix) {
	int index, jndex;
	if (index_matrix >= 0) {
		printf("Matrix %s[%d]:\n", matrix_name, index_matrix);
	} else {
		printf("Matrix %s:\n", matrix_name);
	}
	for (index = 0; index < a->size1; index++) {
		printf("==");
		for (jndex = 0; jndex < a->size2; jndex++) {
			printf("%.3f   ", gsl_matrix_get(a, index, jndex));
		}
		printf("==\n");
	}
}

static void bayrepo_layers_clean(void *blob) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (data->layers) {
			int index = 0;
			for (index = 0; index < data->layers_numb; index++) {
				if (data->layers[index])
					gsl_matrix_free(data->layers[index]);
			}
			free(data->layers);
			data->layers = NULL;
		}
		if (data->layers_delta) {
			int index = 0;
			for (index = 0; index < data->layers_numb; index++) {
				if (data->layers_delta[index])
					gsl_matrix_free(data->layers_delta[index]);
			}
			data->layers_numb = 0;
			free(data->layers_delta);
			data->layers_delta = NULL;
		}
		data->layers_numb = 0;
	}
}

void bayrepo_clean_neuro(void *blob) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (data->input_m) {
			gsl_matrix_free(data->input_m);
			data->input_m = NULL;
		}
		if (data->output_m) {
			gsl_matrix_free(data->output_m);
			data->output_m = NULL;
		}
		if (data->train) {
			gsl_matrix_free(data->train);
			data->train = NULL;
		}
		if (data->temp) {
			gsl_matrix_free(data->temp);
			data->temp = NULL;
		}
		if (data->error) {
			gsl_matrix_free(data->error);
			data->error = NULL;
		}
		if (data->activ_l) {
			free(data->activ_l);
			data->activ_l = NULL;
		}
		if (data->number_of_hidden > 0 && data->hidden_m) {
			int i;
			for (i = 0; i < data->number_of_hidden; i++) {
				if (data->hidden_m[i]) {
					gsl_matrix_free(data->hidden_m[i]);
					data->hidden_m[i] = NULL;
				}
			}
			free(data->hidden_m);
		}
		if (data->number_of_hidden > 0 && data->dropuot) {
			int i;
			for (i = 0; i < data->number_of_hidden; i++) {
				if (data->dropuot[i]) {
					gsl_matrix_free(data->dropuot[i]);
					data->dropuot[i] = NULL;
				}
			}
			free(data->dropuot);
		}
		bayrepo_layers_clean(blob);
		free(data);
	}
	if (r) {
		gsl_rng_free(r);
		r = NULL;
	}
}

void bayrepo_set_layer_activ(void * blob, int layer_number, activation activ) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (data->number_of_hidden) {
			if (layer_number <= data->number_of_hidden) {
				data->activ_l[layer_number] = activ;
			}
		} else {
			if (!layer_number) {
				data->activ_l[0] = activ;
			}
		}
	}
}

static int bayrepo_random_matrix(gsl_matrix *a, int m, int n, int is_negative) {
	int index, jndex;

	if (!r)
		return -1;

	for (index = 0; index < m; index++) {
		for (jndex = 0; jndex < n; jndex++) {
			gsl_matrix_set(a, index, jndex,
					gsl_rng_uniform(r) - (is_negative ? 0.5 : 0.0));
		}
	}

	return 0;
}

void *bayrepo_init_neuro(int input, int output, int hidden, int hidden_num,
		double alpha, activation activ) {
	int index;

	gsl_rng_default_seed = time(NULL);

	T = gsl_rng_knuthran2;
	r = gsl_rng_alloc(T);

	if (hidden_num < 0) {
		hidden_num = 0;
	}
	neuro_skeleton *blob = calloc(1, sizeof(neuro_skeleton));
	if (!blob)
		return NULL;
	blob->input_m = gsl_matrix_alloc(1, input);
	CLEAN_IF_NULL(input_m);
	blob->train = gsl_matrix_alloc(1, output);
	CLEAN_IF_NULL(train);
	blob->error = gsl_matrix_alloc(1, output);
	CLEAN_IF_NULL(error);

	if (hidden_num) {
		blob->output_m = gsl_matrix_alloc(hidden, output);
		CLEAN_IF_NULL(output_m);
		blob->hidden_m = (gsl_matrix **) calloc(hidden_num,
				sizeof(gsl_matrix *));
		CLEAN_IF_NULL(hidden_m);
		blob->dropuot = (gsl_matrix **) calloc(hidden_num,
				sizeof(gsl_matrix *));
		CLEAN_IF_NULL(dropuot);
		for (index = 1; index < hidden_num; index++) {
			blob->hidden_m[index] = gsl_matrix_alloc(hidden, hidden);
			CLEAN_IF_NULL(hidden_m[index]);
			blob->dropuot[index] = gsl_matrix_alloc(1, hidden);
			CLEAN_IF_NULL(dropuot[index]);
		}
		blob->hidden_m[0] = gsl_matrix_alloc(input, hidden);
		CLEAN_IF_NULL(hidden_m[0]);
		blob->dropuot[0] = gsl_matrix_alloc(1, hidden);
		CLEAN_IF_NULL(dropuot[0]);
		blob->temp = gsl_matrix_alloc(1, hidden);
		CLEAN_IF_NULL(temp);
	} else {
		blob->output_m = gsl_matrix_alloc(input, output);
		CLEAN_IF_NULL(output_m);
	}
	blob->alpha = alpha;
	blob->input_l = input;
	blob->output_l = output;
	blob->hidden_l = hidden;
	blob->number_of_hidden = hidden_num;

	gsl_matrix_set_zero(blob->input_m);
	gsl_matrix_set_zero(blob->train);
	if (hidden_num) {
		if (bayrepo_random_matrix(blob->output_m, hidden, output,
				(activ == RELU ? 0 : 1)) < 0) {
			CLEAN_BLOB()
;		}
		for (index = 1; index < hidden_num; index++) {
			if (bayrepo_random_matrix(blob->hidden_m[index], hidden, hidden, (activ==RELU?0:1))<0) {
				CLEAN_BLOB();
			}
		}
		if (bayrepo_random_matrix(blob->hidden_m[0], input, hidden, (activ==RELU?0:1))<0) {
			CLEAN_BLOB();
		}
	} else {
		if (bayrepo_random_matrix(blob->output_m, input, output, (activ==RELU?0:1))<0) {
			CLEAN_BLOB();
		}
	}

	int lyr_nmb = 1 + blob->number_of_hidden ? (blob->number_of_hidden + 1) : 0;

	blob->layers = (gsl_matrix **) calloc(lyr_nmb, sizeof(gsl_matrix *));
	CLEAN_IF_NULL(layers);

	if (hidden_num) {
		for (index = 1; index < hidden_num; index++) {
			blob->layers[index] = gsl_matrix_alloc(1, hidden);
			CLEAN_IF_NULL(layers[index]);
		}
		blob->layers[0] = gsl_matrix_alloc(1, hidden);
		CLEAN_IF_NULL(layers[0]);
		blob->layers[lyr_nmb - 1] = gsl_matrix_alloc(1, output);
		CLEAN_IF_NULL(layers[lyr_nmb-1]);
	} else {
		blob->layers[0] = gsl_matrix_alloc(1, output);
		CLEAN_IF_NULL(layers[0]);
	}

	blob->layers_numb = lyr_nmb;
	blob->layers_delta = (gsl_matrix **) calloc(lyr_nmb, sizeof(gsl_matrix *));
	CLEAN_IF_NULL(layers_delta);

	if (hidden_num) {
		for (index = 1; index < hidden_num; index++) {
			blob->layers_delta[index] = gsl_matrix_alloc(1, hidden);
			CLEAN_IF_NULL(layers_delta[index]);
		}
		blob->layers_delta[0] = gsl_matrix_alloc(1, hidden);
		CLEAN_IF_NULL(layers_delta[0]);
		blob->layers_delta[lyr_nmb - 1] = gsl_matrix_alloc(1, output);
		CLEAN_IF_NULL(layers_delta[lyr_nmb-1]);
	} else {
		blob->layers_delta[0] = gsl_matrix_alloc(1, output);
		CLEAN_IF_NULL(layers_delta[0]);
	}
	blob->activ = activ;
	blob->activ_l = calloc(blob->number_of_hidden + 1, sizeof(activation));
	CLEAN_IF_NULL(activ_l);
	for (index = 0; index < (blob->number_of_hidden + 1); index++) {
		if (index == blob->number_of_hidden) {
			blob->activ_l[index] = NOACTIV;
		} else {
			blob->activ_l[index] = DEFLT;
		}
	}

	return (void *) blob;
}

static void bayrepo_fill_dropout(gsl_matrix *a, int m, int n) {
	int index, jndex;
	if (!r) {
		for (index = 0; index < m; index++) {
			for (jndex = 0; jndex < n; jndex++) {
				gsl_matrix_set(a, index, jndex, 1.0);
			}
		}
		return;
	}

	for (index = 0; index < m; index++) {
		for (jndex = 0; jndex < n; jndex++) {
			gsl_matrix_set(a, index, jndex, gsl_rng_uniform_int(r, 2) * 1.0);
		}
	}

	return;
}

void bayrepo_fill_input(void *blob, int position, double scaled_value) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (position < data->input_l) {
			gsl_matrix_set(data->input_m, 0, position, scaled_value);
		}
	}
}

void bayrepo_fill_train(void *blob, int position, double scaled_value) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (position < data->output_l) {
			gsl_matrix_set(data->train, 0, position, scaled_value);
		}
	}
}

void bayrepo_fill_hidden(void *blob, int index, int position_x, int position_y,
		double scaled_value) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		gsl_matrix_set(data->hidden_m[index], position_x, position_y,
				scaled_value);
	}
}

void bayrepo_fill_outm(void *blob, int position_x, int position_y,
		double scaled_value) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		gsl_matrix_set(data->output_m, position_x, position_y, scaled_value);
	}
}

static void bayrepo_zero_layers(void *blob) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		int index;
		for (index = 0; index < data->layers_numb; index++) {
			gsl_matrix_set_zero(data->layers[index]);
		}
	}
}

static double bayrepo_activation_func(double elem, neuro_skeleton *data,
		int lyn) {
	activation act = data->activ;
	if ((lyn < (data->number_of_hidden + 1)) && (data->activ_l[lyn] != DEFLT)) {
		act = data->activ_l[lyn];
	}
	switch (act) {
	case RELU:
		return elem > 0.0 ? elem : 0.0;
	case TANH:
		return tanh(elem);
	case SIGMOID:
		return 1.0 / (1.0 + exp(-elem));
	default:
		return elem;
	}
}

activation bayrepo_get_layer_func(void *blob, int lyn) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if ((lyn < (data->number_of_hidden + 1))
				&& (data->activ_l[lyn] != DEFLT)) {
			return data->activ_l[lyn];
		}
	}
	return NOACTIV;
}

activation bayrepo_get_sublayer_func(void *blob, int lyn) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (lyn < (data->number_of_hidden + 1)) {
			return data->activ_l[lyn];
		}
	}
	return NOACTIV;
}

static double bayrepo_activation_deriv(double elem, neuro_skeleton *data,
		int lyn) {
	activation act = data->activ;
	if ((lyn < (data->number_of_hidden + 1)) && (data->activ_l[lyn] != DEFLT)) {
		act = data->activ_l[lyn];
	}
	switch (act) {
	case RELU:
		return elem > 0.0 ? 1.0 : 0.0;
	case TANH:
		return 1.0 - (elem * elem);
	case SIGMOID:
		return elem * (1.0 - elem);
	default:
		return elem;
	}
}

static void bayrepo_matix_customize(gsl_matrix *a, int size,
		neuro_skeleton *data, int lyn) {
	int index;
	for (index = 0; index < size; index++) {
		gsl_matrix_set(a, 0, index,
				bayrepo_activation_func(gsl_matrix_get(a, 0, index), data,
						lyn));
	}
}

static void bayrepo_matix_deriv(gsl_matrix *a, int size, neuro_skeleton *data,
		int lyn) {
	int index;
	for (index = 0; index < size; index++) {
		gsl_matrix_set(a, 0, index,
				bayrepo_activation_deriv(gsl_matrix_get(a, 0, index), data,
						lyn));
	}
}

static void bayrepo_query_internal(void *blob, int dropout) {
	int index;
	if (blob) {
		ISDEBUGINFO_BEG()
			printf("=====================Query=========================\n");
		ISDEBUGINFO_END()
		neuro_skeleton *data = (neuro_skeleton *) blob;
		bayrepo_zero_layers(blob);

		if (data->number_of_hidden) {
			if (dropout == 1) {
				for (index = 0; index < data->number_of_hidden; index++) {
					bayrepo_fill_dropout(data->dropuot[index], 1,
							data->hidden_l);
				}
			}
			int cnt = 0;
			gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, data->input_m,
					data->hidden_m[0], 0.0, data->layers[0]);
			bayrepo_matix_customize(data->layers[0], data->hidden_l, data, 0);
			if (dropout == 1) {
				gsl_matrix_mul_elements(data->layers[0], data->dropuot[0]);
				gsl_matrix_scale(data->layers[0], 2.0);
			}
			cnt++;
			for (index = 1; index < data->number_of_hidden; index++) {
				gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
						data->layers[index - 1], data->hidden_m[index], 0.0,
						data->layers[index]);
				bayrepo_matix_customize(data->layers[index], data->hidden_l,
						data, index);
				if (dropout == 1) {
					gsl_matrix_mul_elements(data->layers[index],
							data->dropuot[index]);
					gsl_matrix_scale(data->layers[index], 2.0);
				}
				cnt++;
			}
			gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0,
					data->layers[cnt - 1], data->output_m, 0.0,
					data->layers[cnt]);
			bayrepo_matix_customize(data->layers[cnt], data->output_l, data,
					cnt);

		} else {
			gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, data->input_m,
					data->output_m, 0.0, data->layers[0]);
			bayrepo_matix_customize(data->layers[0], data->output_l, data, 0);
		}

		DEBUGINFO(data->input_m, "INPUTM", -1);
		if (data->number_of_hidden) {
			for (index = 0; index < data->number_of_hidden; index++) {
				DEBUGINFO(data->hidden_m[index], "HIDDEN", index);
			}
		}
		DEBUGINFO(data->output_m, "OUTPUTM", -1);
		for (index = 0; index < data->layers_numb; index++) {
			DEBUGINFO(data->layers[index], "LAYER", index);
		}
	}
}

void bayrepo_query(void *blob) {
	bayrepo_query_internal(blob, 0);
}

double bayrepo_get_result(void *blob, int position) {
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		if (data->layers && position < data->output_l) {
			return gsl_matrix_get(data->layers[data->layers_numb - 1], 0,
					position);
		}
	}
	return -10000.0;
}

double bayrepo_get_sum(gsl_matrix *a) {
	double result = 0.0;
	int index, jndex = 0;
	for (index = 0; index < a->size1; index++) {
		for (jndex = 0; jndex < a->size2; jndex++) {
			result += gsl_matrix_get(a, index, jndex);
		}
	}
	return result;
}

void bayrepo_train(void *blob, int epoch, int use_dropout) {
	int index;
	if (blob) {
		while (epoch--) {
			ISDEBUGINFO_BEG()
				printf(
						"=====================Epoch %d=========================\n",
						epoch);
			ISDEBUGINFO_END()
			neuro_skeleton *data = (neuro_skeleton *) blob;
			bayrepo_query_internal(blob, use_dropout);
			gsl_matrix_memcpy(data->layers_delta[data->layers_numb - 1],
					data->layers[data->layers_numb - 1]);
			ISDEBUGINFO_BEG()
				gsl_matrix_memcpy(data->error,
						data->layers[data->layers_numb - 1]);
			ISDEBUGINFO_END();
			gsl_matrix_sub(data->layers_delta[data->layers_numb - 1],
					data->train);
			ISDEBUGINFO_BEG()
				gsl_matrix_sub(data->error, data->train);
				gsl_matrix_mul_elements(data->error, data->error);
				printf("=======>Error=%f\n", bayrepo_get_sum(data->error));
			ISDEBUGINFO_END();
			if (data->number_of_hidden) {
				int index;
				for (index = (data->layers_numb - 2); index >= 0; index--) {
					gsl_matrix_set_zero(data->temp);
					gsl_matrix_memcpy(data->temp, data->layers[index]);
					bayrepo_matix_deriv(data->temp, data->hidden_l, data,
							index);
					if (index == (data->layers_numb - 2)) {
						gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0,
								data->layers_delta[index + 1], data->output_m,
								0.0, data->layers_delta[index]);
					} else {
						gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0,
								data->layers_delta[index + 1],
								data->hidden_m[index + 1], 0.0,
								data->layers_delta[index]);
					}
					gsl_matrix_mul_elements(data->layers_delta[index],
							data->temp);
				}

				if (use_dropout) {
					for (index = 0; index < data->number_of_hidden; index++) {
						gsl_matrix_mul_elements(data->layers_delta[index],
								data->dropuot[index]);
					}
				}

				for (index = (data->layers_numb - 1); index >= 0; index--) {
					if (index == (data->layers_numb - 1)) {
						gsl_blas_dgemm(CblasTrans, CblasNoTrans, -data->alpha,
								data->layers[index - 1],
								data->layers_delta[index], 1.0, data->output_m);
					} else if (index == 0) {
						gsl_blas_dgemm(CblasTrans, CblasNoTrans, -data->alpha,
								data->input_m, data->layers_delta[index], 1.0,
								data->hidden_m[0]);
					} else {
						gsl_blas_dgemm(CblasTrans, CblasNoTrans, -data->alpha,
								data->layers[index - 1],
								data->layers_delta[index], 1.0,
								data->hidden_m[index]);
					}
				}
			} else {
				gsl_blas_dgemm(CblasTrans, CblasNoTrans, -data->alpha,
						data->input_m, data->layers_delta[0], 1.0,
						data->output_m);
			}
			for (index = 0; index < data->layers_numb; index++) {
				DEBUGINFO(data->layers_delta[index], "LAYER_DELTA", index);
			}
		}
	}
}

static void byrepo_png_write_data(png_structp png_ptr, png_bytep data,
		png_size_t length) {

	bayrepo_mem_encode* p = (bayrepo_mem_encode*) png_get_io_ptr(png_ptr);
	size_t nsize = p->size + length;

	if (p->buffer)
		p->buffer = realloc(p->buffer, nsize);
	else
		p->buffer = malloc(nsize);

	if (!p->buffer)
		png_error(png_ptr, "Write Error");

	memcpy(p->buffer + p->size, data, length);
	p->size += length;
}

static void bayrepo_png_flush(png_structp png_ptr) {
}

int bayrepo_write_matrix(void *blob, FILE *fp, int width, int height,
		bayrepo_mem_encode *buffer) {
	int code = 0;
	if (buffer) {
		buffer->buffer = NULL;
		buffer->size = 0;
	}
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	png_bytep row = NULL;
	if ((blob == NULL) || (fp == NULL)) {
		return -1;
	}

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) {
		code = -3;
		goto finalise;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		code = -4;
		goto finalise;
	}

	if (setjmp(png_jmpbuf(png_ptr))) {
		code = -5;
		goto finalise;
	}

	if (buffer) {
		png_set_write_fn(png_ptr, buffer, byrepo_png_write_data,
				bayrepo_png_flush);
	} else {
		png_init_io(png_ptr, fp);
	}

	neuro_skeleton *data = (neuro_skeleton *) blob;

	int picSize = (height + 3) + (height + 3) * data->number_of_hidden;

	png_set_IHDR(png_ptr, info_ptr, width, picSize, 8, PNG_COLOR_TYPE_GRAY,
	PNG_INTERLACE_NONE,
	PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

	png_write_info(png_ptr, info_ptr);

	row = (png_bytep) malloc(3 * width * sizeof(png_byte));
	if (!row) {
		code = -5;
		goto finalise;
	}

	int index = 0;
	for (index = 0; index < data->number_of_hidden + 1; index++) {
		gsl_matrix * m = NULL;
		if (data->number_of_hidden) {
			m = (index == data->number_of_hidden) ?
					data->output_m : data->hidden_m[index];
		} else {
			m = data->output_m;
		}

		double rangeMax = gsl_matrix_max(m);
		double rangeMin = gsl_matrix_min(m);

		if (((width / m->size1) == 0) || ((height / m->size2) == 0)) {
			return -2;
		}

		int sizeX = width / m->size1;
		int sizeY = height / m->size2;

		int x, y;
		for (y = 0; y < height; y++) {
			for (x = 0; x < width; x++) {
				int curX = x / sizeX;
				int curY = y / sizeY;
				if ((curX >= m->size1) || (curY >= m->size2)) {
					row[x] = (png_byte) 255;
				} else {
					png_byte res_color = (png_byte) ((gsl_matrix_get(m, curX,
							curY) - rangeMin) / (rangeMax - rangeMin) * 255.0);
					if (res_color > 255.0)
						res_color = 255.0;
					row[x] = (png_byte) (255.0 - res_color);
				}
			}
			png_write_row(png_ptr, row);
		}
		for (y = 0; y < 3; y++) {
			for (x = 0; x < width; x++) {
				if (y != 1) {
					row[x] = (png_byte) 255;
				} else {
					row[x] = (png_byte) 0;
				}
			}
			png_write_row(png_ptr, row);
		}
	}

	png_write_end(png_ptr, NULL);

	finalise: if (info_ptr != NULL)
		png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
	if (png_ptr != NULL)
		png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
	if (row != NULL)
		free(row);
	return code;

}

void bayrepo_print_matrix_custom(void *blob, bayrepo_decorator *decor) {
	char layer_name[MAX_LAYER_NAME_LEN];
	if (blob) {
		neuro_skeleton *data = (neuro_skeleton *) blob;
		int index = 0;
		for (index = 0; index < (data->number_of_hidden + 1); index++) {
			gsl_matrix * m = NULL;
			if (data->number_of_hidden) {
				m = (index == data->number_of_hidden) ?
						data->output_m : data->hidden_m[index];
				if (index == data->number_of_hidden) {
					snprintf(layer_name, MAX_LAYER_NAME_LEN, "Output layer");
				} else {
					snprintf(layer_name, MAX_LAYER_NAME_LEN, "Hidden layer %d",
							index);
				}
			} else {
				m = data->output_m;
				snprintf(layer_name, MAX_LAYER_NAME_LEN, "Output layer");
			}
			int posX, posY;
			if (decor->table_header)
				decor->table_header(decor->user_data, layer_name, m->size1);
			for (posX = 0; posX < m->size2; posX++) {
				if (decor->pre_column)
					decor->pre_column(decor->user_data);
				for (posY = 0; posY < m->size1; posY++) {
					if (decor->print_func)
						decor->print_func(decor->user_data,
								gsl_matrix_get(m, posY, posX));
				}
				if (decor->post_column)
					decor->post_column(decor->user_data);
			}
			if (decor->table_footer)
				decor->table_footer(decor->user_data);
		}
	}
}

int input_l;
int output_l;
int hidden_l;
int number_of_hidden;
double alpha;
gsl_matrix *input_m;
gsl_matrix *output_m;
gsl_matrix **hidden_m;
gsl_matrix **dropuot;
gsl_matrix **layers;
gsl_matrix **layers_delta;
gsl_matrix *temp;
gsl_matrix *train;
gsl_matrix *error;
int layers_numb;
activation activ;
activation *activ_l;

/*
 * Save format
 *
 *  [int input_l]\n
 *  [int output_l]\n
 *  [int hidden_l]\n
 *  [int number_of_hidden]\n
 *  [double alpha]\n
 *  [int activ]\n
 *  [ACTBEG]\n
 *  [int layer_number]:[int activ]\n
 *  [ACTEND]\n
 *  [HIDDEN_BEG]\n
 *  [int X]:[int Y]:[double value]\n
 *  [HIDDEN_END]
 *  [OUTPUT_BEG]\n
 *  [int X]:[int Y]:[double value]\n
 *  [OUTPUT_END]\n
 */

static char *bayrepo_reallocate_buffer(char *buffer, char *newdata, int *len,
		int newlen) {
	buffer = (char *) realloc(buffer, *len + newlen);
	if (!buffer) {
		return NULL;
	}
	memcpy(buffer + *len, newdata, newlen);
	*len = *len + newlen;
	return buffer;
}

int bayrepo_save_to_buffer(void *blob, char **buffer) {
	char buff[MAX_LAYER_NAME_LEN];
	int index;
	if (blob) {
		int len = 0;
		char *ptr = NULL;
		neuro_skeleton *data = (neuro_skeleton *) blob;
		snprintf(buff, MAX_LAYER_NAME_LEN, "%d\n", data->input_l);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		snprintf(buff, MAX_LAYER_NAME_LEN, "%d\n", data->output_l);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		snprintf(buff, MAX_LAYER_NAME_LEN, "%d\n", data->hidden_l);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		snprintf(buff, MAX_LAYER_NAME_LEN, "%d\n", data->number_of_hidden);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		snprintf(buff, MAX_LAYER_NAME_LEN, "%f\n", data->alpha);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		snprintf(buff, MAX_LAYER_NAME_LEN, "%d\n", (int) data->activ);
		ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len, strlen(buff));
		ptr = bayrepo_reallocate_buffer(ptr, (char *) "[ACTBEG]\n", &len,
				strlen("[ACTBEG]\n"));
		for (index = 0; index < (data->number_of_hidden + 1); index++) {
			snprintf(buff, MAX_LAYER_NAME_LEN, "%d:%d\n", index,
					(int) data->activ_l[index]);
			ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len,
					strlen(buff));
		}
		ptr = bayrepo_reallocate_buffer(ptr, (char *) "[ACTEND]\n", &len,
				strlen("[ACTEND]\n"));
		for (index = 0; index < data->number_of_hidden; index++) {
			ptr = bayrepo_reallocate_buffer(ptr, (char *) "[HIDDEN_BEG]\n",
					&len, strlen("[HIDDEN_BEG]\n"));
			int x, y;
			for (x = 0; x < data->hidden_m[index]->size1; x++) {
				for (y = 0; y < data->hidden_m[index]->size2; y++) {
					snprintf(buff, MAX_LAYER_NAME_LEN, "%d:%d:%f\n", x, y,
							gsl_matrix_get(data->hidden_m[index], x, y));
					ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len,
							strlen(buff));
				}
			}
			ptr = bayrepo_reallocate_buffer(ptr, (char *) "[HIDDEN_END]\n",
					&len, strlen("[HIDDEN_END]\n"));
		}
		ptr = bayrepo_reallocate_buffer(ptr, (char *) "[OUTPUT_BEG]\n", &len,
				strlen("[OUTPUT_BEG]\n"));
		int x, y;
		for (x = 0; x < data->output_m->size1; x++) {
			for (y = 0; y < data->output_m->size2; y++) {
				snprintf(buff, MAX_LAYER_NAME_LEN, "%d:%d:%f\n", x, y,
						gsl_matrix_get(data->output_m, x, y));
				ptr = bayrepo_reallocate_buffer(ptr, (char *) buff, &len,
						strlen(buff));
			}
		}
		ptr = bayrepo_reallocate_buffer(ptr, (char *) "[OUTPUT_END]\n", &len,
				strlen("[OUTPUT_END]\n"));
		*buffer = ptr;
		return len;
	}
	return 0;
}

void *bayrepo_restore_buffer(char *buffer, int buffer_len) {
	FILE *fp = fmemopen((void*) buffer, buffer_len, "r");
	int input_l = 0;
	int output_l = 0;
	int hidden_l = 0;
	int numb_of_hidden = 0;
	activation act = RELU;
	int act_beg = 0;
	double alpha = 0.0;
	void *blob = NULL;
	int is_hidden = 0;
	int hidden_index = 0;
	int is_out = 0;
	if (fp) {
		char result_buf[MAX_BUFFER_LEN];
		int counter = 0;

		while (!feof(fp)) {
			if (fgets(result_buf, MAX_BUFFER_LEN, fp)) {
				switch (counter) {
				case 0: {
					result_buf[strlen(result_buf) - 1] = 0;
					input_l = atoi(result_buf);
				}
					break;
				case 1: {
					result_buf[strlen(result_buf) - 1] = 0;
					output_l = atoi(result_buf);
				}
					break;
				case 2: {
					result_buf[strlen(result_buf) - 1] = 0;
					hidden_l = atoi(result_buf);
				}
					break;
				case 3: {
					result_buf[strlen(result_buf) - 1] = 0;
					numb_of_hidden = atoi(result_buf);
				}
					break;
				case 4: {
					char *tptr;
					result_buf[strlen(result_buf) - 1] = 0;
					alpha = strtod(result_buf, &tptr);
				}
					break;
				case 5: {
					result_buf[strlen(result_buf) - 1] = 0;
					act = (activation) atoi(result_buf);
					if (input_l > 0 && output_l > 0 && hidden_l >= 0
							&& numb_of_hidden >= 0 && alpha > 0.0) {
						blob = bayrepo_init_neuro(input_l, output_l, hidden_l,
								numb_of_hidden, alpha, act);
					}
				}
					break;
				default: {
					if (!blob)
						return NULL;
					if (strstr(result_buf, "[ACTBEG]")) {
						act_beg = 1;
					} else if (strstr(result_buf, "[ACTEND]")) {
						act_beg = 0;
					} else if (act_beg) {
						result_buf[strlen(result_buf) - 1] = 0;
						char *ptr = strchr(result_buf, ':');
						if (ptr) {
							*ptr = 0;
							ptr++;
							int ly = atoi(result_buf);
							int ac = atoi(ptr);
							bayrepo_set_layer_activ(blob, ly, (activation) ac);
						}
					} else if (strstr(result_buf, "[HIDDEN_BEG]")) {
						is_hidden = 1;
					} else if (strstr(result_buf, "[HIDDEN_END]")) {
						hidden_index++;
						is_hidden = 0;
					} else if (is_hidden) {
						result_buf[strlen(result_buf) - 1] = 0;
						char *ptr1 = strchr(result_buf, ':');
						if (ptr1) {
							*ptr1 = 0;
							ptr1++;
							char *ptr2 = strchr(ptr1, ':');
							if (ptr2) {
								*ptr2 = 0;
								ptr2++;
								char *tptr = NULL;
								int x = atoi(result_buf);
								int y = atoi(ptr1);
								double vl = strtod(ptr2, &tptr);
								bayrepo_fill_hidden(blob, hidden_index, x, y,
										vl);
							}
						}
					} else if (strstr(result_buf, "[OUTPUT_BEG]")) {
						is_out = 1;
					} else if (strstr(result_buf, "[OUTPUT_END]")) {
						hidden_index++;
						is_out = 0;
					} else if (is_out) {
						result_buf[strlen(result_buf) - 1] = 0;
						char *ptr1 = strchr(result_buf, ':');
						if (ptr1) {
							*ptr1 = 0;
							ptr1++;
							char *ptr2 = strchr(ptr1, ':');
							if (ptr2) {
								*ptr2 = 0;
								ptr2++;
								char *tptr = NULL;
								int x = atoi(result_buf);
								int y = atoi(ptr1);
								double vl = strtod(ptr2, &tptr);
								bayrepo_fill_outm(blob, x, y, vl);
							}
						}
					}
				}
				}
			}
			counter++;
		}
		return blob;

	}
	return NULL;
}


/*
 * Copyright 2020 Makani Technologies LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// The GSL extra library provides linear algebra functions using a
// similar interface to the rest of the GSL library.

#ifndef COMMON_C_MATH_GSL_LINALG_EXTRA_H_
#define COMMON_C_MATH_GSL_LINALG_EXTRA_H_

#include <stdint.h>

#include <gsl/gsl_blas_types.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>

#ifdef __cplusplus
extern "C" {
#endif

int32_t GslTriangularSolve(CBLAS_SIDE_t side, CBLAS_UPLO_t uplo,
                           CBLAS_TRANSPOSE_t transpose, const gsl_matrix *T,
                           const gsl_matrix *B, gsl_matrix *X);
void GslTrapezoidalToTriangular(const gsl_matrix *R, gsl_matrix *T,
                                gsl_vector *tau);
void GslTrapezoidalToTriangularZTMat(const gsl_matrix *T, const gsl_vector *tau,
                                     const gsl_matrix *X, gsl_matrix *Zt_X);
int32_t GslMatrixDivide(CBLAS_SIDE_t side, const gsl_matrix *A,
                        const gsl_matrix *B, gsl_matrix *X);

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  // COMMON_C_MATH_GSL_LINALG_EXTRA_H_


#pragma once

#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>

#include <cmocka.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>

/* A very small number */
#define EPSILON 1.0e-16

#ifdef DOXYGEN
/**
 * @brief Assert that the two given doubles are equal to within tolerance.
 *
 * The function prints an error message to standard error and terminates the
 * test by calling fail() if the doubles are not equal to within tolerance.
 *
 * @param[in]  a    The first double to compare.
 *
 * @param[in]  b    The double to compare against the first one.
 *
 * @param[in]  eps  The double tolerance value.
 */
void assert_double_equal(double a, double b, double eps);
#else
#define assert_double_equal(a, b, eps) \
    _assert_double_equal(a, b, eps, __FILE__, __LINE__)
#endif

#ifdef DOXYGEN
/**
 * @brief Assert that the two given doubles are not equal to within tolerance.
 *
 * The function prints an error message to standard error and terminates the
 * test by calling fail() if the doubles are equal to within tolerance.
 *
 * @param[in]  a    The first double to compare.
 *
 * @param[in]  b    The double to compare against the first one.
 *
 * @param[in]  eps  The double tolerance value.
 *
 * @see assert_double_equal()
 */
void assert_double_not_equal(double a, double b, double eps);
#else
#define assert_double_not_equal(a, b, eps) \
    _assert_double_not_equal(a, b, eps, __FILE__, __LINE__)
#endif

#ifdef DOXYGEN
/**
 * @brief Assert that the two given GSL vectors are equal.
 *
 * The function prints an error message to standard error and terminates the
 * test by calling fail() if the vectors are not equal to within tolerance.
 *
 * @param[in]  a    The first GSL vector to compare.
 *
 * @param[in]  b    The GSL vector to compare against the first one.
 *
 * @param[in]  eps  The double tolerance value.
 *
 * @see assert_gsl_vector_equal()
 */
void assert_gsl_vector_equal(gsl_vector *a, gsl_vector *b, double eps);
#else
#define assert_gsl_vector_equal(a, b, eps) \
    _assert_gsl_vector_equal(a, b, eps, __FILE__, __LINE__)
#endif

#ifdef DOXYGEN
/**
 * @brief Assert that the two given GSL matrices are equal.
 *
 * The function prints an error message to standard error and terminates the
 * test by calling fail() if the matrices are not equal to within tolerance.
 *
 * @param[in]  a    The first GSL matrix to compare.
 *
 * @param[in]  b    The GSL matrix to compare against the first one.
 *
 * @param[in]  eps  The double tolerance value.
 *
 * @see assert_gsl_matrix_equal()
 */
void assert_gsl_matrix_equal(gsl_matrix *a, gsl_matrix *b, double eps);
#else
#define assert_gsl_matrix_equal(a, b, eps) \
    _assert_gsl_matrix_equal(a, b, eps, __FILE__, __LINE__)
#endif

void _assert_double_equal(const double a, const double b, const double eps,
                          const char* const file, const int line);

void _assert_double_not_equal(const double a, const double b, const double eps,
                              const char* const file, const int line);

void _assert_gsl_vector_equal(const gsl_vector *a, const gsl_vector *b, double eps,
			      const char* const file, const int line);

void _assert_gsl_matrix_equal(const gsl_matrix *a, const gsl_matrix *b, double eps,
			      const char* const file, const int line);


/* rng/ranlux.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

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

/* This is a lagged fibonacci generator with skipping developed by Luescher.
   The sequence is a series of 24-bit integers, x_n,

   x_n = d_n + b_n

   where d_n = x_{n-10} - x_{n-24} - c_{n-1}, b_n = 0 if d_n >= 0 and
   b_n = 2^24 if d_n < 0, c_n = 0 if d_n >= 0 and c_n = 1 if d_n < 0,
   where after 24 samples a group of p integers are "skipped", to
   reduce correlations. By default p = 199, but can be increased to
   365.

   The period of the generator is around 10^171.

   From: M. Luescher, "A portable high-quality random number generator
   for lattice field theory calculations", Computer Physics
   Communications, 79 (1994) 100-110.

   Available on the net as hep-lat/9309020 at http://xxx.lanl.gov/

   See also,

   F. James, "RANLUX: A Fortran implementation of the high-quality
   pseudo-random number generator of Luscher", Computer Physics
   Communications, 79 (1994) 111-114

   Kenneth G. Hamilton, F. James, "Acceleration of RANLUX", Computer
   Physics Communications, 101 (1997) 241-248

   Kenneth G. Hamilton, "Assembler RANLUX for PCs", Computer Physics
   Communications, 101 (1997) 249-253  */

static inline unsigned long int ranlux_get (void *vstate);
static double ranlux_get_double (void *vstate);
static void ranlux_set_lux (void *state, unsigned long int s, unsigned int luxury);
static void ranlux_set (void *state, unsigned long int s);
static void ranlux389_set (void *state, unsigned long int s);

static const unsigned long int mask_lo = 0x00ffffffUL;	/* 2^24 - 1 */
static const unsigned long int mask_hi = ~0x00ffffffUL;
static const unsigned long int two24 = 16777216;	/* 2^24 */

typedef struct
  {
    unsigned int i;
    unsigned int j;
    unsigned int n;
    unsigned int skip;
    unsigned int carry;
    unsigned long int u[24];
  }
ranlux_state_t;

static inline unsigned long int increment_state (ranlux_state_t * state);

static inline unsigned long int
increment_state (ranlux_state_t * state)
{
  unsigned int i = state->i;
  unsigned int j = state->j;
  long int delta = state->u[j] - state->u[i] - state->carry;

  if (delta & mask_hi)
    {
      state->carry = 1;
      delta &= mask_lo;
    }
  else
    {
      state->carry = 0;
    }

  state->u[i] = delta;

  if (i == 0)
    {
      i = 23;
    }
  else
    {
      i--;
    }

  state->i = i;

  if (j == 0)
    {
      j = 23;
    }
  else
    {
      j--;
    }

  state->j = j;

  return delta;
}

static inline unsigned long int
ranlux_get (void *vstate)
{
  ranlux_state_t *state = (ranlux_state_t *) vstate;
  const unsigned int skip = state->skip;
  unsigned long int r = increment_state (state);

  state->n++;

  if (state->n == 24)
    {
      unsigned int i;
      state->n = 0;
      for (i = 0; i < skip; i++)
	increment_state (state);
    }

  return r;
}

static double
ranlux_get_double (void *vstate)
{
  return ranlux_get (vstate) / 16777216.0;
}

static void
ranlux_set_lux (void *vstate, unsigned long int s, unsigned int luxury)
{
  ranlux_state_t *state = (ranlux_state_t *) vstate;
  int i;

  long int seed;

  if (s == 0)
    s = 314159265;	/* default seed is 314159265 */

  seed = s;

  /* This is the initialization algorithm of F. James, widely in use
     for RANLUX. */

  for (i = 0; i < 24; i++)
    {
      unsigned long int k = seed / 53668;
      seed = 40014 * (seed - k * 53668) - k * 12211;
      if (seed < 0)
	{
	  seed += 2147483563;
	}
      state->u[i] = seed % two24;
    }

  state->i = 23;
  state->j = 9;
  state->n = 0;
  state->skip = luxury - 24;

  if (state->u[23] & mask_hi)
    {
      state->carry = 1;
    }
  else
    {
      state->carry = 0;
    }
}

static void
ranlux_set (void *vstate, unsigned long int s)
{
  ranlux_set_lux (vstate, s, 223);
}

static void
ranlux389_set (void *vstate, unsigned long int s)
{
  ranlux_set_lux (vstate, s, 389);
}

static const gsl_rng_type ranlux_type =
{"ranlux",			/* name */
 0x00ffffffUL,			/* RAND_MAX */
 0,				/* RAND_MIN */
 sizeof (ranlux_state_t),
 &ranlux_set,
 &ranlux_get,
 &ranlux_get_double};

static const gsl_rng_type ranlux389_type =
{"ranlux389",			/* name */
 0x00ffffffUL,			/* RAND_MAX */
 0,				/* RAND_MIN */
 sizeof (ranlux_state_t),
 &ranlux389_set,
 &ranlux_get,
 &ranlux_get_double};

const gsl_rng_type *gsl_rng_ranlux = &ranlux_type;
const gsl_rng_type *gsl_rng_ranlux389 = &ranlux389_type;


/* blas/gsl_blas.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 *
 * 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.
 */

/*
 * Author:  G. Jungman
 */
#ifndef __GSL_BLAS_H__
#define __GSL_BLAS_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 <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>

#include <gsl/gsl_blas_types.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

/* ========================================================================
 * Level 1
 * ========================================================================
 */

GSL_FUN int gsl_blas_sdsdot (float alpha,
                     const gsl_vector_float * X,
                     const gsl_vector_float * Y,
                     float * result
                     );

GSL_FUN int gsl_blas_dsdot (const gsl_vector_float * X,
                    const gsl_vector_float * Y,
                    double * result
                    );

GSL_FUN int gsl_blas_sdot (const gsl_vector_float * X,
                   const gsl_vector_float * Y,
                   float * result
                   );

GSL_FUN int gsl_blas_ddot (const gsl_vector * X,
                   const gsl_vector * Y,
                   double * result
                   );

GSL_FUN int  gsl_blas_cdotu (const gsl_vector_complex_float * X,
                     const gsl_vector_complex_float * Y,
                     gsl_complex_float * dotu);

GSL_FUN int  gsl_blas_cdotc (const gsl_vector_complex_float * X,
                     const gsl_vector_complex_float * Y,
                     gsl_complex_float * dotc);

GSL_FUN int  gsl_blas_zdotu (const gsl_vector_complex * X,
                     const gsl_vector_complex * Y,
                     gsl_complex * dotu);

GSL_FUN int  gsl_blas_zdotc (const gsl_vector_complex * X,
                     const gsl_vector_complex * Y,
                     gsl_complex * dotc);

GSL_FUN float  gsl_blas_snrm2  (const gsl_vector_float * X);
GSL_FUN float  gsl_blas_sasum  (const gsl_vector_float * X);
GSL_FUN double gsl_blas_dnrm2  (const gsl_vector * X);
GSL_FUN double gsl_blas_dasum  (const gsl_vector * X);
GSL_FUN float  gsl_blas_scnrm2 (const gsl_vector_complex_float * X);
GSL_FUN float  gsl_blas_scasum (const gsl_vector_complex_float * X);
GSL_FUN double gsl_blas_dznrm2 (const gsl_vector_complex * X);
GSL_FUN double gsl_blas_dzasum (const gsl_vector_complex * X);

GSL_FUN CBLAS_INDEX_t gsl_blas_isamax (const gsl_vector_float * X);
GSL_FUN CBLAS_INDEX_t gsl_blas_idamax (const gsl_vector * X);
GSL_FUN CBLAS_INDEX_t gsl_blas_icamax (const gsl_vector_complex_float * X);
GSL_FUN CBLAS_INDEX_t gsl_blas_izamax (const gsl_vector_complex * X);

GSL_FUN int  gsl_blas_sswap (gsl_vector_float * X,
                     gsl_vector_float * Y);

GSL_FUN int  gsl_blas_scopy (const gsl_vector_float * X,
                     gsl_vector_float * Y);

GSL_FUN int  gsl_blas_saxpy (float alpha,
                     const gsl_vector_float * X,
                     gsl_vector_float * Y);

GSL_FUN int  gsl_blas_dswap (gsl_vector * X,
                     gsl_vector * Y);

GSL_FUN int  gsl_blas_dcopy (const gsl_vector * X,
                     gsl_vector * Y);

GSL_FUN int  gsl_blas_daxpy (double alpha,
                     const gsl_vector * X,
                     gsl_vector * Y);

GSL_FUN int  gsl_blas_cswap (gsl_vector_complex_float * X,
                     gsl_vector_complex_float * Y);

GSL_FUN int  gsl_blas_ccopy (const gsl_vector_complex_float * X,
                     gsl_vector_complex_float * Y);

GSL_FUN int  gsl_blas_caxpy (const gsl_complex_float alpha,
                     const gsl_vector_complex_float * X,
                     gsl_vector_complex_float * Y);

GSL_FUN int  gsl_blas_zswap (gsl_vector_complex * X,
                     gsl_vector_complex * Y);

GSL_FUN int  gsl_blas_zcopy (const gsl_vector_complex * X,
                     gsl_vector_complex * Y);

GSL_FUN int  gsl_blas_zaxpy (const gsl_complex alpha,
                     const gsl_vector_complex * X,
                     gsl_vector_complex * Y);

GSL_FUN int  gsl_blas_srotg (float a[], float b[], float c[], float s[]);

GSL_FUN int  gsl_blas_srotmg (float d1[], float d2[], float b1[], float b2, float P[]);

GSL_FUN int  gsl_blas_srot (gsl_vector_float * X,
                    gsl_vector_float * Y,
                    float c, float s);

GSL_FUN int  gsl_blas_srotm (gsl_vector_float * X,
                     gsl_vector_float * Y,
                     const float P[]);

GSL_FUN int  gsl_blas_drotg (double a[], double b[], double c[], double s[]);

GSL_FUN int  gsl_blas_drotmg (double d1[], double d2[], double b1[],
                      double b2, double P[]);

GSL_FUN int  gsl_blas_drot (gsl_vector * X,
                    gsl_vector * Y,
                    const double c, const double s);

GSL_FUN int  gsl_blas_drotm (gsl_vector * X,
                     gsl_vector * Y,
                     const double P[]);

GSL_FUN void gsl_blas_sscal  (float  alpha, gsl_vector_float * X);
GSL_FUN void gsl_blas_dscal  (double alpha, gsl_vector * X);
GSL_FUN void gsl_blas_cscal  (const gsl_complex_float alpha, gsl_vector_complex_float * X);
GSL_FUN void gsl_blas_zscal  (const gsl_complex alpha, gsl_vector_complex * X);
GSL_FUN void gsl_blas_csscal (float  alpha, gsl_vector_complex_float * X);
GSL_FUN void gsl_blas_zdscal (double alpha, gsl_vector_complex * X);

/* ===========================================================================
 * Level 2
 * ===========================================================================
 */

/*
 * Routines with standard 4 prefixes (S, D, C, Z)
 */
GSL_FUN int  gsl_blas_sgemv (CBLAS_TRANSPOSE_t TransA,
                     float alpha,
                     const gsl_matrix_float * A,
                     const gsl_vector_float * X,
                     float beta,
                     gsl_vector_float * Y);

GSL_FUN int  gsl_blas_strmv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_float * A,
                     gsl_vector_float * X);

GSL_FUN int  gsl_blas_strsv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_float * A,
                     gsl_vector_float * X);

GSL_FUN int  gsl_blas_dgemv (CBLAS_TRANSPOSE_t TransA,
                     double alpha,
                     const gsl_matrix * A,
                     const gsl_vector * X,
                     double beta,
                     gsl_vector * Y);

GSL_FUN int  gsl_blas_dtrmv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix * A,
                     gsl_vector * X);

GSL_FUN int  gsl_blas_dtrsv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix * A,
                     gsl_vector * X);

GSL_FUN int  gsl_blas_cgemv (CBLAS_TRANSPOSE_t TransA,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_vector_complex_float * X,
                     const gsl_complex_float beta,
                     gsl_vector_complex_float * Y);

GSL_FUN int  gsl_blas_ctrmv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_complex_float * A,
                     gsl_vector_complex_float * X);

GSL_FUN int  gsl_blas_ctrsv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_complex_float * A,
                     gsl_vector_complex_float * X);

GSL_FUN int  gsl_blas_zgemv (CBLAS_TRANSPOSE_t TransA,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_vector_complex * X,
                     const gsl_complex beta,
                     gsl_vector_complex * Y);

GSL_FUN int  gsl_blas_ztrmv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_complex * A,
                     gsl_vector_complex * X);

GSL_FUN int  gsl_blas_ztrsv (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t TransA, CBLAS_DIAG_t Diag,
                     const gsl_matrix_complex * A,
                     gsl_vector_complex *X);

/*
 * Routines with S and D prefixes only
 */
GSL_FUN int  gsl_blas_ssymv (CBLAS_UPLO_t Uplo,
                     float alpha,
                     const gsl_matrix_float * A,
                     const gsl_vector_float * X,
                     float beta,
                     gsl_vector_float * Y);

GSL_FUN int  gsl_blas_sger (float alpha,
                    const gsl_vector_float * X,
                    const gsl_vector_float * Y,
                    gsl_matrix_float * A);

GSL_FUN int  gsl_blas_ssyr (CBLAS_UPLO_t Uplo,
                    float alpha,
                    const gsl_vector_float * X,
                    gsl_matrix_float * A);

GSL_FUN int  gsl_blas_ssyr2 (CBLAS_UPLO_t Uplo,
                     float alpha,
                     const gsl_vector_float * X,
                     const gsl_vector_float * Y,
                     gsl_matrix_float * A);

GSL_FUN int  gsl_blas_dsymv (CBLAS_UPLO_t Uplo,
                     double alpha,
                     const gsl_matrix * A,
                     const gsl_vector * X,
                     double beta,
                     gsl_vector * Y);
GSL_FUN int  gsl_blas_dger (double alpha,
                    const gsl_vector * X,
                    const gsl_vector * Y,
                    gsl_matrix * A);

GSL_FUN int  gsl_blas_dsyr (CBLAS_UPLO_t Uplo,
                    double alpha,
                    const gsl_vector * X,
                    gsl_matrix * A);

GSL_FUN int  gsl_blas_dsyr2 (CBLAS_UPLO_t Uplo,
                     double alpha,
                     const gsl_vector * X,
                     const gsl_vector * Y,
                     gsl_matrix * A);

/*
 * Routines with C and Z prefixes only
 */

GSL_FUN int  gsl_blas_chemv (CBLAS_UPLO_t Uplo,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_vector_complex_float * X,
                     const gsl_complex_float beta,
                     gsl_vector_complex_float * Y);

GSL_FUN int  gsl_blas_cgeru (const gsl_complex_float alpha,
                     const gsl_vector_complex_float * X,
                     const gsl_vector_complex_float * Y,
                     gsl_matrix_complex_float * A);

GSL_FUN int  gsl_blas_cgerc (const gsl_complex_float alpha,
                     const gsl_vector_complex_float * X,
                     const gsl_vector_complex_float * Y,
                     gsl_matrix_complex_float * A);

GSL_FUN int  gsl_blas_cher (CBLAS_UPLO_t Uplo,
                    float alpha,
                    const gsl_vector_complex_float * X,
                    gsl_matrix_complex_float * A);

GSL_FUN int  gsl_blas_cher2 (CBLAS_UPLO_t Uplo,
                     const gsl_complex_float alpha,
                     const gsl_vector_complex_float * X,
                     const gsl_vector_complex_float * Y,
                     gsl_matrix_complex_float * A);

GSL_FUN int  gsl_blas_zhemv (CBLAS_UPLO_t Uplo,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_vector_complex * X,
                     const gsl_complex beta,
                     gsl_vector_complex * Y);

GSL_FUN int  gsl_blas_zgeru (const gsl_complex alpha,
                     const gsl_vector_complex * X,
                     const gsl_vector_complex * Y,
                     gsl_matrix_complex * A);

GSL_FUN int  gsl_blas_zgerc (const gsl_complex alpha,
                     const gsl_vector_complex * X,
                     const gsl_vector_complex * Y,
                     gsl_matrix_complex * A);

GSL_FUN int  gsl_blas_zher (CBLAS_UPLO_t Uplo,
                    double alpha,
                    const gsl_vector_complex * X,
                    gsl_matrix_complex * A);

GSL_FUN int  gsl_blas_zher2 (CBLAS_UPLO_t Uplo,
                     const gsl_complex alpha,
                     const gsl_vector_complex * X,
                     const gsl_vector_complex * Y,
                     gsl_matrix_complex * A);

/*
 * ===========================================================================
 * Prototypes for level 3 BLAS
 * ===========================================================================
 */

/*
 * Routines with standard 4 prefixes (S, D, C, Z)
 */
GSL_FUN int  gsl_blas_sgemm (CBLAS_TRANSPOSE_t TransA,
                     CBLAS_TRANSPOSE_t TransB,
                     float alpha,
                     const gsl_matrix_float * A,
                     const gsl_matrix_float * B,
                     float beta,
                     gsl_matrix_float * C);

GSL_FUN int  gsl_blas_ssymm (CBLAS_SIDE_t Side, CBLAS_UPLO_t Uplo,
                     float alpha,
                     const gsl_matrix_float * A,
                     const gsl_matrix_float * B,
                     float beta,
                     gsl_matrix_float * C);

GSL_FUN int  gsl_blas_ssyrk (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t Trans,
                     float alpha,
                     const gsl_matrix_float * A,
                     float beta,
                     gsl_matrix_float * C);

GSL_FUN int  gsl_blas_ssyr2k (CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t Trans,
                      float alpha,
                      const gsl_matrix_float * A,
                      const gsl_matrix_float * B,
                      float beta,
                      gsl_matrix_float * C);

GSL_FUN int  gsl_blas_strmm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     float alpha,
                     const gsl_matrix_float * A,
                     gsl_matrix_float * B);

GSL_FUN int  gsl_blas_strsm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     float alpha,
                     const gsl_matrix_float * A,
                     gsl_matrix_float * B);

GSL_FUN int  gsl_blas_dgemm (CBLAS_TRANSPOSE_t TransA,
                     CBLAS_TRANSPOSE_t TransB,
                     double alpha,
                     const gsl_matrix * A,
                     const gsl_matrix * B,
                     double beta,
                     gsl_matrix * C);

GSL_FUN int  gsl_blas_dsymm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo,
                     double alpha,
                     const gsl_matrix * A,
                     const gsl_matrix * B,
                     double beta,
                     gsl_matrix * C);

GSL_FUN int  gsl_blas_dsyrk (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t Trans,
                     double alpha,
                     const gsl_matrix * A,
                     double beta,
                     gsl_matrix * C);

GSL_FUN int  gsl_blas_dsyr2k (CBLAS_UPLO_t Uplo,
                      CBLAS_TRANSPOSE_t Trans,
                      double alpha,
                      const  gsl_matrix * A,
                      const  gsl_matrix * B,
                      double beta,
                      gsl_matrix * C);

GSL_FUN int  gsl_blas_dtrmm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     double alpha,
                     const gsl_matrix * A,
                     gsl_matrix * B);

GSL_FUN int  gsl_blas_dtrsm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     double alpha,
                     const gsl_matrix * A,
                     gsl_matrix * B);

GSL_FUN int  gsl_blas_cgemm (CBLAS_TRANSPOSE_t TransA,
                     CBLAS_TRANSPOSE_t TransB,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_matrix_complex_float * B,
                     const gsl_complex_float beta,
                     gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_csymm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_matrix_complex_float * B,
                     const gsl_complex_float beta,
                     gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_csyrk (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t Trans,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_complex_float beta,
                     gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_csyr2k (CBLAS_UPLO_t Uplo,
                      CBLAS_TRANSPOSE_t Trans,
                      const gsl_complex_float alpha,
                      const gsl_matrix_complex_float * A,
                      const gsl_matrix_complex_float * B,
                      const gsl_complex_float beta,
                      gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_ctrmm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     gsl_matrix_complex_float * B);

GSL_FUN int  gsl_blas_ctrsm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     gsl_matrix_complex_float * B);

GSL_FUN int  gsl_blas_zgemm (CBLAS_TRANSPOSE_t TransA,
                     CBLAS_TRANSPOSE_t TransB,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_matrix_complex * B,
                     const gsl_complex beta,
                     gsl_matrix_complex * C);

GSL_FUN int  gsl_blas_zsymm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_matrix_complex * B,
                     const gsl_complex beta,
                     gsl_matrix_complex * C);

GSL_FUN int  gsl_blas_zsyrk (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t Trans,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_complex beta,
                     gsl_matrix_complex * C);

GSL_FUN int  gsl_blas_zsyr2k (CBLAS_UPLO_t Uplo,
                      CBLAS_TRANSPOSE_t Trans,
                      const gsl_complex alpha,
                      const gsl_matrix_complex * A,
                      const gsl_matrix_complex * B,
                      const gsl_complex beta,
                      gsl_matrix_complex *C);

GSL_FUN int  gsl_blas_ztrmm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     gsl_matrix_complex * B);

GSL_FUN int  gsl_blas_ztrsm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo, CBLAS_TRANSPOSE_t TransA,
                     CBLAS_DIAG_t Diag,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     gsl_matrix_complex * B);

/*
 * Routines with prefixes C and Z only
 */
GSL_FUN int  gsl_blas_chemm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo,
                     const gsl_complex_float alpha,
                     const gsl_matrix_complex_float * A,
                     const gsl_matrix_complex_float * B,
                     const gsl_complex_float beta,
                     gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_cherk (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t Trans,
                     float alpha,
                     const gsl_matrix_complex_float * A,
                     float beta,
                     gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_cher2k (CBLAS_UPLO_t Uplo,
                      CBLAS_TRANSPOSE_t Trans,
                      const gsl_complex_float alpha,
                      const gsl_matrix_complex_float * A,
                      const gsl_matrix_complex_float * B,
                      float beta,
                      gsl_matrix_complex_float * C);

GSL_FUN int  gsl_blas_zhemm (CBLAS_SIDE_t Side,
                     CBLAS_UPLO_t Uplo,
                     const gsl_complex alpha,
                     const gsl_matrix_complex * A,
                     const gsl_matrix_complex * B,
                     const gsl_complex beta,
                     gsl_matrix_complex * C);

GSL_FUN int  gsl_blas_zherk (CBLAS_UPLO_t Uplo,
                     CBLAS_TRANSPOSE_t Trans,
                     double alpha,
                     const gsl_matrix_complex * A,
                     double beta,
                     gsl_matrix_complex * C);

GSL_FUN int  gsl_blas_zher2k (CBLAS_UPLO_t Uplo,
                      CBLAS_TRANSPOSE_t Trans,
                      const gsl_complex alpha,
                      const gsl_matrix_complex * A,
                      const gsl_matrix_complex * B,
                      double beta,
                      gsl_matrix_complex * C);

__END_DECLS

#endif /* __GSL_BLAS_H__ */


/*
GENETIC - A simple genetic algorithm.

Copyright 2014, Javier Burguete Tolosa.

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.

THIS SOFTWARE IS PROVIDED BY Javier Burguete Tolosa ``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 Javier Burguete Tolosa 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.
*/

/**
 * \file test_genetic.c
 * \brief Source file to test the genetic algorithm functions.
 * \author Javier Burguete Tolosa.
 * \copyright Copyright 2014 Javier Burguete Tolosa. All rights reserved.
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <glib.h>
#if HAVE_MPI
#include <mpi.h>
#endif
#include "entity.h"
#include "population.h"
#include "reproduction.h"
#include "selection.h"
#include "evolution.h"
#include "genetic.h"

int ntasks = 1;                 ///< Number of tasks.
unsigned int nthreads = 1;      ///< Number of threads.
GMutex mutex[1];                ///< Mutex to lock memory writing on threads.
GeneticVariable v[2];           ///< Array of variables to optimize.

/**
 * Evaluation function.
 *
 * \return RMSE error on the linear equations system: x+y=3, x-y=1.
 */
double
evaluate (Entity * entity)      ///< Entity to simulate.
{
  double x, y, e1, e2;
  x = genetic_get_variable (entity, v);
  y = genetic_get_variable (entity, v + 1);
  e1 = x + y - 3.;
  e2 = x - y - 1.;
  e1 = e1 * e1 + e2 * e2;
  return e1;
}

/**
 * Main function.
 *
 * \return 0 always.
 */
int
main (int argn                  ///< Number of arguments.
#if !HAVE_MPI
      __attribute__ ((unused))
#endif
      ,
      char **argc               ///< Array of argument strings.
#if !HAVE_MPI
      __attribute__ ((unused))
#endif
     )
{
  int rank;
  char *best_genome;
  double *best_variables, best_objective;
#if HAVE_MPI
  MPI_Init (&argn, &argc);
  MPI_Comm_size (MPI_COMM_WORLD, &ntasks);
  MPI_Comm_rank (MPI_COMM_WORLD, &rank);
#else
  rank = 0;
#endif
  nthreads = 4;
  v[0].maximum = 10.;
  v[0].minimum = -10.;
  v[0].nbits = 16;
  v[1].maximum = 10.;
  v[1].minimum = -10.;
  v[1].nbits = 16;
  genetic_algorithm_default (2,
                             v,
                             100,
                             20,
                             0.3,
                             0.4,
                             0.1,
                             707l,
                             0.0,
                             &evaluate,
                             &best_genome, &best_variables, &best_objective);
  if (rank == 0)
    {
      printf ("x=%lg y=%lg error=%lg\n",
              best_variables[0], best_variables[1], best_objective);
      g_free (best_genome);
      g_free (best_variables);
    }
#if HAVE_MPI
  MPI_Finalize ();
#endif
  return 0;
}


/* this program is in the public domain */

#include "bench-user.h"
#include <math.h>

#ifdef HAVE_GSL_GSL_VERSION_H
#include <gsl/gsl_version.h>
#endif

static const char *mkvers(void)
{
#ifdef HAVE_GSL_GSL_VERSION_H
     return gsl_version;
#else
     return "unknown"
#endif
}

BEGIN_BENCH_DOC
BENCH_DOC("name", "gsl-mixed-radix")
BENCH_DOC("package", "GNU Scientific Library (GSL)")
BENCH_DOC("author", "Brian Gough")
BENCH_DOC("year", "2002")
BENCH_DOC("url", "http://sources.redhat.com/gsl")
BENCH_DOC("url-was-valid-on", "Thu Jul 26 07:48:45 EDT 2001")
BENCH_DOC("copyright",
  "Copyright (C) 1996, 1997, 1998, 1999, 2000 Brian Gough\n"
  "\n"
  "This program is free software; you can redistribute it and/or modify\n"
  "it under the terms of the GNU General Public License as published by\n"
  "the Free Software Foundation; either version 2 of the License, or (at\n"
  "your option) any later version.\n")
BENCH_DOC("language", "C")
BENCH_DOCF("version", mkvers)
END_BENCH_DOC

#ifdef BENCHFFT_SINGLE
#include <gsl/gsl_fft_complex_float.h>
#include <gsl/gsl_fft_real_float.h>
#include <gsl/gsl_fft_halfcomplex_float.h>
#define C(x) gsl_fft_complex_float_##x
#define CWv(x) gsl_fft_complex_wavetable_float_##x
#define CWk(x) gsl_fft_complex_workspace_float_##x
#define R(x) gsl_fft_real_float_##x
#define RWv(x) gsl_fft_real_wavetable_float_##x
#define RWk(x) gsl_fft_real_workspace_float_##x
#define H(x) gsl_fft_halfcomplex_float_##x
#define HWv(x) gsl_fft_halfcomplex_wavetable_float_##x
#else
#include <gsl/gsl_fft_complex.h>
#include <gsl/gsl_fft_real.h>
#include <gsl/gsl_fft_halfcomplex.h>
#define C(x) gsl_fft_complex_##x
#define CWv(x) gsl_fft_complex_wavetable_##x
#define CWk(x) gsl_fft_complex_workspace_##x
#define R(x) gsl_fft_real_##x
#define RWv(x) gsl_fft_real_wavetable_##x
#define RWk(x) gsl_fft_real_workspace_##x
#define H(x) gsl_fft_halfcomplex_##x
#define HWv(x) gsl_fft_halfcomplex_wavetable_##x
#endif

int can_do(struct problem *p)
{
     return (p->rank == 1 && problem_in_place(p));
}

/* fftpack-style real transforms */
void copy_h2c(struct problem *p, bench_complex *out)
{
     copy_h2c_1d_fftpack(p, out, -1.0);
}

void copy_c2h(struct problem *p, bench_complex *in)
{
     copy_c2h_1d_fftpack(p, in, -1.0);
}

static void *Wv = 0, *Wk = 0;

void setup(struct problem *p)
{
     int n;

     BENCH_ASSERT(can_do(p));
     n = p->n[0];

     if (p->kind == PROBLEM_COMPLEX) {
	  Wv = CWv(alloc)(n);
	  Wk = CWk(alloc)(n);
     } else {
	  if (p->sign == -1)
	       Wv = RWv(alloc)(n);
	  else
	       Wv = HWv(alloc)(n);
	  Wk = RWk(alloc)(n);
     }
}

void doit(int iter, struct problem *p)
{
     int i;
     int n = p->n[0];
     void *in = p->in;
     void *wv = Wv, *wk = Wk;

     if (p->kind == PROBLEM_COMPLEX) {
	  if (p->sign == -1) {
	    for (i = 0; i < iter; ++i)
		 C(forward)(in, 1, n, wv, wk);
	  } else {
	    for (i = 0; i < iter; ++i)
		 C(backward)(in, 1, n, wv, wk);
	  }
     } else {
	  if (p->sign == -1) {
	    for (i = 0; i < iter; ++i)
		 R(transform)(in, 1, n, wv, wk);
	  } else {
	    for (i = 0; i < iter; ++i)
		 H(transform)(in, 1, n, wv, wk);
	  }
     }
}

void done(struct problem *p)
{
     UNUSED(p);
     if (p->kind == PROBLEM_COMPLEX) {
	  CWv(free)(Wv);
     } else {
	  if (p->sign == -1)
	       RWv(free)(Wv);
	  else
	       HWv(free)(Wv);
	  RWk(free)(Wk);
     }
}