/**
* Copyright 2016 BitTorrent Inc.
*
* 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.
*/
#pragma once

#include <scraps/config.h>

#include <scraps/Byte.h>

#if SCRAPS_APPLE
    #include <scraps/apple/SHA256.h>
    namespace scraps { using SHA256 = apple::SHA256; }
#else
    #include <scraps/sodium/SHA256.h>
    namespace scraps { using SHA256 = sodium::SHA256; }
#endif

#include <gsl.h>

namespace scraps {

template <typename BaseByteType>
struct SHA256ByteTag {};

template <typename BaseByteType>
using SHA256Byte = StrongByte<SHA256ByteTag<BaseByteType>>;

template <typename ByteT, std::ptrdiff_t N>
std::array<SHA256Byte<std::remove_const_t<ByteT>>, SHA256::kHashSize>
GetSHA256(gsl::span<ByteT, N> data) {
    std::array<SHA256Byte<std::remove_const_t<ByteT>>, SHA256::kHashSize> ret;

    SHA256 sha256;
    sha256.update(data.data(), data.size());
    sha256.finish(ret.data());

    return ret;
}

} // namespace scraps


/* permutation/gsl_permutation.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 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.
 */

#ifndef __GSL_PERMUTATION_H__
#define __GSL_PERMUTATION_H__

#include <stdlib.h>
#include <gsl/gsl_errno.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

struct gsl_permutation_struct
{
  size_t size;
  size_t *data;
};

typedef struct gsl_permutation_struct gsl_permutation;

gsl_permutation *gsl_permutation_alloc (const size_t n);
gsl_permutation *gsl_permutation_calloc (const size_t n);
void gsl_permutation_init (gsl_permutation * p);
void gsl_permutation_free (gsl_permutation * p);

int gsl_permutation_fread (FILE * stream, gsl_permutation * p);
int gsl_permutation_fwrite (FILE * stream, const gsl_permutation * p);
int gsl_permutation_fscanf (FILE * stream, gsl_permutation * p);
int gsl_permutation_fprintf (FILE * stream, const gsl_permutation * p, const char *format);

size_t gsl_permutation_size (const gsl_permutation * p);
size_t * gsl_permutation_data (const gsl_permutation * p);

size_t gsl_permutation_get (const gsl_permutation * p, const size_t i);
int gsl_permutation_swap (gsl_permutation * p, const size_t i, const size_t j);

int gsl_permutation_valid (gsl_permutation * p);
void gsl_permutation_reverse (gsl_permutation * p);
int gsl_permutation_inverse (gsl_permutation * inv, const gsl_permutation * p);
int gsl_permutation_next (gsl_permutation * p);
int gsl_permutation_prev (gsl_permutation * p);

extern int gsl_check_range;

#ifdef HAVE_INLINE

