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

#ifndef __GSL_MATRIX_INT_H__
#define __GSL_MATRIX_INT_H__

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

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_int.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;
  int * data;
  gsl_block_int * block;
  int owner;
} gsl_matrix_int;

typedef struct
{
  gsl_matrix_int matrix;
} _gsl_matrix_int_view;

typedef _gsl_matrix_int_view gsl_matrix_int_view;

typedef struct
{
  gsl_matrix_int matrix;
} _gsl_matrix_int_const_view;

typedef const _gsl_matrix_int_const_view gsl_matrix_int_const_view;

/* Allocation */

GSL_FUN gsl_matrix_int *
gsl_matrix_int_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_int *
gsl_matrix_int_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_int *
gsl_matrix_int_alloc_from_block (gsl_block_int * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_FUN gsl_matrix_int *
gsl_matrix_int_alloc_from_matrix (gsl_matrix_int * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN gsl_vector_int *
gsl_vector_int_alloc_row_from_matrix (gsl_matrix_int * m,
                                        const size_t i);

GSL_FUN gsl_vector_int *
gsl_vector_int_alloc_col_from_matrix (gsl_matrix_int * m,
                                        const size_t j);

GSL_FUN void gsl_matrix_int_free (gsl_matrix_int * m);

/* Views */

GSL_FUN _gsl_matrix_int_view
gsl_matrix_int_submatrix (gsl_matrix_int * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_row (gsl_matrix_int * m, const size_t i);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_column (gsl_matrix_int * m, const size_t j);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_diagonal (gsl_matrix_int * m);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_subdiagonal (gsl_matrix_int * m, const size_t k);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_superdiagonal (gsl_matrix_int * m, const size_t k);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_subrow (gsl_matrix_int * m, const size_t i,
                         const size_t offset, const size_t n);

GSL_FUN _gsl_vector_int_view
gsl_matrix_int_subcolumn (gsl_matrix_int * m, const size_t j,
                            const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_int_view
gsl_matrix_int_view_array (int * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_int_view
gsl_matrix_int_view_array_with_tda (int * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_int_view
gsl_matrix_int_view_vector (gsl_vector_int * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_int_view
gsl_matrix_int_view_vector_with_tda (gsl_vector_int * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_int_const_view
gsl_matrix_int_const_submatrix (const gsl_matrix_int * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_row (const gsl_matrix_int * m,
                            const size_t i);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_column (const gsl_matrix_int * m,
                               const size_t j);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_diagonal (const gsl_matrix_int * m);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_subdiagonal (const gsl_matrix_int * m,
                                    const size_t k);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_superdiagonal (const gsl_matrix_int * m,
                                      const size_t k);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_subrow (const gsl_matrix_int * m, const size_t i,
                               const size_t offset, const size_t n);

GSL_FUN _gsl_vector_int_const_view
gsl_matrix_int_const_subcolumn (const gsl_matrix_int * m, const size_t j,
                                  const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_int_const_view
gsl_matrix_int_const_view_array (const int * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_int_const_view
gsl_matrix_int_const_view_array_with_tda (const int * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_int_const_view
gsl_matrix_int_const_view_vector (const gsl_vector_int * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_int_const_view
gsl_matrix_int_const_view_vector_with_tda (const gsl_vector_int * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_int_set_zero (gsl_matrix_int * m);
GSL_FUN void gsl_matrix_int_set_identity (gsl_matrix_int * m);
GSL_FUN void gsl_matrix_int_set_all (gsl_matrix_int * m, int x);

GSL_FUN int gsl_matrix_int_fread (FILE * stream, gsl_matrix_int * m) ;
GSL_FUN int gsl_matrix_int_fwrite (FILE * stream, const gsl_matrix_int * m) ;
GSL_FUN int gsl_matrix_int_fscanf (FILE * stream, gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_fprintf (FILE * stream, const gsl_matrix_int * m, const char * format);

GSL_FUN int gsl_matrix_int_memcpy(gsl_matrix_int * dest, const gsl_matrix_int * src);
GSL_FUN int gsl_matrix_int_swap(gsl_matrix_int * m1, gsl_matrix_int * m2);

GSL_FUN int gsl_matrix_int_swap_rows(gsl_matrix_int * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_int_swap_columns(gsl_matrix_int * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_int_swap_rowcol(gsl_matrix_int * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_int_transpose (gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_transpose_memcpy (gsl_matrix_int * dest, const gsl_matrix_int * src);

GSL_FUN int gsl_matrix_int_max (const gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_min (const gsl_matrix_int * m);
GSL_FUN void gsl_matrix_int_minmax (const gsl_matrix_int * m, int * min_out, int * max_out);

GSL_FUN void gsl_matrix_int_max_index (const gsl_matrix_int * m, size_t * imax, size_t *jmax);
GSL_FUN void gsl_matrix_int_min_index (const gsl_matrix_int * m, size_t * imin, size_t *jmin);
GSL_FUN void gsl_matrix_int_minmax_index (const gsl_matrix_int * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_FUN int gsl_matrix_int_equal (const gsl_matrix_int * a, const gsl_matrix_int * b);

GSL_FUN int gsl_matrix_int_isnull (const gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_ispos (const gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_isneg (const gsl_matrix_int * m);
GSL_FUN int gsl_matrix_int_isnonneg (const gsl_matrix_int * m);

GSL_FUN int gsl_matrix_int_add (gsl_matrix_int * a, const gsl_matrix_int * b);
GSL_FUN int gsl_matrix_int_sub (gsl_matrix_int * a, const gsl_matrix_int * b);
GSL_FUN int gsl_matrix_int_mul_elements (gsl_matrix_int * a, const gsl_matrix_int * b);
GSL_FUN int gsl_matrix_int_div_elements (gsl_matrix_int * a, const gsl_matrix_int * b);
GSL_FUN int gsl_matrix_int_scale (gsl_matrix_int * a, const double x);
GSL_FUN int gsl_matrix_int_add_constant (gsl_matrix_int * a, const double x);
GSL_FUN int gsl_matrix_int_add_diagonal (gsl_matrix_int * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_int_get_row(gsl_vector_int * v, const gsl_matrix_int * m, const size_t i);
GSL_FUN int gsl_matrix_int_get_col(gsl_vector_int * v, const gsl_matrix_int * m, const size_t j);
GSL_FUN int gsl_matrix_int_set_row(gsl_matrix_int * m, const size_t i, const gsl_vector_int * v);
GSL_FUN int gsl_matrix_int_set_col(gsl_matrix_int * m, const size_t j, const gsl_vector_int * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL int   gsl_matrix_int_get(const gsl_matrix_int * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void    gsl_matrix_int_set(gsl_matrix_int * m, const size_t i, const size_t j, const int x);
GSL_FUN INLINE_DECL int * gsl_matrix_int_ptr(gsl_matrix_int * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const int * gsl_matrix_int_const_ptr(const gsl_matrix_int * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE
INLINE_FUN
int
gsl_matrix_int_get(const gsl_matrix_int * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      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] ;
}

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

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

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

#endif

__END_DECLS

#endif /* __GSL_MATRIX_INT_H__ */


#ifndef __GSL_PERMUTE_VECTOR_H__
#define __GSL_PERMUTE_VECTOR_H__

#include <gsl/gsl_permute_vector_complex_long_double.h>
#include <gsl/gsl_permute_vector_complex_double.h>
#include <gsl/gsl_permute_vector_complex_float.h>

#include <gsl/gsl_permute_vector_long_double.h>
#include <gsl/gsl_permute_vector_double.h>
#include <gsl/gsl_permute_vector_float.h>

#include <gsl/gsl_permute_vector_ulong.h>
#include <gsl/gsl_permute_vector_long.h>

#include <gsl/gsl_permute_vector_uint.h>
#include <gsl/gsl_permute_vector_int.h>

#include <gsl/gsl_permute_vector_ushort.h>
#include <gsl/gsl_permute_vector_short.h>

#include <gsl/gsl_permute_vector_uchar.h>
#include <gsl/gsl_permute_vector_char.h>

#endif /* __GSL_PERMUTE_VECTOR_H__ */


/*****************************************************************************
Copyright (c) 2011-2014, The OpenBLAS Project
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   1. Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the
      distribution.
   3. Neither the name of the OpenBLAS project nor the names of
      its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE 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 OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

**********************************************************************************/

#include "openblas_utest.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <cblas.h>

void* xmalloc(size_t n)
{
    void* tmp;
    tmp = malloc(n);
    if (tmp == NULL) {
        fprintf(stderr, "You are about to die\n");
        exit(1);
    } else {
        return tmp;
    }
}

void check_dgemm(double *a, double *b, double *result, double *expected, int n)
{
    int i;
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n,
        1.0, a, n, b, n, 0.0, result, n);
    for(i = 0; i < n * n; ++i) {
        ASSERT_DBL_NEAR_TOL(expected[i], result[i], DOUBLE_EPS);
    }
}

CTEST(fork, safety)
{
    int n = 1000;
    int i;

    double *a, *b, *c, *d;
    size_t n_bytes;

    pid_t fork_pid;
    pid_t fork_pid_nested;

    n_bytes = sizeof(*a) * n * n;

    a = xmalloc(n_bytes);
    b = xmalloc(n_bytes);
    c = xmalloc(n_bytes);
    d = xmalloc(n_bytes);

    // Put ones in a and b
    for(i = 0; i < n * n; ++i) {
        a[i] = 1;
        b[i] = 1;
    }

    // Compute a DGEMM product in the parent process prior to forking to
    // ensure that the OpenBLAS thread pool is initialized.
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, n, n, n,
       1.0, a, n, b, n, 0.0, c, n);

    fork_pid = fork();
    if (fork_pid == -1) {
        CTEST_ERR("Failed to fork process.");
    } else if (fork_pid == 0) {
        // Compute a DGEMM product in the child process to check that the
        // thread pool as been properly been reinitialized after the fork.
        check_dgemm(a, b, d, c, n);

        // Nested fork to check that the pthread_atfork protection can work
        // recursively
        fork_pid_nested = fork();
        if (fork_pid_nested == -1) {
            CTEST_ERR("Failed to fork process.");
            exit(1);
        } else if (fork_pid_nested == 0) {
            check_dgemm(a, b, d, c, n);
            exit(0);
        } else {
            check_dgemm(a, b, d, c, n);
            int child_status = 0;
            pid_t wait_pid = wait(&child_status);
            ASSERT_EQUAL(wait_pid, fork_pid_nested);
            ASSERT_EQUAL(0, WEXITSTATUS (child_status));
            exit(0);
        }
    } else {
        check_dgemm(a, b, d, c, n);
        // Wait for the child to finish and check the exit code.
        int child_status = 0;
        pid_t wait_pid = wait(&child_status);
        ASSERT_EQUAL(wait_pid, fork_pid);
        ASSERT_EQUAL(0, WEXITSTATUS (child_status));
    }
}


#ifndef EIGEN_BENCH_UTIL_H
#define EIGEN_BENCH_UTIL_H

#include <Eigen/Core>
#include "BenchTimer.h"

using namespace std;
using namespace Eigen;

#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/array.hpp>
#include <boost/preprocessor/arithmetic.hpp>
#include <boost/preprocessor/comparison.hpp>
#include <boost/preprocessor/punctuation.hpp>
#include <boost/preprocessor/punctuation/comma.hpp>
#include <boost/preprocessor/stringize.hpp>

template<typename MatrixType> void initMatrix_random(MatrixType& mat) __attribute__((noinline));
template<typename MatrixType> void initMatrix_random(MatrixType& mat)
{
  mat.setRandom();// = MatrixType::random(mat.rows(), mat.cols());
}

template<typename MatrixType> void initMatrix_identity(MatrixType& mat) __attribute__((noinline));
template<typename MatrixType> void initMatrix_identity(MatrixType& mat)
{
  mat.setIdentity();
}

#ifndef __INTEL_COMPILER
#define DISABLE_SSE_EXCEPTIONS()  { \
  int aux; \
  asm( \
  "stmxcsr   %[aux]           \n\t" \
  "orl       $32832, %[aux]   \n\t" \
  "ldmxcsr   %[aux]           \n\t" \
  : : [aux] "m" (aux)); \
}
#else
#define DISABLE_SSE_EXCEPTIONS()
#endif

#ifdef BENCH_GMM
#include <gmm/gmm.h>
template <typename EigenMatrixType, typename GmmMatrixType>
void eiToGmm(const EigenMatrixType& src, GmmMatrixType& dst)
{
  dst.resize(src.rows(),src.cols());
  for (int j=0; j<src.cols(); ++j)
    for (int i=0; i<src.rows(); ++i)
      dst(i,j) = src.coeff(i,j);
}
#endif

#ifdef BENCH_GSL
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_eigen.h>
template <typename EigenMatrixType>
void eiToGsl(const EigenMatrixType& src, gsl_matrix** dst)
{
  for (int j=0; j<src.cols(); ++j)
    for (int i=0; i<src.rows(); ++i)
      gsl_matrix_set(*dst, i, j, src.coeff(i,j));
}
#endif

#ifdef BENCH_UBLAS
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/vector.hpp>
template <typename EigenMatrixType, typename UblasMatrixType>
void eiToUblas(const EigenMatrixType& src, UblasMatrixType& dst)
{
  dst.resize(src.rows(),src.cols());
  for (int j=0; j<src.cols(); ++j)
    for (int i=0; i<src.rows(); ++i)
      dst(i,j) = src.coeff(i,j);
}
template <typename EigenType, typename UblasType>
void eiToUblasVec(const EigenType& src, UblasType& dst)
{
  dst.resize(src.size());
  for (int j=0; j<src.size(); ++j)
      dst[j] = src.coeff(j);
}
#endif

#endif // EIGEN_BENCH_UTIL_H


/* gsl_histogram2d_copy.c
 * Copyright (C) 2000  Simone Piccardi
 *
 * This library 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 library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
/***************************************************************
 *
 * File gsl_histogram2d_copy.c:
 * Routine to copy a 2D histogram.
 * Need GSL library and header.
 *
 * Author: S. Piccardi
 * Jan. 2000
 *
 ***************************************************************/
#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_histogram2d.h>

/*
 * gsl_histogram2d_copy:
 * copy the contents of an histogram into another
 */
int
gsl_histogram2d_memcpy (gsl_histogram2d * dest, const gsl_histogram2d * src)
{
  size_t nx = src->nx;
  size_t ny = src->ny;
  size_t i;
  if (dest->nx != src->nx || dest->ny != src->ny)
    {
      GSL_ERROR ("histograms have different sizes, cannot copy",
		 GSL_EINVAL);
    }

  for (i = 0; i <= nx; i++)
    {
      dest->xrange[i] = src->xrange[i];
    }

  for (i = 0; i <= ny; i++)
    {
      dest->yrange[i] = src->yrange[i];
    }

  for (i = 0; i < nx * ny; i++)
    {
      dest->bin[i] = src->bin[i];
    }

  return GSL_SUCCESS;
}

/*
 * gsl_histogram2d_duplicate:
 * duplicate an histogram creating
 * an identical new one
 */

gsl_histogram2d *
gsl_histogram2d_clone (const gsl_histogram2d * src)
{
  size_t nx = src->nx;
  size_t ny = src->ny;
  size_t i;
  gsl_histogram2d *h;

  h = gsl_histogram2d_calloc_range (nx, ny, src->xrange, src->yrange);

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

  for (i = 0; i < nx * ny; i++)
    {
      h->bin[i] = src->bin[i];
    }

  return h;
}


/*
 * CircularDB implementation for time series data.
 *
 * Copyright (c) 2007-2009 Powerset, Inc
 * Copyright (c) Dan Grillo, Manish Dubey, Dan Sully
 *
 * All rights reserved.
 */

#include "config.h"

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

/* For the aggregation interface */
#include <gsl/gsl_errno.h>
#include <gsl/gsl_interp.h>
#include <gsl/gsl_sort.h>
#include <gsl/gsl_statistics.h>

#include <circulardb_interface.h>

/* Future win32 support */
#ifndef O_BINARY
#define O_BINARY 0
#endif

/* Save away errno so it doesn't get overwritten */
int cdb_error(void) {
    int cdb_error = errno;
    return cdb_error;
}

static void _print_record(FILE *fh, cdb_time_t time, double value, const char *date_format) {

    if (date_format == NULL || strcmp(date_format, "") == 0) {

        fprintf(fh, "%d %.8g\n", (int)(time), value);

    } else {

        char formatted[256];
        time_t stime = (time_t)time;

        strftime(formatted, sizeof(formatted), date_format, localtime(&stime));

        fprintf(fh, "%d [%s] %.8g\n", (int)(time), formatted, value);
    }
}

static uint64_t _physical_record_for_logical_record(cdb_header_t *header, int64_t logical_record) {

    uint64_t physical_record = 0;

    /* -ve indicates nth record from the end
       +ve indicates nth record from the beginning (zero based counting for
          this case)

       -3 = seek to 3rd record from the end
        5 = seek to 6th record from the beginning
        0 = seek to first record (start) from the beginning

       change the request for -nth record (nth record from the end)
       to a request for mth record from the beginning, where:

       m = N + n (n is -ve)

       N : total num of records. */

    if (logical_record < 0) {
        int64_t rec_num_from_start = header->num_records + logical_record;

        /* if asking for records more than there are in the db, just give as many as we can */
        logical_record = rec_num_from_start >= 0 ? rec_num_from_start : 0;
    }

    if (logical_record >= header->num_records) {
#ifdef DEBUG
        printf("Can't seek to record [%"PRIu64"] with only [%"PRIu64"] in db\n", logical_record, header->num_records);
#endif
        return 0;
    }

    /* DRK unclear behavior here. Looks like if I specify -N where N >
       num_records, I get pointed to #0, but if I specify +N where N >
       num_records, it's an error */

    /* Nth logical record (from the beginning) maps to Mth physical record
       in the file, where:

       m = (n+s) % N

       s = physical record that is 0th logical record
       N = total number of records in the db.  */

    physical_record = logical_record + header->start_record;

    if (header->num_records > 0) {
        physical_record = (physical_record % header->num_records);
    }

    return physical_record;
}

static int64_t _seek_to_logical_record(cdb_t *cdb, int64_t logical_record) {

    uint64_t physical_record = _physical_record_for_logical_record(cdb->header, logical_record);
    uint64_t offset = HEADER_SIZE + (physical_record * RECORD_SIZE);

    if (lseek(cdb->fd, offset, SEEK_SET) != offset) {
        return -1;
    }

    return physical_record;
}

static cdb_time_t _time_for_logical_record(cdb_t *cdb, int64_t logical_record) {

    cdb_record_t record[RECORD_SIZE];
    cdb_time_t time = 0;

    /* skip over any record that has NULL time or bad time values
       Such datapoints in cdb indicate a corrupted cdb. */
    while (!time || time <= 0) {

        if (_seek_to_logical_record(cdb, logical_record) < 0) {
            time = 0;
            break;
        }

        logical_record += 1;

        if (read(cdb->fd, &record, RECORD_SIZE) < 0) {
            time = 0;
            break;
        }

        time = record->time;
    }

    return time;
}

/* note - if no exact match, will return a record with a time greater than the requested value */
static int64_t _logical_record_for_time(cdb_t *cdb, cdb_time_t req_time, int64_t start_logical_record, int64_t end_logical_record) {

    bool first_time = false;
    cdb_time_t start_time, next_time, center_time;
    int64_t delta, center_logical_record, next_logical_record;

    uint64_t num_recs = cdb->header->num_records;

    /* for the very first time find start and end */
    if (start_logical_record == 0 && end_logical_record == 0) {

        start_logical_record = 0;
        end_logical_record   = num_recs - 1;

        first_time = true;
    }

    /* if no particular time was requested, just return the first one. */
    if (req_time == 0) {
        return start_logical_record;
    }

    /* if there are only 2 or 1 records in the search space, return the last record */
    if (end_logical_record - start_logical_record <= 1) {
        return end_logical_record;
    }

    start_time = _time_for_logical_record(cdb, start_logical_record);

    /* if requested time is less than start_time, start_time is the best we can do. */
    if (req_time <= start_time) {
        return start_logical_record;
    }

    /* don't go out of bounds */
    if (start_logical_record + 1 >= num_recs) {
        return start_logical_record;
    }

    next_logical_record = start_logical_record;
    next_time = start_time;

    /* if _seek_to_logical_record encounters bad data it fabricates and
       returns next good value. Try to get the *real* next rec. */
    while ((next_time - start_time) == 0) {

        next_logical_record += 1;

        next_time = _time_for_logical_record(cdb, next_logical_record);

        if (next_logical_record >= num_recs) {
            break;
        }
    }

    delta = next_time - start_time;

    /* delta = 0 means that _seek_to_logical_record fabricated data on the fly */
    if (delta == 0) {
        return start_logical_record;
    /* if we have wrapped over, or if the requested time is in the range of start and next, return start */
    } else if (delta < 0) {
        return start_logical_record;
    } else if (req_time <= next_time) {
        return next_logical_record;
    }

    /* for the very first binary search pivot point, take an aggressive guess to make search converge faster */
    if (first_time) {
        center_logical_record = (req_time - start_time) / (next_time - start_time) - 1;
    } else {
        center_logical_record = start_logical_record + (end_logical_record - start_logical_record) / 2;
    }

    if (num_recs > 0) {
        center_logical_record = (center_logical_record % num_recs);
    }

    center_time = _time_for_logical_record(cdb, center_logical_record);

    if (req_time >= center_time) {
        start_logical_record = center_logical_record;
    } else {
        end_logical_record = center_logical_record;
    }

    return _logical_record_for_time(cdb, req_time, start_logical_record, end_logical_record);
}

bool _cdb_is_writable(cdb_t *cdb) {

    /* We can't check for the O_RDONLY bit being because its defined value is zero.
     * i.e. there are no bits set to look for. We therefore assume
     * O_RDONLY if neither O_WRONLY nor O_RDWR are set. */
    if (cdb->flags & O_RDWR) {
        return true;
    }

    return false;
}

int cdb_read_header(cdb_t *cdb) {
    struct stat st;

    /* If the header has already been read from backing store do not read again */
    if (cdb->synced == true) {
        return CDB_SUCCESS;
    }

    if (cdb_open(cdb) != 0) {
        return cdb_error();
    }

    if (pread(cdb->fd, cdb->header, HEADER_SIZE, 0) != HEADER_SIZE) {
        return cdb_error();
    }

    if (strncmp(cdb->header->token, CDB_TOKEN, sizeof(CDB_TOKEN)) != 0) {
        return CDB_EBADTOK;
    }

    if (strncmp(cdb->header->version, CDB_VERSION, sizeof(CDB_VERSION)) != 0) {
        return CDB_EBADVER;
    }

    cdb->synced = true;

    /* Calculate the number of records */
    if (fstat(cdb->fd, &st) == 0) {
        cdb->header->num_records = (st.st_size - HEADER_SIZE) / RECORD_SIZE;
    } else {
        cdb->header->num_records = 0;
    }

    return CDB_SUCCESS;
}

int cdb_write_header(cdb_t *cdb) {

    if (cdb->synced) {
        return CDB_SUCCESS;
    }

    if (_cdb_is_writable(cdb) == false) {
        return CDB_ERDONLY;
    }

    cdb->synced = false;

    if (cdb_open(cdb) > 0) {
        return cdb_error();
    }

    if (pwrite(cdb->fd, cdb->header, HEADER_SIZE, 0) != HEADER_SIZE) {
        return cdb_error();
    }

    cdb->synced = true;

    return CDB_SUCCESS;
}

void cdb_print_header(cdb_t * cdb) {

    printf("version: [%s]\n", cdb->header->version);
    printf("name: [%s]\n", cdb->header->name);
    printf("desc: [%s]\n", cdb->header->desc);
    printf("units: [%s]\n", cdb->header->units);

    if (cdb->header->type == CDB_TYPE_COUNTER) {
        printf("type: [COUNTER]\n");
    }

    if (cdb->header->type == CDB_TYPE_GAUGE) {
        printf("type: [GAUGE]\n");
    }

    printf("min_value: [%g]\n", cdb->header->min_value);
    printf("max_value: [%g]\n", cdb->header->max_value);
    printf("max_records: [%"PRIu64"]\n", cdb->header->max_records);
    printf("num_records: [%"PRIu64"]\n", cdb->header->num_records);
    printf("start_record: [%"PRIu64"]\n", cdb->header->start_record);
}

int cdb_write_records(cdb_t *cdb, cdb_record_t *records, uint64_t len, uint64_t *num_recs) {

    /* read old header if it exists.
       write a header out, since the db may not have existed.
    */
    uint64_t i   = 0;
    uint64_t j   = 0;
    off_t offset = 0;
    *num_recs    = 0;

    if (cdb_read_header(cdb) != CDB_SUCCESS) {
        return cdb_error();
    }

    if (_cdb_is_writable(cdb) == false) {
        return CDB_ERDONLY;
    }

    if (cdb->header->max_records <= 0) {
        return CDB_EINVMAX;
    }

    /* Logic for writes:
    cdb is 5 records.
        try to write 7 records
        len = 7
        len + 0 > 5
        j = (7 + 0) - 5
        j = 2
        i = 7 - 2
        i = 5

        need to write j records at offset: HEADER_SIZE + (cdb->header->start_record * RECORD_SIZE)
        index into records is i

        need to write i records at offset: HEADER_SIZE + (cdb->header->num_records * RECORD_SIZE)
        index into records is 0;
    */

    /* Calculate our indicies into the records array. */
    if (len + cdb->header->num_records >= cdb->header->max_records) {
        j = (len + cdb->header->num_records) - cdb->header->max_records;
        i = (len - j);
    } else {
        i = len;
    }

    /* If we need to wrap around */
    if (j > 0) {

        offset = HEADER_SIZE + (cdb->header->start_record * RECORD_SIZE);

        cdb->header->start_record += j;
        cdb->header->start_record %= cdb->header->max_records;

        if (pwrite(cdb->fd, &records[i], (RECORD_SIZE * j), offset) != (RECORD_SIZE * j)) {
            return cdb_error();
        }

        cdb->synced = false;

        /* start_record is no longer 0, so update the header */
        if (cdb_write_header(cdb) != CDB_SUCCESS) {
            return cdb_error();
        }
    }

    /* Normal case */
    offset = HEADER_SIZE + (cdb->header->num_records * RECORD_SIZE);
    cdb->header->num_records += i;

    if (pwrite(cdb->fd, &records[0], (RECORD_SIZE * i), offset) != (RECORD_SIZE * i)) {
        return cdb_error();
    }

    *num_recs += len;

#ifdef DEBUG
    printf("write_records: wrote [%"PRIu64"] records\n", *num_recs);
#endif

    return CDB_SUCCESS;
}

bool cdb_write_record(cdb_t *cdb, cdb_time_t time, double value) {

    cdb_record_t record[RECORD_SIZE];
    uint64_t num_recs = 0;

    record->time  = time;
    record->value = value;

    if (cdb_write_records(cdb, record, 1, &num_recs) != CDB_SUCCESS) {
        return false;
    }

    return true;
}

int cdb_update_records(cdb_t *cdb, cdb_record_t *records, uint64_t len, uint64_t *num_recs) {

    int ret    = CDB_SUCCESS;
    *num_recs  = 0;
    uint64_t i = 0;

    if (cdb_read_header(cdb) != CDB_SUCCESS) {
        return cdb_error();
    }

    if (_cdb_is_writable(cdb) == false) {
        return CDB_ERDONLY;
    }

#ifdef DEBUG
    printf("in update_records with [%"PRIu64"] num_recs\n", cdb->header->num_records);
#endif

    for (i = 0; i < len; i++) {

        cdb_time_t time = records[i].time;
        cdb_time_t rtime;
        uint64_t lrec;

        lrec = _logical_record_for_time(cdb, time, 0, 0);

        if (lrec >= 1) {
            lrec -= 1;
            /* DRK things like this are extremely confusing. some logical
               functions are zero based? some are one? or you're trying to back up? */
        }

        rtime = _time_for_logical_record(cdb, lrec);

        while (rtime < time && lrec < cdb->header->num_records - 1) {

            /* DRK is this true? or is the condition (lrec - start_lrec) <
               num_recs -- seems you can't wrap here (i.e. what if the initial
               lrec was num_recs - 1) */

            lrec += 1;
            rtime = _time_for_logical_record(cdb, lrec);
        }

#ifdef DEBUG
        printf("update_records: value: lrec [%"PRIu64"] time [%d] rtime [%d]\n", lrec, (int)time, (int)rtime);
#endif

        while (time == rtime && lrec < cdb->header->num_records - 1) {

            _seek_to_logical_record(cdb, lrec);

            if (write(cdb->fd, &records[0], RECORD_SIZE) != RECORD_SIZE) {
                ret = cdb_error();
                break;
            }

            lrec += 1;

            rtime = _time_for_logical_record(cdb, lrec);
        }
    }

    if (ret == CDB_SUCCESS) {

        if (i > 0) {
            cdb->synced = false;
            *num_recs = i;
        }

        if (cdb_write_header(cdb) != CDB_SUCCESS) {
            ret = cdb_error();
        }
    }

    return ret;
}

bool cdb_update_record(cdb_t *cdb, cdb_time_t time, double value) {

    cdb_record_t record[RECORD_SIZE];
    uint64_t num_recs = 0;

    record->time  = time;
    record->value = value;

    if (cdb_update_records(cdb, record, 1, &num_recs) != 0) {
        return false;
    }

    return true;
}

int cdb_discard_records_in_time_range(cdb_t *cdb, cdb_request_t *request, uint64_t *num_recs) {

    uint64_t i = 0;
    int64_t lrec;
    off_t offset = RECORD_SIZE;
    *num_recs = 0;

    if (cdb_read_header(cdb) != CDB_SUCCESS) {
        return cdb_error();
    }

    if (_cdb_is_writable(cdb) == false) {
        return CDB_ERDONLY;
    }

    lrec = _logical_record_for_time(cdb, request->start, 0, 0);

    if (lrec >= 1) {
        lrec -= 1;
    }

    for (i = lrec; i < cdb->header->num_records; i++) {

        cdb_time_t rtime = _time_for_logical_record(cdb, i);

        if (rtime >= request->start && rtime <= request->end) {

            cdb_record_t record[RECORD_SIZE];

            record->time  = rtime;
            record->value = CDB_NAN;

            if (pwrite(cdb->fd, &record, RECORD_SIZE, offset) != RECORD_SIZE) {
                return cdb_error();
            }

            *num_recs += 1;
        }
    }

    if (*num_recs > 0) {
        cdb->synced = false;
    }

    if (cdb_write_header(cdb) != CDB_SUCCESS) {
        return cdb_error();
    }

    return CDB_SUCCESS;
}

static int _compute_scale_factor_and_num_records(cdb_t *cdb, int64_t *num_records, int32_t *factor) {

    if (cdb->header->type == CDB_TYPE_COUNTER) {
        if (*num_records != 0) {

            if (*num_records > 0) {
                *num_records += 1;
            } else {
                *num_records -= 1;
            }
        }
    }

    if (strlen(cdb->header->units) > 0) {

        int32_t multiplier = 1;
        char *frequency;

        if ((frequency = calloc(strlen(cdb->header->units), sizeof(char))) == NULL) {
            return CDB_ENOMEM;
        }

        if ((sscanf(cdb->header->units, "per %d %s", &multiplier, frequency) == 2) ||
            (sscanf(cdb->header->units, "per %s", frequency) == 1) ||
            (sscanf(cdb->header->units, "%*s per %s", frequency) == 1)) {

            if (strcmp(frequency, "min") == 0) {
                *factor = 60;
            } else if (strcmp(frequency, "hour") == 0) {
                *factor = 60 * 60;
            } else if (strcmp(frequency, "sec") == 0 || strcmp(frequency, "second") == 0) {
                *factor = 1;
            } else if (strcmp(frequency, "day") == 0) {
                *factor = 60 * 60 * 24;
            } else if (strcmp(frequency, "week") == 0) {
                *factor = 60 * 60 * 24 * 7;
            } else if (strcmp(frequency, "month") == 0) {
                *factor = 60 * 60 * 24 * 30;
            } else if (strcmp(frequency, "quarter") == 0) {
                *factor = 60 * 60 * 24 * 90;
            } else if (strcmp(frequency, "year") == 0) {
                *factor = 60 * 60 * 24 * 365;
            }

            if (*factor != 0) {
                *factor *= multiplier;
            }
        }

        free(frequency);
    }

    return CDB_SUCCESS;
}

/* Statistics code
 * Make only one call to reading for a particular time range and compute all our stats
 */
void _compute_statistics(cdb_range_t *range, uint64_t *num_recs, cdb_record_t *records) {

    uint64_t i     = 0;
    uint64_t valid = 0;
    double sum     = 0.0;
    double *values = calloc(*num_recs, sizeof(double));

    for (i = 0; i < *num_recs; i++) {

        if (!isnan(records[i].value)) {

            sum += values[valid] = records[i].value;
            valid++;
        }
    }

    range->num_recs = valid;
    range->mean     = gsl_stats_mean(values, 1, valid);
    range->max      = gsl_stats_max(values, 1, valid);
    range->min      = gsl_stats_min(values, 1, valid);
    range->sum      = sum;
    range->stddev   = gsl_stats_sd(values, 1, valid);
    range->absdev   = gsl_stats_absdev(values, 1, valid);

    /* The rest need sorted data */
    gsl_sort(values, 1, valid);

    range->median   = gsl_stats_median_from_sorted_data(values, 1, valid);
    range->pct95th  = gsl_stats_quantile_from_sorted_data(values, 1, valid, 0.95);
    range->pct75th  = gsl_stats_quantile_from_sorted_data(values, 1, valid, 0.75);
    range->pct50th  = gsl_stats_quantile_from_sorted_data(values, 1, valid, 0.50);
    range->pct25th  = gsl_stats_quantile_from_sorted_data(values, 1, valid, 0.25);

    /* MAD must come last because it alters the values array
     * http://en.wikipedia.org/wiki/Median_absolute_deviation */
    for (i = 0; i < valid; i++) {
        values[i] = fabs(values[i] - range->median);

        if (values[i] < 0.0) {
            values[i] *= -1.0;
        }
    }

    /* Final sort is required MAD */
    gsl_sort(values, 1, valid);
    range->mad = gsl_stats_median_from_sorted_data(values, 1, valid);

    free(values);
}

double cdb_get_statistic(cdb_range_t *range, cdb_statistics_enum_t type) {

    switch (type) {
        case CDB_MEDIAN:
            return range->median;
        case CDB_MAD:
            return range->mad;
        case CDB_95TH:
            return range->pct95th;
        case CDB_75TH:
            return range->pct75th;
        case CDB_50TH:
            return range->pct50th;
        case CDB_25TH:
            return range->pct25th;
        case CDB_MEAN:
            return range->mean;
        case CDB_SUM:
            return range->sum;
        case CDB_MAX:
            return range->max;
        case CDB_MIN:
            return range->min;
        case CDB_STDDEV:
            return range->stddev;
        case CDB_ABSDEV:
            return range->absdev;
        default:
            fprintf(stderr, "aggregate_using_function_for_records() function: [%d] not supported\n", type);
            return CDB_FAILURE;
    }
}

static int _cdb_read_records(cdb_t *cdb, cdb_request_t *request, uint64_t *num_recs, cdb_record_t **records) {

    int64_t first_requested_logical_record;
    int64_t last_requested_logical_record;
    uint64_t last_requested_physical_record;
    int64_t seek_physical_record;

    cdb_record_t *buffer = NULL;

    if (cdb_read_header(cdb) != CDB_SUCCESS) {
        return cdb_error();
    }

    if (request->start != 0 && request->end != 0 && request->end < request->start) {
        return CDB_ETMRANGE;
    }

    if (cdb->header == NULL || cdb->synced == false) {
        return CDB_ESANITY;
    }

    /* bail out if there are no records */
    if (cdb->header->num_records <= 0) {
        return CDB_ENORECS;
    }

    /*
      get the number of requested records:

      -ve indicates n records from the beginning
      +ve indicates n records off of the end.
      0 or undef means the whole thing.

      switch the meaning of -ve/+ve to be more array like
    */
    if (request->count != 0) {
        request->count = -request->count;
    }

#ifdef DEBUG
    printf("read_records start: [%ld]\n", request->start);
    printf("read_records end: [%ld]\n", request->end);
    printf("read_records num_requested: [%"PRIu64"]\n", request->count);
#endif

    if (request->count != 0 && request->count < 0 && request->start == 0) {
        /* if reading only few records from the end, just set -ve offset to seek to */
        first_requested_logical_record = request->count;

    } else {
        /* compute which record to start reading from the beginning, based on start time specified. */
        first_requested_logical_record = _logical_record_for_time(cdb, request->start, 0, 0);
    }

    /* if end is not defined, read all the records or only read uptill the specified record. */
    if (request->end == 0) {

        last_requested_logical_record = cdb->header->num_records - 1;

    } else {

        last_requested_logical_record = _logical_record_for_time(cdb, request->end, 0, 0);

        /* this can return something > end, check for that */
        if (_time_for_logical_record(cdb, last_requested_logical_record) > request->end) {
            last_requested_logical_record -= 1;
        }
    }

    last_requested_physical_record = (last_requested_logical_record + cdb->header->start_record) % cdb->header->num_records;

    /* After _seek_to_logical_record(), we're at the offset to read from. */
    seek_physical_record = _seek_to_logical_record(cdb, first_requested_logical_record);

    if (last_requested_physical_record >= seek_physical_record) {

        uint64_t nrec = (last_requested_physical_record - seek_physical_record + 1);
        uint64_t rlen = RECORD_SIZE * nrec;

        if ((buffer = calloc(1, rlen)) == NULL) {
            free(buffer);
            return CDB_ENOMEM;
        }

        if (read(cdb->fd, buffer, rlen) != rlen) {
            free(buffer);
            return cdb_error();
        }

        *num_recs = nrec;

    } else {

        /* We've wrapped around the end of the file */
        uint64_t nrec1 = (cdb->header->num_records - seek_physical_record);
        uint64_t nrec2 = (last_requested_physical_record + 1);

        uint64_t rlen1 = RECORD_SIZE * nrec1;
        uint64_t rlen2 = RECORD_SIZE * nrec2;

        if ((buffer = calloc(1, rlen1 + rlen2)) == NULL) {
            free(buffer);
            return CDB_ENOMEM;
        }

        /* Read at the offset set by _seek_to_logical_record() */
        if (read(cdb->fd, buffer, rlen1) != rlen1) {
            free(buffer);
            return cdb_error();
        }

        /* And then the wrap around portion past the header. */
        if (pread(cdb->fd, &buffer[nrec1], rlen2, HEADER_SIZE) != rlen2) {
            free(buffer);
            return cdb_error();
        }

        *num_recs = nrec1 + nrec2;
    }

    /* Deal with cooking the output */
    if (request->cooked) {

        bool check_min_max = true;
        int32_t factor = 0;
        uint64_t i = 0;
        uint64_t cooked_recs = 0;
        double prev_value = 0.0;
        cdb_time_t prev_date = 0;
        cdb_record_t *crecords;

        if ((crecords = calloc(*num_recs, RECORD_SIZE)) == NULL) {
            free(crecords);
            free(buffer);
            return CDB_ENOMEM;
        }

        if (_compute_scale_factor_and_num_records(cdb, &request->count, &factor)) {
            free(crecords);
            free(buffer);
            return cdb_error();
        }

        if (cdb->header->min_value == 0 && cdb->header->max_value == 0) {
            check_min_max = false;
        }

        for (i = 0; i < *num_recs; i++) {

            cdb_time_t date = buffer[i].time;
            double value    = buffer[i].value;

            if (cdb->header->type == CDB_TYPE_COUNTER) {
                double new_value = value;
                value = CDB_NAN;

                if (!isnan(prev_value) && !isnan(new_value)) {

                    double val_delta = new_value - prev_value;

                    if (val_delta >= 0) {
                        value = val_delta;
                    }
                }

                prev_value = new_value;
            }

            if (factor != 0 && cdb->header->type == CDB_TYPE_COUNTER) {

                /* Skip the first entry, since it's absolute and is needed
                 * to calculate the second */
                if (prev_date == 0) {
                    prev_date = date;
                    continue;
                }

                cdb_time_t time_delta = date - prev_date;

                if (time_delta > 0 && !isnan(value)) {
                    value = factor * (value / time_delta);
                }

                prev_date = date;
            }

            /* Check for min/max boundaries */
            /* Should this be done on write instead of read? */
            if (check_min_max && !isnan(value)) {
                if (value > cdb->header->max_value || value < cdb->header->min_value) {
                    value = CDB_NAN;
                }
            }

            /* Copy the munged data to our new array, since we might skip
             * elements. Also keep in mind mmap for the future */
            crecords[cooked_recs].time  = date;
            crecords[cooked_recs].value = value;
            cooked_recs += 1;
        }

        /* Now swap our cooked records for the buffer, so we can slice it as needed. */
        free(buffer);
        buffer = crecords;
        *num_recs = cooked_recs;
    }

    /* If we've been requested to average the records & timestamps */
    if (request->step > 1) {

        cdb_record_t *arecords;
        uint32_t step      = request->step;
        uint64_t step_recs = 0;
        uint64_t leftover  = (*num_recs % step);
        uint64_t walkend   = (*num_recs - leftover);
        uint64_t i = 0;

        if ((arecords = calloc(((*num_recs / step) + leftover), RECORD_SIZE)) == NULL) {
            free(arecords);
            free(buffer);
            return CDB_ENOMEM;
        }

        /* Walk our list of cooked records, jumping ahead by the given step.
           For each set of records within that step, we want to get the average
           for those records and place them into a new array.
         */
        for (i = 0; i < walkend; i += step) {

            uint64_t j = 0;
            double xi[step];
            double yi[step];

            for (j = 0; j < step; j++) {

                /* No NaNs on average - they cause bogus graphs. Is there a
                 * better value than 0 to use here? */
                if (isnan(buffer[i+j].value)) {
                    buffer[i+j].value = 0;
                }

                xi[j] = (double)buffer[i+j].time;
                yi[j] = buffer[i+j].value;
            }

            arecords[step_recs].time  = (cdb_time_t)gsl_stats_mean(xi, 1, step);
            arecords[step_recs].value = gsl_stats_mean(yi, 1, step);
            step_recs += 1;
        }

        /* Now collect from the last step point to the end & average. */
        if (leftover > 0) {
            uint64_t leftover_start = *num_recs - leftover;

            uint64_t j = 0;
            double xi[leftover];
            double yi[leftover];

            for (i = leftover_start; i < *num_recs; i++) {

                /* No NaNs on average - they cause bogus graphs. Is there a
                 * better value than 0 to use here? */
                if (isnan(buffer[i].value)) {
                    buffer[i].value = 0;
                }

                xi[j] = (double)buffer[i].time;
                yi[j] = buffer[i].value;
                j++;
            }

            arecords[step_recs].time  = (cdb_time_t)gsl_stats_mean(xi, 1, j);
            arecords[step_recs].value = gsl_stats_mean(yi, 1, j);
            step_recs += 1;
        }

        free(buffer);
        buffer = arecords;
        *num_recs = step_recs;
    }

    /* now pull out the number of requested records if asked */
    if (request->count != 0 && *num_recs >= abs(request->count)) {

        uint64_t start_index = 0;

        if (request->count <= 0) {
            start_index = *num_recs - abs(request->count);
        }

        *num_recs = abs(request->count);

        if ((*records  = calloc(*num_recs, RECORD_SIZE)) == NULL) {
            free(buffer);
            return CDB_ENOMEM;
        }

        memcpy(*records, &buffer[start_index], RECORD_SIZE * *num_recs);

        free(buffer);

    } else {

        *records = buffer;
    }

    return CDB_SUCCESS;
}

int cdb_read_records(cdb_t *cdb, cdb_request_t *request,
    uint64_t *num_recs, cdb_record_t **records, cdb_range_t *range) {

    int ret   = CDB_SUCCESS;

    ret = _cdb_read_records(cdb, request, num_recs, records);

    if (ret == CDB_SUCCESS) {

        if (*num_recs > 0) {
            range->start_time = request->start;
            range->end_time   = request->end;

            _compute_statistics(range, num_recs, *records);
        }
    }

    return ret;
}

void cdb_print_records(cdb_t *cdb, cdb_request_t *request, FILE *fh, const char *date_format) {

    uint64_t i = 0;
    uint64_t num_recs = 0;

    cdb_record_t *records = NULL;

    if (_cdb_read_records(cdb, request, &num_recs, &records) == CDB_SUCCESS) {

        for (i = 0; i < num_recs; i++) {

            _print_record(fh, records[i].time, records[i].value, date_format);
        }
    }

    free(records);
}

void cdb_print(cdb_t *cdb) {

    const char *date_format = "%Y-%m-%d %H:%M:%S";
    cdb_request_t request;

    request.start  = 0;
    request.end    = 0;
    request.count  = 0;
    request.step   = 0;
    request.cooked = false;

    printf("============== Header ================\n");

    if (cdb_read_header(cdb) == CDB_SUCCESS) {
        cdb_print_header(cdb);
    }

    if (cdb->header->type == CDB_TYPE_COUNTER) {

        printf("============= Raw Counter Records =============\n");
        cdb_print_records(cdb, &request, stdout, date_format);
        printf("============== End Raw Counter Records ==============\n");

        printf("============== Cooked Records ================\n");

    } else {
        printf("============== Records ================\n");
    }

    request.cooked = true;
    cdb_print_records(cdb, &request, stdout, date_format);

    printf("============== End ================\n");
}

/* Take in an array of cdbs */
int cdb_read_aggregate_records(cdb_t **cdbs, int num_cdbs, cdb_request_t *request,
    uint64_t *driver_num_recs, cdb_record_t **records, cdb_range_t *range) {

    uint64_t i = 0;
    int ret    = CDB_SUCCESS;
    cdb_record_t *driver_records = NULL;
    *driver_num_recs = 0;

    if (cdbs[0] == NULL) {
        return CDB_ESANITY;
    }

    /* The first cdb is the driver */
    ret = _cdb_read_records(cdbs[0], request, driver_num_recs, &driver_records);

    if (ret != CDB_SUCCESS) {
        fprintf(stderr, "Bailed on: %s\n", cdbs[0]->filename);
        free(driver_records);
        return ret;
    }

    if ((*records = calloc(*driver_num_recs, RECORD_SIZE)) == NULL) {
        free(driver_records);
        return CDB_ENOMEM;
    }

    if (*driver_num_recs <= 1) {
        free(driver_records);
        return CDB_EINTERPD;
    }

    double *driver_x_values   = calloc(*driver_num_recs, sizeof(double));
    double *driver_y_values   = calloc(*driver_num_recs, sizeof(double));
    double *follower_x_values = calloc(*driver_num_recs, sizeof(double));
    double *follower_y_values = calloc(*driver_num_recs, sizeof(double));

    for (i = 0; i < *driver_num_recs; i++) {
        (*records)[i].time  = driver_x_values[i] = driver_records[i].time;
        (*records)[i].value = driver_y_values[i] = driver_records[i].value;
    }

    /* initialize and allocate the gsl objects  */
    gsl_interp_accel *accel = gsl_interp_accel_alloc();
    gsl_interp *interp = gsl_interp_alloc(gsl_interp_linear, *driver_num_recs);

    /* Allows 0.0 to be returned as a valid yi */
    gsl_set_error_handler_off();

    gsl_interp_init(interp, driver_x_values, driver_y_values, *driver_num_recs);

    for (i = 1; i < num_cdbs; i++) {

        uint64_t j = 0;
        uint64_t follower_num_recs = 0;

        cdb_record_t *follower_records = NULL;

        ret = _cdb_read_records(cdbs[i], request, &follower_num_recs, &follower_records);

        /* Just bail, free all allocations below and let the error bubble up */
        if (ret == CDB_SUCCESS && follower_num_recs != 0) {

            for (j = 0; j < *driver_num_recs; j++) {

                /* Check for out of bounds */
                if (j >= follower_num_recs) {
                    break;
                }

                follower_x_values[j] = follower_records[j].time;
                follower_y_values[j] = follower_records[j].value;
            }

            for (j = 0; j < *driver_num_recs; j++) {

                double yi = gsl_interp_eval(interp, follower_x_values, follower_y_values, driver_x_values[j], accel);

                if (isnormal(yi)) {
                    (*records)[j].value += yi;
                }
            }
        }

        free(follower_records);

        if (ret != CDB_SUCCESS) {
            break;
        }
    }

    if (ret == CDB_SUCCESS && *driver_num_recs > 0) {
        /* Compute all the statistics for this range */
        range->start_time = request->start;
        range->end_time   = request->end;

        _compute_statistics(range, driver_num_recs, *records);
    }

    free(driver_x_values);
    free(driver_y_values);
    free(follower_x_values);
    free(follower_y_values);

    gsl_interp_free(interp);
    gsl_interp_accel_free(accel);
    free(driver_records);

    return ret;
}

void cdb_print_aggregate_records(cdb_t **cdbs, int32_t num_cdbs, cdb_request_t *request, FILE *fh, const char *date_format) {

    uint64_t i = 0;
    uint64_t num_recs = 0;

    cdb_record_t *records = NULL;
    cdb_range_t *range = calloc(1, sizeof(cdb_range_t));

    cdb_read_aggregate_records(cdbs, num_cdbs, request, &num_recs, &records, range);

    for (i = 0; i < num_recs; i++) {

        _print_record(fh, records[i].time, records[i].value, date_format);
    }

    free(range);
    free(records);
}

void cdb_generate_header(cdb_t *cdb, char* name, char* desc, uint64_t max_records, int32_t type,
    char* units, uint64_t min_value, uint64_t max_value) {

    if (max_records == 0) {
        max_records = CDB_DEFAULT_RECORDS;
    }

    if (type == 0) {
        cdb->header->type = CDB_DEFAULT_DATA_TYPE;
    }

    if (units == NULL || (strcmp(units, "") == 0)) {
        units = (char*)CDB_DEFAULT_DATA_UNIT;
    }

    if (desc == NULL) {
        desc = (char*)"";
    }

    memset(cdb->header->name, 0, sizeof(cdb->header->name));
    memset(cdb->header->desc, 0, sizeof(cdb->header->desc));
    memset(cdb->header->units, 0, sizeof(cdb->header->units));
    memset(cdb->header->version, 0, sizeof(cdb->header->version));
    memset(cdb->header->token, 0, sizeof(cdb->header->token));

    strncpy(cdb->header->name, name, sizeof(cdb->header->name));
    strncpy(cdb->header->desc, desc, sizeof(cdb->header->desc));
    strncpy(cdb->header->units, units, sizeof(cdb->header->units));
    strncpy(cdb->header->version, CDB_VERSION, sizeof(cdb->header->version));
    strncpy(cdb->header->token, CDB_TOKEN, sizeof(cdb->header->token));

    cdb->header->type         = type;
    cdb->header->max_records  = max_records;
    cdb->header->min_value    = min_value;
    cdb->header->max_value    = max_value;
    cdb->header->num_records  = 0;
    cdb->header->start_record = 0;
}

cdb_t* cdb_new(void) {

    cdb_t *cdb  = calloc(1, sizeof(cdb_t));
    cdb->header = calloc(1, HEADER_SIZE);

    cdb->fd = -1;
    cdb->synced = false;
    cdb->flags = -1;
    cdb->mode = -1;

    return cdb;
}

cdb_request_t cdb_new_request(void) {
    cdb_request_t request;
    memset (&request, 0, sizeof (request));
    request.start  = 0;
    request.end    = 0;
    request.count  = 0;
    request.cooked = true;
    request.step   = 0;
    return request;
}

int cdb_open(cdb_t *cdb) {

    if (cdb->fd >= 0) {
        return CDB_SUCCESS;
    }

    /* Default flags if none were set */
    if (cdb->flags == -1) {
        cdb->flags = O_RDONLY|O_BINARY;
    }

    /* A cdb can't be write only - we need to read the header */
    if (cdb->flags & O_WRONLY) {
        cdb->flags = O_RDWR;
    }

    if (cdb->mode == -1) {
        cdb->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    }

    cdb->fd = open(cdb->filename, cdb->flags, cdb->mode);

    if (cdb->fd < 0) {
        return cdb_error();
    }

    return CDB_SUCCESS;
}

int cdb_close(cdb_t *cdb) {

    if (cdb != NULL) {

        if (cdb->fd > 0) {
            if (close(cdb->fd) != 0) {
                return cdb_error();
            }
            cdb->fd = -1;
        }
    }

    return CDB_SUCCESS;
}

int cdb_free(cdb_t *cdb) {
    int ret = CDB_SUCCESS;

    if (cdb != NULL) {

        if (cdb->header != NULL) {
            ret = cdb_close(cdb);
            free(cdb->header);
            cdb->header = NULL;
        }

        free(cdb);
        cdb = NULL;
    }

    return ret;
}

/* -*- Mode: C; tab-width: 4 -*- */
/* vim: set tabstop=4 expandtab shiftwidth=4: */


/* Copyright 2018 Los Alamos National Laboratory
 * Copyright 2009-2018 The University of Tennessee and The University
 *                     of Tennessee Research Foundation
 *
 * 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.
 */
#ifndef _TESTSCOMMON_H
#define _TESTSCOMMON_H

/* parsec things */
#include "parsec.h"

/* system and io */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* Plasma and math libs */
#include <math.h>
//#include <cblas.h>
//#include <lapacke.h>
//#include <core_blas.h>

#include "parsec/profiling.h"
#include "parsec/parsec_internal.h"
#include "parsec/utils/debug.h"
//#include "dplasma.h"

#ifdef __cplusplus
extern "C" {
#endif

/* these are globals in common.c */
extern const char *PARSEC_SCHED_NAME[];
extern int unix_timestamp;
extern char cwd[];

/* Update PASTE_CODE_PROGRESS_KERNEL below if you change this list */
enum iparam_t {
  IPARAM_RANK,         /* Rank                              */
  IPARAM_NNODES,       /* Number of nodes                   */
  IPARAM_NCORES,       /* Number of cores                   */
  IPARAM_NGPUS,        /* Number of GPUs                    */
  IPARAM_P,            /* Rows in the process grid          */
  IPARAM_Q,            /* Columns in the process grid       */
  IPARAM_M,            /* Number of rows of the matrix      */
  IPARAM_N,            /* Number of columns of the matrix   */
  IPARAM_K,            /* RHS or K                          */
  IPARAM_LDA,          /* Leading dimension of A            */
  IPARAM_LDB,          /* Leading dimension of B            */
  IPARAM_LDC,          /* Leading dimension of C            */
  IPARAM_IB,           /* Inner-blocking size               */
  IPARAM_NB,           /* Number of columns in a tile       */
  IPARAM_MB,           /* Number of rows in a tile          */
  IPARAM_SNB,          /* Number of columns in a super-tile */
  IPARAM_SMB,          /* Number of rows in a super-tile    */
  IPARAM_HMB,          /* Small MB for recursive hdags */
  IPARAM_HNB,          /* Small NB for recursive hdags */
  IPARAM_CHECK,        /* Checking activated or not         */
  IPARAM_VERBOSE,      /* How much noise do we want?        */
  IPARAM_SCHEDULER,    /* User-selected scheduler */
  IPARAM_SIZEOF
};

#define PARSEC_SCHEDULER_DEFAULT 0
#define PARSEC_SCHEDULER_LFQ 1
#define PARSEC_SCHEDULER_LTQ 2
#define PARSEC_SCHEDULER_AP  3
#define PARSEC_SCHEDULER_LHQ 4
#define PARSEC_SCHEDULER_GD  5
#define PARSEC_SCHEDULER_PBQ 6
#define PARSEC_SCHEDULER_IP  7
#define PARSEC_SCHEDULER_RND 8

void iparam_default_gemm(int* iparam);
void iparam_default_ibnbmb(int* iparam, int ib, int nb, int mb);

#define PASTE_CODE_IPARAM_LOCALS(iparam)                                \
    rank  = iparam[IPARAM_RANK];                                    \
    nodes = iparam[IPARAM_NNODES];                                  \
    cores = iparam[IPARAM_NCORES];                                  \
    gpus  = iparam[IPARAM_NGPUS];                                   \
    P     = iparam[IPARAM_P];                                       \
    Q     = iparam[IPARAM_Q];                                       \
    M     = iparam[IPARAM_M];                                       \
    N     = iparam[IPARAM_N];                                       \
    K     = iparam[IPARAM_K];                                       \
    NRHS  = K;                                                      \
    LDA   = max(M, iparam[IPARAM_LDA]);                             \
    LDB   = max(N, iparam[IPARAM_LDB]);                             \
    LDC   = max(K, iparam[IPARAM_LDC]);                             \
    IB    = iparam[IPARAM_IB];                                      \
    MB    = iparam[IPARAM_MB];                                      \
    NB    = iparam[IPARAM_NB];                                      \
    SMB   = iparam[IPARAM_SMB];                                     \
    SNB   = iparam[IPARAM_SNB];                                     \
    HMB   = iparam[IPARAM_HMB];                                     \
    HNB   = iparam[IPARAM_HNB];                                     \
    MT    = (M%MB==0) ? (M/MB) : (M/MB+1);                          \
    NT    = (N%NB==0) ? (N/NB) : (N/NB+1);                          \
    KT    = (K%MB==0) ? (K/MB) : (K/MB+1);                          \
    check = iparam[IPARAM_CHECK];                                   \
    loud  = iparam[IPARAM_VERBOSE];                                 \
    scheduler = iparam[IPARAM_SCHEDULER];                           \
    (void)rank;(void)nodes;(void)cores;(void)gpus;(void)P;(void)Q;(void)M;(void)N;(void)K;(void)NRHS; \
    (void)LDA;(void)LDB;(void)LDC;(void)IB;(void)MB;(void)NB;(void)MT;(void)NT;(void)KT; \
    (void)SMB;(void)SNB;(void)HMB;(void)HNB;(void)check;(void)loud; \
    (void)scheduler;

/*******************************
 * globals values
 *******************************/

#if defined(PARSEC_HAVE_MPI)
extern MPI_Datatype SYNCHRO;
#endif  /* PARSEC_HAVE_MPI */

void print_usage(void);
void print_arguments(int* iparam);

parsec_context_t *setup_parsec(int argc, char* argv[], int *iparam);
void cleanup_parsec(parsec_context_t* parsec, int *iparam);

/**
 * No macro with the name max or min is acceptable as there is
 * no way to correctly define them without borderline effects.
 */
#undef max
#undef min
static inline int max(int a, int b) { return a > b ? a : b; }
static inline int min(int a, int b) { return a < b ? a : b; }

/* Paste code to allocate a matrix in desc if cond_init is true */
#define PASTE_CODE_ALLOCATE_MATRIX(DC, COND, TYPE, INIT_PARAMS)      \
    if(COND) {                                                          \
        DC.mat = parsec_data_allocate((size_t)DC.super.nb_local_tiles * \
                                        (size_t)DC.super.bsiz *      \
                                        (size_t)parsec_datadist_getsizeoftype(DC.super.mtype)); \
        parsec_data_collection_set_key((parsec_data_collection_t*)&DC, #DC);          \
    }

#ifdef __cplusplus
}
#endif

#endif /* _TESTSCOMMON_H */


#ifndef Performance_h
#define Performance_h 1
#include <vector>

#include <gsl/gsl_errno.h>

// if p0 is less than chop, then set to zero, associated with calling routine chop
const double chop = 1e-3;
const double p1bound = 1e-5;

void debugPerformanceOn(unsigned);

enum class signalType {output, controlOpen, controlClosed};

double performance(const std::vector<double>& num, const std::vector<double>& den,
					double gamma, double tmax, signalType s);

// GSL error handling: call setGSLErrorHandle(s), s = 0 turns off error handler, 1 sets my handler; should check return status of all significant GSL calls and take appropriate action within code, for example return high performance value and thus zero fitness if cannot evaluate performance for parameter combination
inline void my_gsl_handler (const char *reason, const char *file, int line, int gsl_errno __attribute__((unused)))
{std::cout << fmt::format("GSL error: {}:{}, {}\n", file, line, reason);}
inline void setGSLErrorHandle(int s)
    {(s) ? gsl_set_error_handler(&my_gsl_handler) : gsl_set_error_handler_off();}

#endif


/* fp-win.c
 *
 * Author: Brian Gladman
 *
 * 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.
 */

#include <float.h>

#include <config.h>
#include <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_errno.h>

const char *fp_env_string = "round-to-nearest,double-precision,mask-all";

int
gsl_ieee_set_mode (int precision, int rounding, int exception_mask)
{
	unsigned int old, mode = _DN_SAVE, mask = _MCW_DN | _MCW_RC | _MCW_EM;

	switch(precision)
    {
    case GSL_IEEE_SINGLE_PRECISION:		mode |= _PC_24; break;
    case GSL_IEEE_EXTENDED_PRECISION:	mode |= _PC_64; break;
    case GSL_IEEE_DOUBLE_PRECISION:
    default:							mode |= _PC_53;
	}

	/* precison control is disabled on Windows x64 with MSVC
	   but is allowed by the Intel compiler
	*/
#if !defined( _WIN64 ) || defined( __ICL )
	mask |= _MCW_PC;
#endif

	switch(rounding)
    {
    case GSL_IEEE_ROUND_DOWN:			mode |= _RC_DOWN; break;
    case GSL_IEEE_ROUND_UP:				mode |= _RC_UP;   break;
    case GSL_IEEE_ROUND_TO_ZERO:		mode |= _RC_CHOP; break;
    case GSL_IEEE_ROUND_TO_NEAREST:
    default:							mode |= _RC_NEAR;
    }

	if(exception_mask & GSL_IEEE_MASK_INVALID)
		mode |= _EM_INVALID;
	if(exception_mask & GSL_IEEE_MASK_DENORMALIZED)
		mode |= _EM_DENORMAL;
	if(exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
		mode |= _EM_ZERODIVIDE;
	if(exception_mask & GSL_IEEE_MASK_OVERFLOW)
		mode |= _EM_OVERFLOW;
	if(exception_mask & GSL_IEEE_MASK_UNDERFLOW)
		mode |= _EM_UNDERFLOW;
	if(exception_mask & GSL_IEEE_TRAP_INEXACT)
		mode &= ~_EM_INEXACT;
	else
		mode |= _EM_INEXACT;

	_clearfp();
	_controlfp_s(&old, mode, mask);
	return GSL_SUCCESS;
}


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

#ifndef __GSL_VECTOR_INT_H__
#define __GSL_VECTOR_INT_H__

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

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_block_int.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 size;
  size_t stride;
  int *data;
  gsl_block_int *block;
  int owner;
}
gsl_vector_int;

typedef struct
{
  gsl_vector_int vector;
} _gsl_vector_int_view;

typedef _gsl_vector_int_view gsl_vector_int_view;

typedef struct
{
  gsl_vector_int vector;
} _gsl_vector_int_const_view;

typedef const _gsl_vector_int_const_view gsl_vector_int_const_view;

/* Allocation */

GSL_FUN gsl_vector_int *gsl_vector_int_alloc (const size_t n);
GSL_FUN gsl_vector_int *gsl_vector_int_calloc (const size_t n);

GSL_FUN gsl_vector_int *gsl_vector_int_alloc_from_block (gsl_block_int * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

GSL_FUN gsl_vector_int *gsl_vector_int_alloc_from_vector (gsl_vector_int * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

GSL_FUN void gsl_vector_int_free (gsl_vector_int * v);

/* Views */

GSL_FUN _gsl_vector_int_view
gsl_vector_int_view_array (int *v, size_t n);

GSL_FUN _gsl_vector_int_view
gsl_vector_int_view_array_with_stride (int *base,
                                         size_t stride,
                                         size_t n);

GSL_FUN _gsl_vector_int_const_view
gsl_vector_int_const_view_array (const int *v, size_t n);

GSL_FUN _gsl_vector_int_const_view
gsl_vector_int_const_view_array_with_stride (const int *base,
                                               size_t stride,
                                               size_t n);

GSL_FUN _gsl_vector_int_view
gsl_vector_int_subvector (gsl_vector_int *v,
                            size_t i,
                            size_t n);

GSL_FUN _gsl_vector_int_view
gsl_vector_int_subvector_with_stride (gsl_vector_int *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

GSL_FUN _gsl_vector_int_const_view
gsl_vector_int_const_subvector (const gsl_vector_int *v,
                                  size_t i,
                                  size_t n);

GSL_FUN _gsl_vector_int_const_view
gsl_vector_int_const_subvector_with_stride (const gsl_vector_int *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

GSL_FUN void gsl_vector_int_set_zero (gsl_vector_int * v);
GSL_FUN void gsl_vector_int_set_all (gsl_vector_int * v, int x);
GSL_FUN int gsl_vector_int_set_basis (gsl_vector_int * v, size_t i);

GSL_FUN int gsl_vector_int_fread (FILE * stream, gsl_vector_int * v);
GSL_FUN int gsl_vector_int_fwrite (FILE * stream, const gsl_vector_int * v);
GSL_FUN int gsl_vector_int_fscanf (FILE * stream, gsl_vector_int * v);
GSL_FUN int gsl_vector_int_fprintf (FILE * stream, const gsl_vector_int * v,
                              const char *format);

GSL_FUN int gsl_vector_int_memcpy (gsl_vector_int * dest, const gsl_vector_int * src);

GSL_FUN int gsl_vector_int_reverse (gsl_vector_int * v);

GSL_FUN int gsl_vector_int_swap (gsl_vector_int * v, gsl_vector_int * w);
GSL_FUN int gsl_vector_int_swap_elements (gsl_vector_int * v, const size_t i, const size_t j);

GSL_FUN int gsl_vector_int_max (const gsl_vector_int * v);
GSL_FUN int gsl_vector_int_min (const gsl_vector_int * v);
GSL_FUN void gsl_vector_int_minmax (const gsl_vector_int * v, int * min_out, int * max_out);

GSL_FUN size_t gsl_vector_int_max_index (const gsl_vector_int * v);
GSL_FUN size_t gsl_vector_int_min_index (const gsl_vector_int * v);
GSL_FUN void gsl_vector_int_minmax_index (const gsl_vector_int * v, size_t * imin, size_t * imax);

GSL_FUN int gsl_vector_int_add (gsl_vector_int * a, const gsl_vector_int * b);
GSL_FUN int gsl_vector_int_sub (gsl_vector_int * a, const gsl_vector_int * b);
GSL_FUN int gsl_vector_int_mul (gsl_vector_int * a, const gsl_vector_int * b);
GSL_FUN int gsl_vector_int_div (gsl_vector_int * a, const gsl_vector_int * b);
GSL_FUN int gsl_vector_int_scale (gsl_vector_int * a, const int x);
GSL_FUN int gsl_vector_int_add_constant (gsl_vector_int * a, const double x);
GSL_FUN int gsl_vector_int_axpby (const int alpha, const gsl_vector_int * x, const int beta, gsl_vector_int * y);
GSL_FUN int gsl_vector_int_sum (const gsl_vector_int * a);

GSL_FUN int gsl_vector_int_equal (const gsl_vector_int * u,
                            const gsl_vector_int * v);

GSL_FUN int gsl_vector_int_isnull (const gsl_vector_int * v);
GSL_FUN int gsl_vector_int_ispos (const gsl_vector_int * v);
GSL_FUN int gsl_vector_int_isneg (const gsl_vector_int * v);
GSL_FUN int gsl_vector_int_isnonneg (const gsl_vector_int * v);

GSL_FUN INLINE_DECL int gsl_vector_int_get (const gsl_vector_int * v, const size_t i);
GSL_FUN INLINE_DECL void gsl_vector_int_set (gsl_vector_int * v, const size_t i, int x);
GSL_FUN INLINE_DECL int * gsl_vector_int_ptr (gsl_vector_int * v, const size_t i);
GSL_FUN INLINE_DECL const int * gsl_vector_int_const_ptr (const gsl_vector_int * v, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
int
gsl_vector_int_get (const gsl_vector_int * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

INLINE_FUN
void
gsl_vector_int_set (gsl_vector_int * v, const size_t i, int x)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

INLINE_FUN
int *
gsl_vector_int_ptr (gsl_vector_int * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (int *) (v->data + i * v->stride);
}

INLINE_FUN
const int *
gsl_vector_int_const_ptr (const gsl_vector_int * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= v->size))
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const int *) (v->data + i * v->stride);
}
#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_INT_H__ */


#pragma once

#include <gsl\gsl>
#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include "DrawableGameComponent.h"
#include "MatrixHelper.h"
#include "PointLight.h"
#include "DepthMap.h"
#include "Rectangle.h"
#include "ShadowMappingMaterial.h"
#include "RenderStateHelper.h"

namespace DirectX
{
	class SpriteBatch;
}

namespace Library
{
	class ProxyModel;
	class RenderableFrustum;
	class DepthMapMaterial;
}

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

		ShadowMappingDrawModes DrawMode() const;
		const std::string& DrawModeString() const;
		void SetDrawMode(ShadowMappingDrawModes drawMode);

		float DepthBias() const;
		void SetDepthBias(float bias);

		float SlopeScaledDepthBias() const;
		void SetSlopeScaledDepthBias(float bias);

		float AmbientLightIntensity() const;
		void SetAmbientLightIntensity(float intensity);

		float PointLightIntensity() const;
		void SetPointLightIntensity(float intensity);

		float PointLightRadius() const;
		void SetPointLightRadius(float radius);

		const Library::Camera& Projector() const;
		const DirectX::XMFLOAT3& ProjectorPosition() const;
		const DirectX::XMVECTOR ProjectorPositionVector() const;
		void SetProjectorPosition(const DirectX::XMFLOAT3& position);
		void SetProjectorPosition(DirectX::FXMVECTOR position);
		const DirectX::XMFLOAT3& ProjectorDirection() const;
		void RotateProjector(const DirectX::XMFLOAT2& amount);

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

	private:
		inline static const std::uint32_t ShadowMapWidth{ 1024 };
		inline static const std::uint32_t ShadowMapHeight{ 1024 };
		static inline const RECT ShadowMapDestinationRectangle{ 0, 512, 256, 768 };

		inline static DirectX::XMFLOAT4X4 mProjectedTextureScalingMatrix
		{
			0.5f,  0.0f, 0.0f, 0.0f,
			0.0f, -0.5f, 0.0f, 0.0f,
			0.0f,  0.0f, 1.0f, 0.0f,
			0.5f,  0.5f, 0.0f, 1.0f
		};

		void UpdateTransforms(ShadowMappingMaterial::VertexCBufferPerObject& transforms, DirectX::FXMMATRIX worldViewProjectionMatrix, DirectX::CXMMATRIX worldMatrix, DirectX::CXMMATRIX projectiveTextureMatrix);
		void UpdateDepthBiasRasterizerState();

		ShadowMappingMaterial::VertexCBufferPerObject mPlaneTransforms;
		ShadowMappingMaterial::VertexCBufferPerObject mTeapotTransforms;
		DirectX::XMFLOAT4X4 mPlaneWorldMatrix{ Library::MatrixHelper::Identity };
		DirectX::XMFLOAT4X4 mTeapotWorldMatrix{ Library::MatrixHelper::Identity };

		Library::PointLight mPointLight;
		Library::DepthMap mShadowMap;
		Library::RenderStateHelper mRenderStateHelper;
		std::shared_ptr<ShadowMappingMaterial> mMaterial;
		std::shared_ptr<Library::DepthMapMaterial> mDepthMapMaterial;
		winrt::com_ptr<ID3D11Buffer> mPlaneVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mTeapotVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mTeapotPositionOnlyVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mTeapotIndexBuffer;
		std::uint32_t mPlaneVertexCount{ 0 };
		std::uint32_t mTeapotIndexCount{ 0 };
		std::unique_ptr<Library::ProxyModel> mProxyModel;
		std::unique_ptr<Library::Camera> mProjector;
		std::unique_ptr<Library::RenderableFrustum> mRenderableProjectorFrustum;
		std::unique_ptr<DirectX::SpriteBatch> mSpriteBatch;
		bool mUpdateMaterial{ true };
		float mDepthBias{ 0.0f };
		float mSlopeScaledDepthBias{ 2.0f };
		winrt::com_ptr<ID3D11RasterizerState> mDepthBiasState;
	};
}


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

#ifndef __GSL_MATRIX_DOUBLE_H__
#define __GSL_MATRIX_DOUBLE_H__

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

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

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  double * data;
  gsl_block * block;
  int owner;
} gsl_matrix;

typedef struct
{
  gsl_matrix matrix;
} _gsl_matrix_view;

typedef _gsl_matrix_view gsl_matrix_view;

typedef struct
{
  gsl_matrix matrix;
} _gsl_matrix_const_view;

typedef const _gsl_matrix_const_view gsl_matrix_const_view;

/* Allocation */

GSL_FUN gsl_matrix *
gsl_matrix_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix *
gsl_matrix_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix *
gsl_matrix_alloc_from_block (gsl_block * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_FUN gsl_matrix *
gsl_matrix_alloc_from_matrix (gsl_matrix * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN gsl_vector *
gsl_vector_alloc_row_from_matrix (gsl_matrix * m,
                                        const size_t i);

GSL_FUN gsl_vector *
gsl_vector_alloc_col_from_matrix (gsl_matrix * m,
                                        const size_t j);

GSL_FUN void gsl_matrix_free (gsl_matrix * m);

/* Views */

GSL_FUN _gsl_matrix_view
gsl_matrix_submatrix (gsl_matrix * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_view
gsl_matrix_row (gsl_matrix * m, const size_t i);

GSL_FUN _gsl_vector_view
gsl_matrix_column (gsl_matrix * m, const size_t j);

GSL_FUN _gsl_vector_view
gsl_matrix_diagonal (gsl_matrix * m);

GSL_FUN _gsl_vector_view
gsl_matrix_subdiagonal (gsl_matrix * m, const size_t k);

GSL_FUN _gsl_vector_view
gsl_matrix_superdiagonal (gsl_matrix * m, const size_t k);

GSL_FUN _gsl_vector_view
gsl_matrix_subrow (gsl_matrix * m, const size_t i,
                         const size_t offset, const size_t n);

GSL_FUN _gsl_vector_view
gsl_matrix_subcolumn (gsl_matrix * m, const size_t j,
                            const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_view
gsl_matrix_view_array (double * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_view
gsl_matrix_view_array_with_tda (double * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_view
gsl_matrix_view_vector (gsl_vector * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_view
gsl_matrix_view_vector_with_tda (gsl_vector * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_const_view
gsl_matrix_const_submatrix (const gsl_matrix * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_row (const gsl_matrix * m,
                            const size_t i);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_column (const gsl_matrix * m,
                               const size_t j);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_diagonal (const gsl_matrix * m);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_subdiagonal (const gsl_matrix * m,
                                    const size_t k);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_superdiagonal (const gsl_matrix * m,
                                      const size_t k);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_subrow (const gsl_matrix * m, const size_t i,
                               const size_t offset, const size_t n);

GSL_FUN _gsl_vector_const_view
gsl_matrix_const_subcolumn (const gsl_matrix * m, const size_t j,
                                  const size_t offset, const size_t n);

GSL_FUN _gsl_matrix_const_view
gsl_matrix_const_view_array (const double * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_const_view
gsl_matrix_const_view_array_with_tda (const double * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_const_view
gsl_matrix_const_view_vector (const gsl_vector * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_const_view
gsl_matrix_const_view_vector_with_tda (const gsl_vector * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_set_zero (gsl_matrix * m);
GSL_FUN void gsl_matrix_set_identity (gsl_matrix * m);
GSL_FUN void gsl_matrix_set_all (gsl_matrix * m, double x);

GSL_FUN int gsl_matrix_fread (FILE * stream, gsl_matrix * m) ;
GSL_FUN int gsl_matrix_fwrite (FILE * stream, const gsl_matrix * m) ;
GSL_FUN int gsl_matrix_fscanf (FILE * stream, gsl_matrix * m);
GSL_FUN int gsl_matrix_fprintf (FILE * stream, const gsl_matrix * m, const char * format);

GSL_FUN int gsl_matrix_memcpy(gsl_matrix * dest, const gsl_matrix * src);
GSL_FUN int gsl_matrix_swap(gsl_matrix * m1, gsl_matrix * m2);
GSL_FUN int gsl_matrix_tricpy(CBLAS_UPLO_t Uplo, CBLAS_DIAG_t Diag, gsl_matrix * dest, const gsl_matrix * src);

GSL_FUN int gsl_matrix_swap_rows(gsl_matrix * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_swap_columns(gsl_matrix * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_swap_rowcol(gsl_matrix * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_transpose (gsl_matrix * m);
GSL_FUN int gsl_matrix_transpose_memcpy (gsl_matrix * dest, const gsl_matrix * src);
GSL_FUN int gsl_matrix_transpose_tricpy (CBLAS_UPLO_t Uplo_src, CBLAS_DIAG_t Diag, gsl_matrix * dest, const gsl_matrix * src);

GSL_FUN double gsl_matrix_max (const gsl_matrix * m);
GSL_FUN double gsl_matrix_min (const gsl_matrix * m);
GSL_FUN void gsl_matrix_minmax (const gsl_matrix * m, double * min_out, double * max_out);

GSL_FUN void gsl_matrix_max_index (const gsl_matrix * m, size_t * imax, size_t *jmax);
GSL_FUN void gsl_matrix_min_index (const gsl_matrix * m, size_t * imin, size_t *jmin);
GSL_FUN void gsl_matrix_minmax_index (const gsl_matrix * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_FUN int gsl_matrix_equal (const gsl_matrix * a, const gsl_matrix * b);

GSL_FUN int gsl_matrix_isnull (const gsl_matrix * m);
GSL_FUN int gsl_matrix_ispos (const gsl_matrix * m);
GSL_FUN int gsl_matrix_isneg (const gsl_matrix * m);
GSL_FUN int gsl_matrix_isnonneg (const gsl_matrix * m);

GSL_FUN double gsl_matrix_norm1 (const gsl_matrix * m);

GSL_FUN int gsl_matrix_add (gsl_matrix * a, const gsl_matrix * b);
GSL_FUN int gsl_matrix_sub (gsl_matrix * a, const gsl_matrix * b);
GSL_FUN int gsl_matrix_mul_elements (gsl_matrix * a, const gsl_matrix * b);
GSL_FUN int gsl_matrix_div_elements (gsl_matrix * a, const gsl_matrix * b);
GSL_FUN int gsl_matrix_scale (gsl_matrix * a, const double x);
GSL_FUN int gsl_matrix_scale_rows (gsl_matrix * a, const gsl_vector * x);
GSL_FUN int gsl_matrix_scale_columns (gsl_matrix * a, const gsl_vector * x);
GSL_FUN int gsl_matrix_add_constant (gsl_matrix * a, const double x);
GSL_FUN int gsl_matrix_add_diagonal (gsl_matrix * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_get_row(gsl_vector * v, const gsl_matrix * m, const size_t i);
GSL_FUN int gsl_matrix_get_col(gsl_vector * v, const gsl_matrix * m, const size_t j);
GSL_FUN int gsl_matrix_set_row(gsl_matrix * m, const size_t i, const gsl_vector * v);
GSL_FUN int gsl_matrix_set_col(gsl_matrix * m, const size_t j, const gsl_vector * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL double   gsl_matrix_get(const gsl_matrix * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void    gsl_matrix_set(gsl_matrix * m, const size_t i, const size_t j, const double x);
GSL_FUN INLINE_DECL double * gsl_matrix_ptr(gsl_matrix * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const double * gsl_matrix_const_ptr(const gsl_matrix * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE
INLINE_FUN
double
gsl_matrix_get(const gsl_matrix * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      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] ;
}

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

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

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

#endif

__END_DECLS

#endif /* __GSL_MATRIX_DOUBLE_H__ */


/*

Excited States software: KGS
Contributors: See CONTRIBUTORS.txt
Contact: kgs-contact@simtk.org

Copyright (C) 2009-2017 Stanford University

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:

This entire text, including 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, CONTRIBUTORS 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 KGS_DIRECTION_H
#define KGS_DIRECTION_H

#include <gsl/gsl_vector.h>

#include "core/Configuration.h"

/**
 * Implementing sub-classes specify different methods of computing gradients.
 */
class Direction {
 public:
  virtual ~Direction() = 0;

  /**
   * Compute a gradient for the configuration `conf` and store the result in `ret`.
   * A target configuration can be specified if the implementing subclass performs directed
   * gradients. If not the target will be ignored.
   *
   * Any values stored in the `ret` vector will be overwritten by this function so there is
   * no need to reset it to zero before use.
   *
   * \pre  { `conf` and `ret` are both non-nullptr }
   * \post { All values in `ret` are guaranteed to be in the the range -π to π. }
   */
  void gradient(Configuration* conf, Configuration* target, gsl_vector* ret);

 protected:
  virtual void computeGradient(Configuration* conf, Configuration* target, gsl_vector* ret) = 0;

};

#endif //KGS_DIRECTION_H


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <php.h>
#include <cblas.h>
#include "kernel/operators.h"

/**
 * Sets the number of threads to use when parallel processesing.
 *
 * @param return_value
 * @param threads
 */
void tensor_set_num_threads(zval * return_value, zval * threads)
{
    int n = zephir_get_intval(threads);

    openblas_set_num_threads(n);

    RETURN_TRUE;
}

/**
 * Return the number of threads to use when parallel processesing.
 *
 * @param return_value
 */
void tensor_get_num_threads(zval * return_value)
{
    long threads = openblas_get_num_threads();

    RETURN_LONG(threads);
}


#include <petsc.h>
#include "quantum_gates.h"

void projectq_qasm_read(char[],PetscInt*,circuit*);
void projectq_vqe_get_expectation(char[],Vec,PetscScalar*);
void _projectq_qasm_add_gate(char*,circuit*,PetscReal);
void projectq_vqe_get_expectation_encoded(char[],Vec,PetscScalar*,PetscInt,...);
void qiskit_qasm_read(char[],PetscInt*,circuit*);
void _qiskit_qasm_add_gate(char*,circuit*,PetscReal);
void qiskit_vqe_get_expectation(char[],Vec,PetscScalar*);
void quil_read(char[],PetscInt*,circuit*);
void _quil_add_gate(char*,circuit*,PetscReal);
void _quil_get_angle_pi(char[],PetscReal*);