extern inline
size_t
gsl_permutation_get (const gsl_permutation * p, const size_t i)
{
#ifndef GSL_RANGE_CHECK_OFF
  if (i >= p->size)
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return p->data[i];
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_PERMUTATION_H__ */


/*
Copyright (c) 2011-2013, UT-Battelle, LLC
All rights reserved

[PsimagLite, Version 1.0.0]
[by G.A., Oak Ridge National Laboratory]

UT Battelle Open Source Software License 11242008

OPEN SOURCE LICENSE

Subject to the conditions of this License, each
contributor to this software hereby grants, free of
charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), a
perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable copyright license to use, copy,
modify, merge, publish, distribute, and/or sublicense
copies of the Software.

1. Redistributions of Software must retain the above
copyright and license notices, this list of conditions,
and the following disclaimer.  Changes or modifications
to, or derivative works of, the Software should be noted
with comments and the contributor and organization's
name.

2. Neither the names of UT-Battelle, LLC or the
Department of Energy nor the names of the Software
contributors may be used to endorse or promote products
derived from this software without specific prior written
permission of UT-Battelle.

3. The software and the end-user documentation included
with the redistribution, with or without modification,
must include the following acknowledgment:

"This product includes software produced by UT-Battelle,
LLC under Contract No. DE-AC05-00OR22725  with the
Department of Energy."

*********************************************************
DISCLAIMER

THE SOFTWARE IS SUPPLIED BY THE COPYRIGHT HOLDERS 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
COPYRIGHT OWNER, CONTRIBUTORS, UNITED STATES GOVERNMENT,
OR THE UNITED STATES DEPARTMENT OF ENERGY 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.

NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED
STATES DEPARTMENT OF ENERGY, NOR THE COPYRIGHT OWNER, NOR
ANY OF THEIR EMPLOYEES, REPRESENTS THAT THE USE OF ANY
INFORMATION, DATA, APPARATUS, PRODUCT, OR PROCESS
DISCLOSED WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS.

*********************************************************

*/
/** \ingroup PsimagLite */
/*@{*/

/*! \file GslWrapper.h
 *
 *  Wrapper for GSL functions and types
 */

#ifndef GSL_WRAPPER_H_
#define GSL_WRAPPER_H_

#ifdef USE_GSL
#include <gsl/gsl_integration.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_sf_result.h>
#include <gsl/gsl_sf_gamma.h>
#include <gsl/gsl_sf_expint.h>
#endif

#include <stdexcept>
#include "Vector.h"

namespace PsimagLite {

#ifndef USE_GSL
class GslWrapper {
public:
	typedef int DummyType;
	typedef DummyType gsl_integration_workspace;
	typedef double (* GslWrapperFunctionType) (double, void * );
	typedef struct {
		double val;
		double err;
	} gsl_sf_result;

	typedef void (* gsl_error_handler_t) (const char *,const char *,int,int);

	struct gsl_function {
		GslWrapperFunctionType function;
		void * params;
	};

	gsl_error_handler_t  gsl_set_error_handler (gsl_error_handler_t) const
	{

		thereSnoGsl();
		gsl_error_handler_t *fx = new gsl_error_handler_t();

		return *fx;
	}

	gsl_integration_workspace * gsl_integration_workspace_alloc (SizeType) const
	{
		thereSnoGsl();
		int* x = new int;
		return x;
	}

	void gsl_integration_workspace_free (gsl_integration_workspace*) const
	{
		thereSnoGsl();
	}

	int gsl_integration_qag(const gsl_function*,
	                        double,
	                        double,
	                        double,
	                        double,
	                        size_t,
	                        int,
	                        gsl_integration_workspace*,
	                        double*,
	                        double*) const
	{
		thereSnoGsl();
		return 0;
	}

	int gsl_integration_qagiu(gsl_function*,
	                          double,
	                          double,
	                          double,
	                          size_t ,
	                          gsl_integration_workspace*,
	                          double*,
	                          double*) const
	{
		thereSnoGsl();
		return 0;
	}

	int gsl_integration_qagp (const gsl_function*,
	                          double*,
	                          SizeType,
	                          double,
	                          double,
	                          SizeType,
	                          gsl_integration_workspace*,
	                          double*,
	                          double*) const
	{
		thereSnoGsl();
		return 0;
	}

	int gsl_integration_qagi(gsl_function*,
	                         double,
	                         double,
	                         size_t,
	                         gsl_integration_workspace*,
	                         double*,
	                         double*) const
	{
		thereSnoGsl();
		return 0;
	}

	void printError(int) const
	{
		thereSnoGsl();
	}

	int gsl_sf_lngamma_complex_e(double,
	                             double,
	                             gsl_sf_result*,
	                             gsl_sf_result*) const
	{
		thereSnoGsl();
		return 0;
	}

	int gsl_sf_Ci_e(double, gsl_sf_result*)
	{
		thereSnoGsl();
		return 0;
	}

private:

	void thereSnoGsl() const
	{
		throw RuntimeError("You need to compile with the GSL\n");
	}

}; // class GslWrapper

#else

class GslWrapper {
public:

	typedef ::gsl_integration_workspace gsl_integration_workspace;
	typedef ::gsl_function gsl_function;
	typedef ::gsl_sf_result gsl_sf_result;

	void printError(int status) const
	{
		std::cerr<<"GslWrapper: error: "<<gsl_strerror(status)<<"\n";
	}

	gsl_error_handler_t * gsl_set_error_handler (gsl_error_handler_t * new_handler) const
	{
		return ::gsl_set_error_handler(new_handler);
	}

	gsl_integration_workspace * gsl_integration_workspace_alloc (SizeType n) const
	{
		return ::gsl_integration_workspace_alloc(n);
	}

	void gsl_integration_workspace_free (gsl_integration_workspace * w) const
	{
		return ::gsl_integration_workspace_free(w);
	}

	int gsl_integration_qagi(gsl_function* f,
	                         double epsabs,
	                         double epsrel,
	                         size_t limit,
	                         gsl_integration_workspace* workspace,
	                         double* result,
	                         double* abserr) const
	{
		return ::gsl_integration_qagi(f,epsabs,epsrel,limit,workspace,result,abserr);
	}

	int gsl_integration_qagiu(gsl_function* f,
	                          double a,
	                          double epsabs,
	                          double epsrel,
	                          size_t limit,
	                          gsl_integration_workspace* workspace,
	                          double* result,
	                          double* abserr) const
	{
		return ::gsl_integration_qagiu(f,a,epsabs,epsrel,limit,workspace,result,abserr);
	}

	int gsl_integration_qagp (const gsl_function * f,
	                          double * pts,
	                          SizeType npts,
	                          double epsabs,
	                          double epsrel,
	                          SizeType limit,
	                          gsl_integration_workspace * workspace,
	                          double * result,
	                          double * abserr) const
	{
		return ::gsl_integration_qagp(f,
		                              pts,
		                              npts,
		                              epsabs,
		                              epsrel,
		                              limit,
		                              workspace,
		                              result,
		                              abserr);
	}

	int gsl_integration_qag(const gsl_function * f,
	                        double a,
	                        double b,
	                        double epsabs,
	                        double epsrel,
	                        size_t limit,
	                        int key,
	                        gsl_integration_workspace* workspace,
	                        double* result,
	                        double* abserr) const
	{
		return ::gsl_integration_qag(f,
		                             a,
		                             b,
		                             epsabs,
		                             epsrel,
		                             limit,
		                             key,
		                             workspace,
		                             result,
		                             abserr);
	}

	int gsl_sf_lngamma_complex_e(double zr,
	                             double zi,
	                             gsl_sf_result* lnr,
	                             gsl_sf_result* arg) const
	{
		return ::gsl_sf_lngamma_complex_e(zr, zi, lnr, arg);
	}

	int gsl_sf_Ci_e(double x, gsl_sf_result* result) const
	{
		return ::gsl_sf_Ci_e(x,result);
	}

}; // class GslWrapper

#endif

} // namespace PsimagLite

/*@}*/
#endif // GSL_WRAPPER_H_


#include <gsl/gsl_math.h>
#include "gsl_cblas.h"
#include "cblas.h"

void
cblas_cswap (const int N, void *X, const int incX, void *Y, const int incY)
{
#define BASE float
#include "source_swap_c.h"
#undef BASE
}


/* matrix/gsl_matrix_long.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef __GSL_MATRIX_LONG_H__
#define __GSL_MATRIX_LONG_H__

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_long.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 * data;
  gsl_block_long * block;
  int owner;
} gsl_matrix_long;

typedef struct
{
  gsl_matrix_long matrix;
} _gsl_matrix_long_view;

typedef _gsl_matrix_long_view gsl_matrix_long_view;

typedef struct
{
  gsl_matrix_long matrix;
} _gsl_matrix_long_const_view;

typedef const _gsl_matrix_long_const_view gsl_matrix_long_const_view;

/* Allocation */

GSL_EXPORT
gsl_matrix_long *
gsl_matrix_long_alloc (const size_t n1, const size_t n2);

GSL_EXPORT
gsl_matrix_long *
gsl_matrix_long_calloc (const size_t n1, const size_t n2);

GSL_EXPORT
gsl_matrix_long *
gsl_matrix_long_alloc_from_block (gsl_block_long * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_EXPORT
gsl_matrix_long *
gsl_matrix_long_alloc_from_matrix (gsl_matrix_long * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_EXPORT
gsl_vector_long *
gsl_vector_long_alloc_row_from_matrix (gsl_matrix_long * m,
                                        const size_t i);

GSL_EXPORT
gsl_vector_long *
gsl_vector_long_alloc_col_from_matrix (gsl_matrix_long * m,
                                        const size_t j);

GSL_EXPORT void gsl_matrix_long_free (gsl_matrix_long * m);

/* Views */

GSL_EXPORT
_gsl_matrix_long_view
gsl_matrix_long_submatrix (gsl_matrix_long * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_EXPORT
_gsl_vector_long_view
gsl_matrix_long_row (gsl_matrix_long * m, const size_t i);

GSL_EXPORT
_gsl_vector_long_view
gsl_matrix_long_column (gsl_matrix_long * m, const size_t j);

GSL_EXPORT
_gsl_vector_long_view
gsl_matrix_long_diagonal (gsl_matrix_long * m);

GSL_EXPORT
_gsl_vector_long_view
gsl_matrix_long_subdiagonal (gsl_matrix_long * m, const size_t k);

GSL_EXPORT
_gsl_vector_long_view
gsl_matrix_long_superdiagonal (gsl_matrix_long * m, const size_t k);

GSL_EXPORT
_gsl_matrix_long_view
gsl_matrix_long_view_array (long * base,
                             const size_t n1,
                             const size_t n2);

GSL_EXPORT
_gsl_matrix_long_view
gsl_matrix_long_view_array_with_tda (long * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_EXPORT
_gsl_matrix_long_view
gsl_matrix_long_view_vector (gsl_vector_long * v,
                              const size_t n1,
                              const size_t n2);

GSL_EXPORT
_gsl_matrix_long_view
gsl_matrix_long_view_vector_with_tda (gsl_vector_long * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_EXPORT
_gsl_matrix_long_const_view
gsl_matrix_long_const_submatrix (const gsl_matrix_long * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_EXPORT
_gsl_vector_long_const_view
gsl_matrix_long_const_row (const gsl_matrix_long * m,
                            const size_t i);

GSL_EXPORT
_gsl_vector_long_const_view
gsl_matrix_long_const_column (const gsl_matrix_long * m,
                               const size_t j);

GSL_EXPORT
_gsl_vector_long_const_view
gsl_matrix_long_const_diagonal (const gsl_matrix_long * m);

GSL_EXPORT
_gsl_vector_long_const_view
gsl_matrix_long_const_subdiagonal (const gsl_matrix_long * m,
                                    const size_t k);

GSL_EXPORT
_gsl_vector_long_const_view
gsl_matrix_long_const_superdiagonal (const gsl_matrix_long * m,
                                      const size_t k);

GSL_EXPORT
_gsl_matrix_long_const_view
gsl_matrix_long_const_view_array (const long * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_EXPORT
_gsl_matrix_long_const_view
gsl_matrix_long_const_view_array_with_tda (const long * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_EXPORT
_gsl_matrix_long_const_view
gsl_matrix_long_const_view_vector (const gsl_vector_long * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_EXPORT
_gsl_matrix_long_const_view
gsl_matrix_long_const_view_vector_with_tda (const gsl_vector_long * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_EXPORT long   gsl_matrix_long_get(const gsl_matrix_long * m, const size_t i, const size_t j);
GSL_EXPORT void    gsl_matrix_long_set(gsl_matrix_long * m, const size_t i, const size_t j, const long x);

GSL_EXPORT long * gsl_matrix_long_ptr(gsl_matrix_long * m, const size_t i, const size_t j);
GSL_EXPORT const long * gsl_matrix_long_const_ptr(const gsl_matrix_long * m, const size_t i, const size_t j);

GSL_EXPORT void gsl_matrix_long_set_zero (gsl_matrix_long * m);
GSL_EXPORT void gsl_matrix_long_set_identity (gsl_matrix_long * m);
GSL_EXPORT void gsl_matrix_long_set_all (gsl_matrix_long * m, long x);

GSL_EXPORT int gsl_matrix_long_fread (FILE * stream, gsl_matrix_long * m) ;
GSL_EXPORT int gsl_matrix_long_fwrite (FILE * stream, const gsl_matrix_long * m) ;
GSL_EXPORT int gsl_matrix_long_fscanf (FILE * stream, gsl_matrix_long * m);
GSL_EXPORT int gsl_matrix_long_fprintf (FILE * stream, const gsl_matrix_long * m, const char * format);

GSL_EXPORT int gsl_matrix_long_memcpy(gsl_matrix_long * dest, const gsl_matrix_long * src);
GSL_EXPORT int gsl_matrix_long_swap(gsl_matrix_long * m1, gsl_matrix_long * m2);

GSL_EXPORT int gsl_matrix_long_swap_rows(gsl_matrix_long * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_long_swap_columns(gsl_matrix_long * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_long_swap_rowcol(gsl_matrix_long * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_long_transpose (gsl_matrix_long * m);
GSL_EXPORT int gsl_matrix_long_transpose_memcpy (gsl_matrix_long * dest, const gsl_matrix_long * src);

GSL_EXPORT long gsl_matrix_long_max (const gsl_matrix_long * m);
GSL_EXPORT long gsl_matrix_long_min (const gsl_matrix_long * m);
GSL_EXPORT void gsl_matrix_long_minmax (const gsl_matrix_long * m, long * min_out, long * max_out);

GSL_EXPORT void gsl_matrix_long_max_index (const gsl_matrix_long * m, size_t * imax, size_t *jmax);
GSL_EXPORT void gsl_matrix_long_min_index (const gsl_matrix_long * m, size_t * imin, size_t *jmin);
GSL_EXPORT void gsl_matrix_long_minmax_index (const gsl_matrix_long * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_EXPORT int gsl_matrix_long_isnull (const gsl_matrix_long * m);

GSL_EXPORT int gsl_matrix_long_add (gsl_matrix_long * a, const gsl_matrix_long * b);
GSL_EXPORT int gsl_matrix_long_sub (gsl_matrix_long * a, const gsl_matrix_long * b);
GSL_EXPORT int gsl_matrix_long_mul_elements (gsl_matrix_long * a, const gsl_matrix_long * b);
GSL_EXPORT int gsl_matrix_long_div_elements (gsl_matrix_long * a, const gsl_matrix_long * b);
GSL_EXPORT int gsl_matrix_long_scale (gsl_matrix_long * a, const double x);
GSL_EXPORT int gsl_matrix_long_add_constant (gsl_matrix_long * a, const double x);
GSL_EXPORT int gsl_matrix_long_add_diagonal (gsl_matrix_long * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_EXPORT int gsl_matrix_long_get_row(gsl_vector_long * v, const gsl_matrix_long * m, const size_t i);
GSL_EXPORT int gsl_matrix_long_get_col(gsl_vector_long * v, const gsl_matrix_long * m, const size_t j);
GSL_EXPORT int gsl_matrix_long_set_row(gsl_matrix_long * m, const size_t i, const gsl_vector_long * v);
GSL_EXPORT int gsl_matrix_long_set_col(gsl_matrix_long * m, const size_t j, const gsl_vector_long * v);

/* inline functions if you are using GCC */

#ifdef HAVE_INLINE
extern inline
long
gsl_matrix_long_get(const gsl_matrix_long * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_VAL("first index out of range", GSL_EINVAL, 0) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VAL("second index out of range", GSL_EINVAL, 0) ;
    }
#endif
  return m->data[i * m->tda + j] ;
}

extern inline
void
gsl_matrix_long_set(gsl_matrix_long * m, const size_t i, const size_t j, const long x)
{
#if GSL_RANGE_CHECK
  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
  m->data[i * m->tda + j] = x ;
}

extern inline
long *
gsl_matrix_long_ptr(gsl_matrix_long * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  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 (long *) (m->data + (i * m->tda + j)) ;
}

extern inline
const long *
gsl_matrix_long_const_ptr(const gsl_matrix_long * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  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 long *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_LONG_H__ */


#ifndef __GSL_PERMUTE_H__
#define __GSL_PERMUTE_H__

#include <gsl/gsl_permute_complex_long_double.h>
#include <gsl/gsl_permute_complex_double.h>
#include <gsl/gsl_permute_complex_float.h>

#include <gsl/gsl_permute_long_double.h>
#include <gsl/gsl_permute_double.h>
#include <gsl/gsl_permute_float.h>

#include <gsl/gsl_permute_ulong.h>
#include <gsl/gsl_permute_long.h>

#include <gsl/gsl_permute_uint.h>
#include <gsl/gsl_permute_int.h>

#include <gsl/gsl_permute_ushort.h>
#include <gsl/gsl_permute_short.h>

#include <gsl/gsl_permute_uchar.h>
#include <gsl/gsl_permute_char.h>

#endif /* __GSL_PERMUTE_H__ */


//  This matrix class is a C++ wrapper for the GNU Scientific Library
//  Copyright (C)  ULP-IPB Strasbourg

//  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.

#ifndef _vector_#type#_h
#define _vector_#type#_h

#ifdef __HP_aCC
#include <iostream.h>
#else
#include <iostream>
#endif

#include <gsl/gsl_math.h>
#include <gsl/gsl_vector#typeext#.h>
#include <gsl/gsl_blas.h>
#include <gslwrap/vector_double.h>

//#define NDEBUG 0

#include <assert.h>
namespace gsl
{

#ifndef __HP_aCC
	using std::ostream;
//using std::string;
//using std::runtime_error;
#endif

class vector#typeext#_view;

class vector#typeext#
{
protected:
	gsl_vector#typeext# *gsldata;
	void free(){if(gsldata) gsl_vector#typeext#_free(gsldata);gsldata=NULL;}
	void alloc(size_t n) {gsldata=gsl_vector#typeext#_alloc(n);}
	void calloc(size_t n){gsldata=gsl_vector#typeext#_calloc(n);}
public:
	typedef #type# value_type;
	vector#typeext#() : gsldata(NULL) {;}
	vector#typeext#( const vector#typeext# &other ):gsldata(NULL) {copy(other);}
	template<class oclass>
	vector#typeext#( const oclass &other ):gsldata(NULL) {copy(other);}
	~vector#typeext#(){free();}
	vector#typeext#(const size_t& n,bool clear=true)
	{
		if(clear){this->calloc(n);}
		else     {this->alloc(n);}
	}
	vector#typeext#(const int& n,bool clear=true)
	{
		if(clear){this->calloc(n);}
		else     {this->alloc(n);}
	}

	void resize(size_t n);

	template <class oclass>
		void copy(const oclass &other)
		{
			if ( static_cast<const void *>( this ) == static_cast<const void *>( &other ) )
				return;

			if (!other.is_set())
			{
				gsldata=NULL;
				return;
			}
			resize(other.size());
			for (size_t i=0;i<size();i++)
			{
				gsl_vector#typeext#_set(gsldata, i, (#type#)other[i]);
			}
		}
	void copy(const vector#typeext#& other);
	bool is_set() const{if (gsldata) return true; else return false;}
//	void clone(vector#typeext#& other);

//	size_t size() const {if (!gsldata) {cout << "vector#typeext#::size vector not initialized" << endl; exit(-1);}return gsldata->size;}
	size_t size() const {assert (gsldata); return gsldata->size;}

	/** for interfacing with gsl c */
/*  	gsl_vector#typeext#       *gslobj()       {if (!gsldata){cout << "vector#typeext#::gslobj ERROR, data not initialized!! " << endl; exit(-1);}return gsldata;} */
/*  	const gsl_vector#typeext# *gslobj() const {if (!gsldata){cout << "vector#typeext#::gslobj ERROR, data not initialized!! " << endl; exit(-1);}return gsldata;} */
	gsl_vector#typeext#       *gslobj()       {assert(gsldata);return gsldata;}
	const gsl_vector#typeext# *gslobj() const {assert(gsldata);return gsldata;}

	static vector#typeext#_view create_vector_view( const gsl_vector#typeext#_view &other );

// ********Accessing vector elements

//  Unlike FORTRAN compilers, C compilers do not usually provide support for range checking of vectors and matrices (2). However, the functions gsl_vector#typeext#_get and gsl_vector#typeext#_set can perform range checking for you and report an error if you attempt to access elements outside the allowed range.

//  The functions for accessing the elements of a vector or matrix are defined in `gsl_vector#typeext#.h' and declared extern inline to eliminate function-call overhead. If necessary you can turn off range checking completely without modifying any source files by recompiling your program with the preprocessor definition GSL_RANGE_CHECK_OFF. Provided your compiler supports inline functions the effect of turning off range checking is to replace calls to gsl_vector#typeext#_get(v,i) by v->data[i*v->stride] and and calls to gsl_vector#typeext#_set(v,i,x) by v->data[i*v->stride]=x. Thus there should be no performance penalty for using the range checking functions when range checking is turned off.

//      This function returns the i-th element of a vector v. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked and 0 is returned.
	#type# get(size_t i) const {return gsl_vector#typeext#_get(gsldata,i);}

//      This function sets the value of the i-th element of a vector v to x. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked.
	void  set(size_t i,#type# x){gsl_vector#typeext#_set(gsldata,i,x);}

//      These functions return a pointer to the i-th element of a vector v. If i lies outside the allowed range of 0 to n-1 then the error handler is invoked
	#type#       &operator[](size_t i)       { return *gsl_vector#typeext#_ptr(gsldata,i);}
	const #type# &operator[](size_t i) const { return *gsl_vector#typeext#_ptr(gsldata,i);}

	#type#       &operator()(size_t i)       { return *gsl_vector#typeext#_ptr(gsldata,i);}
	const #type# &operator()(size_t i) const { return *gsl_vector#typeext#_ptr(gsldata,i);}

//  ***** Initializing vector elements

//      This function sets all the elements of the vector v to the value x.
	void set_all(#type# x){gsl_vector#typeext#_set_all (gsldata,x);}
//      This function sets all the elements of the vector v to zero.
	void set_zero(){gsl_vector#typeext#_set_zero (gsldata);}

//      This function makes a basis vector by setting all the elements of the vector v to zero except for the i-th element which is set to one.
	int set_basis (size_t i) {return gsl_vector#typeext#_set_basis (gsldata,i);}

//  **** Reading and writing vectors

//  The library provides functions for reading and writing vectors to a file as binary data or formatted text.

//      This function writes the elements of the vector v to the stream stream in binary format. The return value is 0 for success and GSL_EFAILED if there was a problem writing to the file. Since the data is written in the native binary format it may not be portable between different architectures.
	int fwrite (FILE * stream) const {return gsl_vector#typeext#_fwrite (stream, gsldata);}

//      This function reads into the vector v from the open stream stream in binary format. The vector v must be preallocated with the correct length since the function uses the size of v to determine how many bytes to read. The return value is 0 for success and GSL_EFAILED if there was a problem reading from the file. The data is assumed to have been written in the native binary format on the same architecture.
	int fread (FILE * stream) {return gsl_vector#typeext#_fread (stream, gsldata);}

	void load( const char *filename );
	///
	void save( const char *filename ) const;

//      This function writes the elements of the vector v line-by-line to the stream stream using the format specifier format, which should be one of the %g, %e or %f formats for floating point numbers and %d for integers. The function returns 0 for success and GSL_EFAILED if there was a problem writing to the file.
	int fprintf (FILE * stream, const char * format) const {return gsl_vector#typeext#_fprintf (stream, gsldata,format) ;}

//      This function reads formatted data from the stream stream into the vector v. The vector v must be preallocated with the correct length since the function uses the size of v to determine how many numbers to read. The function returns 0 for success and GSL_EFAILED if there was a problem reading from the file.
	int fscanf (FILE * stream)  {return gsl_vector#typeext#_fscanf (stream, gsldata); }

//  ******* Vector views

//  In addition to creating vectors from slices of blocks it is also possible to slice vectors and create vector views. For example, a subvector of another vector can be described with a view, or two views can be made which provide access to the even and odd elements of a vector.

//  A vector view is a temporary object, stored on the stack, which can be used to operate on a subset of vector elements. Vector views can be defined for both constant and non-constant vectors, using separate types that preserve constness. A vector view has the type gsl_vector#typeext#_view and a constant vector view has the type gsl_vector#typeext#_const_view. In both cases the elements of the view can be accessed as a gsl_vector#typeext# using the vector component of the view object. A pointer to a vector of type gsl_vector#typeext# * or const gsl_vector#typeext# * can be obtained by taking the address of this component with the & operator.

//      These functions return a vector view of a subvector of another vector v. The start of the new vector is offset by offset elements from the start of the original
//      vector. The new vector has n elements. Mathematically, the i-th element of the new vector v' is given by,

//      v'(i) = v->data[(offset + i)*v->stride]

//      where the index i runs from 0 to n-1.

//      The data pointer of the returned vector struct is set to null if the combined parameters (offset,n) overrun the end of the original vector.

//      The new vector is only a view of the block underlying the original vector, v. The block containing the elements of v is not owned by the new vector. When the
//      new vector goes out of scope the original vector v and its block will continue to exist. The original memory can only be deallocated by freeing the original vector.
//      Of course, the original vector should not be deallocated while the new vector is still in use.

//      The function gsl_vector#typeext#_const_subvector is equivalent to gsl_vector#typeext#_subvector but can be used for vectors which are declared const.
	vector#typeext#_view subvector (size_t offset, size_t n);
	const vector#typeext#_view subvector (size_t offset, size_t n) const;
//	vector#typeext#_const_view subvector (size_t offset, size_t n) const;

//  	class view
//  	{
//  		gsl_vector#typeext#_view *gsldata;
//  	public:
//  		view();
//  	};
//  	view subvector(size_t offset, size_t n)
//  	{
//  		return view(gsl_vector#typeext#_subvector(gsldata,offset,n);
//  	}
//  	const view subvector(size_t offset, size_t n) const
//  	{
//  		return view(gsl_vector#typeext#_const_subvector(gsldata,offset,n);
//  	}

//  Function: gsl_vector#typeext# gsl_vector#typeext#_subvector_with_stride (gsl_vector#typeext# *v, size_t offset, size_t stride, size_t n)
//  Function: gsl_vector#typeext#_const_view gsl_vector#typeext#_const_subvector_with_stride (const gsl_vector#typeext# * v, size_t offset, size_t stride, size_t n)
//      These functions return a vector view of a subvector of another vector v with an additional stride argument. The subvector is formed in the same way as for
//      gsl_vector#typeext#_subvector but the new vector has n elements with a step-size of stride from one element to the next in the original vector. Mathematically,
//      the i-th element of the new vector v' is given by,

//      v'(i) = v->data[(offset + i*stride)*v->stride]

//      where the index i runs from 0 to n-1.

//      Note that subvector views give direct access to the underlying elements of the original vector. For example, the following code will zero the even elements of the
//      vector v of length n, while leaving the odd elements untouched,

//      gsl_vector#typeext#_view v_even = gsl_vector#typeext#_subvector_with_stride (v, 0, 2, n/2);
//      gsl_vector#typeext#_set_zero (&v_even.vector);

//      A vector view can be passed to any subroutine which takes a vector argument just as a directly allocated vector would be, using &view.vector. For example, the
//      following code computes the norm of odd elements of v using the BLAS routine DNRM2,

//      gsl_vector#typeext#_view v_odd = gsl_vector#typeext#_subvector_with_stride (v, 1, 2, n/2);
//      double r = gsl_blas_dnrm2 (&v_odd.vector);

//      The function gsl_vector#typeext#_const_subvector_with_stride is equivalent to gsl_vector#typeext#_subvector_with_stride but can be used for
//      vectors which are declared const.

//  Function: gsl_vector#typeext#_view gsl_vector#typeext#_complex_real (gsl_vector#typeext#_complex *v)
//  Function: gsl_vector#typeext#_const_view gsl_vector#typeext#_complex_const_real (const gsl_vector#typeext#_complex *v)
//      These functions return a vector view of the real parts of the complex vector v.

//      The function gsl_vector#typeext#_complex_const_real is equivalent to gsl_vector#typeext#_complex_real but can be used for vectors which are declared
//      const.

//  Function: gsl_vector#typeext#_view gsl_vector#typeext#_complex_imag (gsl_vector#typeext#_complex *v)
//  Function: gsl_vector#typeext#_const_view gsl_vector#typeext#_complex_const_imag (const gsl_vector#typeext#_complex *v)
//      These functions return a vector view of the imaginary parts of the complex vector v.

//      The function gsl_vector#typeext#_complex_const_imag is equivalent to gsl_vector#typeext#_complex_imag but can be used for vectors which are declared
//      const.

//  Function: gsl_vector#typeext#_view gsl_vector#typeext#_view_array (double *base, size_t n)
//  Function: gsl_vector#typeext#_const_view gsl_vector#typeext#_const_view_array (const double *base, size_t n)
//      These functions return a vector view of an array. The start of the new vector is given by base and has n elements. Mathematically, the i-th element of the new
//      vector v' is given by,

//      v'(i) = base[i]

//      where the index i runs from 0 to n-1.

//      The array containing the elements of v is not owned by the new vector view. When the view goes out of scope the original array will continue to exist. The
//      original memory can only be deallocated by freeing the original pointer base. Of course, the original array should not be deallocated while the view is still in use.

//      The function gsl_vector#typeext#_const_view_array is equivalent to gsl_vector#typeext#_view_array but can be used for vectors which are declared const.

//  Function: gsl_vector#typeext#_view gsl_vector#typeext#_view_array_with_stride (double * base, size_t stride, size_t n)
//  Function: gsl_vector#typeext#_const_view gsl_vector#typeext#_const_view_array_with_stride (const double * base, size_t stride, size_t n)
//      These functions return a vector view of an array base with an additional stride argument. The subvector is formed in the same way as for
//      gsl_vector#typeext#_view_array but the new vector has n elements with a step-size of stride from one element to the next in the original array. Mathematically,
//      the i-th element of the new vector v' is given by,

//      v'(i) = base[i*stride]

//      where the index i runs from 0 to n-1.

//      Note that the view gives direct access to the underlying elements of the original array. A vector view can be passed to any subroutine which takes a vector
//      argument just as a directly allocated vector would be, using &view.vector.

//      The function gsl_vector#typeext#_const_view_array_with_stride is equivalent to gsl_vector#typeext#_view_array_with_stride but can be used for
//      arrays which are declared const.

//  ************* Copying vectors

//  Common operations on vectors such as addition and multiplication are available in the BLAS part of the library (see section BLAS Support). However, it is useful to have a small number of utility functions which do not require the full BLAS code. The following functions fall into this category.

//      This function copies the elements of the vector src into the vector dest.
	vector#typeext#& operator=(const vector#typeext#& other){copy(other);return (*this);}

//  Function: int gsl_vector#typeext#_swap (gsl_vector#typeext# * v, gsl_vector#typeext# * w)
//      This function exchanges the elements of the vectors v and w by copying. The two vectors must have the same length.

//  ***** Exchanging elements

//  The following function can be used to exchange, or permute, the elements of a vector.

//  Function: int gsl_vector#typeext#_swap_elements (gsl_vector#typeext# * v, size_t i, size_t j)
//      This function exchanges the i-th and j-th elements of the vector v in-place.
	int swap_elements (size_t i, size_t j) {return gsl_vector#typeext#_swap_elements (gsldata, i,j);}

//  Function: int gsl_vector#typeext#_reverse (gsl_vector#typeext# * v)
//      This function reverses the order of the elements of the vector v.
	int reverse () {return  gsl_vector#typeext#_reverse (gsldata) ;}

// ******* Vector operations

//  The following operations are only defined for real vectors.

//      This function adds the elements of vector b to the elements of vector a, a'_i = a_i + b_i. The two vectors must have the same length.
	int operator+=(const vector#typeext# &other) {return gsl_vector#typeext#_add (gsldata, other.gsldata);}

//      This function subtracts the elements of vector b from the elements of vector a, a'_i = a_i - b_i. The two vectors must have the same length.
	int operator-=(const vector#typeext# &other) {return gsl_vector#typeext#_sub (gsldata, other.gsldata);}

//  Function: int gsl_vector#typeext#_mul (gsl_vector#typeext# * a, const gsl_vector#typeext# * b)
//      This function multiplies the elements of vector a by the elements of vector b, a'_i = a_i * b_i. The two vectors must have the same length.
	int operator*=(const vector#typeext# &other) {return gsl_vector#typeext#_mul (gsldata, other.gsldata);}

//      This function divides the elements of vector a by the elements of vector b, a'_i = a_i / b_i. The two vectors must have the same length.
	int operator/=(const vector#typeext# &other) {return gsl_vector#typeext#_div (gsldata, other.gsldata);}

//      This function multiplies the elements of vector a by the constant factor x, a'_i = x a_i.
	int operator*=(#type# x) {return gsl_vector#typeext#_scale (gsldata, x);}

//  Function: int gsl_vector#typeext#_add_constant (gsl_vector#typeext# * a, const double x)
//      This function adds the constant value x to the elements of the vector a, a'_i = a_i + x.
	int operator+=(#type# x) {return gsl_vector#typeext#_add_constant (gsldata,x);}

//      This function multiplies the elements of vector a by the constant factor x, a'_i = x a_i.
	int operator/=(#type# x) {return gsl_vector#typeext#_scale (gsldata, 1/x);}

// bool operators:
	bool operator==(const vector#typeext#& other) const;
	bool operator!=(const vector#typeext#& other) const { return (!((*this)==other));}

// stream output:
//	friend ostream& operator<< ( ostream& os, const vector#typeext#& vect );
	/** returns sum of all the vector elements. */
    #type# sum() const;
	// returns sqrt(v.t*v);
    double norm2() const;

// **** Finding maximum and minimum elements of vectors

//      This function returns the maximum value in the vector v.
    double max() const{return gsl_vector#typeext#_max (gsldata) ;}

//  Function: double gsl_vector#typeext#_min (const gsl_vector#typeext# * v)
//      This function returns the minimum value in the vector v.
    double min() const{return gsl_vector#typeext#_min (gsldata) ;}

//  Function: void gsl_vector#typeext#_minmax (const gsl_vector#typeext# * v, double * min_out, double * max_out)
//      This function returns the minimum and maximum values in the vector v, storing them in min_out and max_out.

//      This function returns the index of the maximum value in the vector v. When there are several equal maximum elements then the lowest index is returned.
	size_t max_index(){return gsl_vector#typeext#_max_index (gsldata);}

//  Function: size_t gsl_vector#typeext#_min_index (const gsl_vector#typeext# * v)
//      This function returns the index of the minimum value in the vector v. When there are several equal minimum elements then the lowest index is returned.
	size_t min_index(){return gsl_vector#typeext#_min_index (gsldata);}

//  Function: void gsl_vector#typeext#_minmax_index (const gsl_vector#typeext# * v, size_t * imin, size_t * imax)
//      This function returns the indices of the minimum and maximum values in the vector v, storing them in imin and imax. When there are several equal minimum
//      or maximum elements then the lowest indices are returned.

//  Vector properties

//  Function: int gsl_vector#typeext#_isnull (const gsl_vector#typeext# * v)
//      This function returns 1 if all the elements of the vector v are zero, and 0 otherwise. };
	bool isnull(){return gsl_vector#typeext#_isnull (gsldata);}
};

// When you add create a view it will stick to its with the view until you call change_view
// ex:
// matrix_float m(5,5);
// vector_float v(5);
// // ...
// m.column(3) = v; //the 3rd column of the matrix m will equal v.
class vector#typeext#_view : public vector#typeext#
{
 public:
	vector#typeext#_view(const vector#typeext#&     other) :vector#typeext#(){init(other);}
	vector#typeext#_view(const vector#typeext#_view& other):vector#typeext#(){init(other);}
	vector#typeext#_view(const gsl_vector#typeext#& gsl_other) : vector#typeext#() {init_with_gsl_vector(gsl_other);}

	void init(const vector#typeext#& other);
	void init_with_gsl_vector(const gsl_vector#typeext#& gsl_other);
	void change_view(const vector#typeext#& other){init(other);}
 private:
};

ostream& operator<< ( ostream& os, const vector#typeext# & vect );

// vector_type<>::type is a template interface to vector_?
// it is usefull for in templated situations for getting the correct vector type
#define tmp_type_is#typeext#
#ifdef tmp_type_is
typedef vector vector_double;
template<class T>
struct vector_type  {typedef vector_double   type;};

template<class T>
struct value_type  {typedef double   type;};

#else
template<> struct vector_type<#type#> {typedef vector#typeext# type;};
#endif
#undef tmp_type_is#typeext#

}
#endif// _vector_#type#_h