/* Copyright (c) 2020 Stijn Hinterding, Utrecht University
 * This sofware is licensed under the MIT license (see the LICENSE file)
*/

#ifndef FAKECOMMUNICATOR_H
#define FAKECOMMUNICATOR_H

#include <phast_gui/interfaces/itimetaggercommunicator.h>

#include <gsl/gsl_rng.h>
#include <chrono>
#include <mutex>

class FakeCommunicator : public ITimeTaggerCommunicator
{
private:
    gsl_rng* r;
    double timeunit_seconds;
    double decayrate_inv_seconds;
    double pulse_period_seconds;
    double detection_probability;

    std::chrono::time_point<std::chrono::high_resolution_clock> prev_time;
    bool first_run;

    int64_t last_largest_time;
    int64_t last_pulse_time;
    int64_t pulse_period_timeunits;
    int64_t last_pulse_published;
    uint64_t sync_counter;
    uint64_t sync_divider;

    int64_t chan1_induced_delay;
    int64_t chan2_induced_delay;

    std::string descriptor;

    bool chan0_enabled;
    bool chan1_enabled;
    bool chan2_enabled;

    bool is_running;

    double sim_speedup_factor;
    std::mutex m;

    std::map<chan_id,timestamp> first_times;
    std::map<chan_id,timestamp> last_times;
    std::map<chan_id,uint64_t> n_events;

    int64_t n_emitters;
private:
    void gen_pulses(std::vector<int64_t> *timestamps,
                    std::vector<uint8_t> *channel_IDs, int64_t duration);

public:
    FakeCommunicator(const FakeCommunicator&) = delete;
    FakeCommunicator& operator=(const FakeCommunicator&) = delete;
    ~FakeCommunicator() override;

    FakeCommunicator(double timeunit_seconds,
                     double decayrate_inv_seconds,
                     double pulse_period_seconds,
                     double detection_probability,
                     uint64_t sync_divider=128,
                     int64_t chan1_induced_delay=0,
                     int64_t chan2_induced_delay=0,
                     int64_t n_emitters=1,
                     double sim_speedup_factor=1);

    void SetSimSpeedupFactor(double value)
    {
        std::lock_guard<std::mutex> l(this->m);
        if (value <= 0.001)
            value = 0.001;

        this->sim_speedup_factor = value;
    }

    double GetSimSpeedupFactor() const
    {
        return this->sim_speedup_factor;
    }

    void SetDecayRate(double value)
    {
        std::lock_guard<std::mutex> l(this->m);
        this->decayrate_inv_seconds = value;
    }

    int64_t GetNumEmitters() const
    {
        return this->n_emitters;
    }

    double GetDecayRate() const
    {
        return this->decayrate_inv_seconds;
    }

    void SetNumEmitters(int64_t value)
    {
        std::lock_guard<std::mutex> l(this->m);

        if (value == 0)
            value = 1;

        this->n_emitters = value;
    }
    void SetPulsePeriod(double value)
    {
        std::lock_guard<std::mutex> l(this->m);
        this->pulse_period_seconds = value;
        this->pulse_period_timeunits = this->pulse_period_seconds/this->timeunit_seconds;
    }

    double GetPulsePeriod() const
    {
        return this->pulse_period_seconds;
    }

    void SetDetectionProbability(double value)
    {
        std::lock_guard<std::mutex> l(this->m);
        if (value > 1.0)
            value = 1.0;

        if (value < 0.0)
            value = 0.0;

        this->detection_probability = value;
    }

    double GetDetectionProbability() const
    {
        return this->detection_probability;
    }

    void SetSyncDivider(uint64_t value)
    {
        std::lock_guard<std::mutex> l(this->m);
        this->sync_divider = value;
    }

    virtual uint64_t ReceiveData(std::vector<int64_t>* timestamps,
                             std::vector<uint8_t>* channel_IDs) override;

    virtual uint64_t GetSyncDivider(chan_id channel_id) override
    {
        if (channel_id == 0)
            return this->sync_divider;

        return 1;
    }

    virtual void DisableChan(uint64_t ID);

    virtual bool ConnectedToDevice() override
    {
        return true;
    }

    virtual const std::string& DeviceDescriptor() const override
    {
        return this->descriptor;
    }

    virtual bool TryToConnect(int64_t) override
    {
        return true;
    }

    virtual bool DataLossSinceLastCall() override
    {
        return false;
    }

    virtual double TimeUnit() const override
    {
        return this->timeunit_seconds;
    }

    virtual bool AnyDeviceAvailable() const override
    {
        return true;
    }

    virtual bool Disconnect() override
    {
        return true;
    }

    virtual uint64_t GetNumDevicesConnected() override
    {
        return 1;
    }

    virtual bool IsRealDevice() const
    {
        return false;
    }
};

#endif // FAKECOMMUNICATOR_H


// Precompiled headers go in here
#pragma once

// Standard Library Header
#include <format>
#include <fstream>
#include <memory>
#include <stdexcept>
#include <random>
#include <algorithm>
#include <utility>
#include <mutex>
#include <shared_mutex>
#include <execution>
#include <optional>
#include <iostream>

// Data structures
#include <string>
#include <vector>
#include <array>

// GSL: Guidelines Support Library
//#include <gsl/gsl>

// Extern libs
#include "fmt/core.h"
#include "nlohmann/json.hpp"

// My
#include "Enums.h"
#include "RandomNumbers.h"
#include "Statistics.h"
#include "Disease/Disease.h"
#include "Disease/Infection.h"
#include "Person/Person.h"
#include "Places/Places.h"
#include "Places/Community.h"
#include "Simulation/MeasureTime.h"


#ifndef __SIMQ_H
#define __SIMQ_H

#include "Queue.h"
#include "statistics.h"
#include "input.h"
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Defining non-queue function prototypes */
Customer* createCustomer(gsl_rng **);
gsl_rng * randomGenerator();
void validateArgs(int, char **);
#endif


#ifndef __LINALG_LIB_WRAPPER_H__
#define __LINALG_LIB_WRAPPER_H__

// Wrapper for linear algebra library (BLAS, LAPACK)

#if !defined(USE_MKL) && !defined(USE_OPENBLAS)
#define USE_OPENBLAS
#endif

#ifdef USE_MKL
#include <mkl.h>
#define BLAS_SET_NUM_THREADS mkl_set_num_threads
#endif

#ifdef USE_OPENBLAS
#include <cblas.h>
#include <lapacke.h>
#define BLAS_SET_NUM_THREADS openblas_set_num_threads
#endif

#endif


/* multiset/gsl_multiset.h
 * based on combination/gsl_combination.h by Szymon Jaroszewicz
 * based on permutation/gsl_permutation.h by Brian Gough
 *
 * Copyright (C) 2009 Rhys Ulerich
 *
 * 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_MULTISET_H__
#define __GSL_MULTISET_H__

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

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

__BEGIN_DECLS

struct gsl_multiset_struct
{
  size_t n;
  size_t k;
  size_t *data;
};

typedef struct gsl_multiset_struct gsl_multiset;

gsl_multiset *gsl_multiset_alloc (const size_t n, const size_t k);
gsl_multiset *gsl_multiset_calloc (const size_t n, const size_t k);
void gsl_multiset_init_first (gsl_multiset * c);
void gsl_multiset_init_last (gsl_multiset * c);
void gsl_multiset_free (gsl_multiset * c);
int gsl_multiset_memcpy (gsl_multiset * dest, const gsl_multiset * src);

int gsl_multiset_fread (FILE * stream, gsl_multiset * c);
int gsl_multiset_fwrite (FILE * stream, const gsl_multiset * c);
int gsl_multiset_fscanf (FILE * stream, gsl_multiset * c);
int gsl_multiset_fprintf (FILE * stream, const gsl_multiset * c, const char *format);

size_t gsl_multiset_n (const gsl_multiset * c);
size_t gsl_multiset_k (const gsl_multiset * c);
size_t * gsl_multiset_data (const gsl_multiset * c);

int gsl_multiset_valid (gsl_multiset * c);
int gsl_multiset_next (gsl_multiset * c);
int gsl_multiset_prev (gsl_multiset * c);

INLINE_DECL size_t gsl_multiset_get (const gsl_multiset * c, const size_t i);

#ifdef HAVE_INLINE

INLINE_FUN
size_t
gsl_multiset_get (const gsl_multiset * c, const size_t i)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(i >= c->k)) /* size_t is unsigned, can't be negative */
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return c->data[i];
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_MULTISET_H__ */


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

  (c) 2017 - 2019 Scientific Computation Research Center,
      Rensselaer Polytechnic Institute. All rights reserved.

  This work is open source software, licensed under the terms of the
  BSD license as described in the LICENSE file in the top-level directory.

*******************************************************************************/
#ifndef MSI_PETSC_VERSION_H_
#define MSI_PETSC_VERSION_H_
#include <petscversion.h>
#include <petsc.h>
#include <utility>

template <typename ... Args>
auto PetscSetPCBackend(Args&&... args) -> decltype(
#if PETSC_VERSION_GT(3,9,5)
  PCFactorSetMatSolverType(std::forward<Args>(args)...)
#else
  PCFactorSetMatSolverPackage(std::forward<Args>(args)...)
#endif
  )
{
#if PETSC_VERSION_GT(3,9,5)
  return PCFactorSetMatSolverType(std::forward<Args>(args)...);
#else
  return PCFactorSetMatSolverPackage(std::forward<Args>(args)...);
#endif
}
#endif


/* blas/gsl_cblas.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 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.
 */

/* This is a copy of the CBLAS standard header.
 * We carry this around so we do not have to
 * break our model for flexible BLAS functionality.
 */

#ifndef __GSL_CBLAS_H__
#define __GSL_CBLAS_H__
#include <stddef.h>
#include <gsl/gsl_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

/*
 * Enumerated and derived types
 */
#define CBLAS_INDEX size_t  /* this may vary between platforms */

enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};
enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};
enum CBLAS_UPLO {CblasUpper=121, CblasLower=122};
enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};
enum CBLAS_SIDE {CblasLeft=141, CblasRight=142};

/*
 * ===========================================================================
 * Prototypes for level 1 BLAS functions (complex are recast as routines)
 * ===========================================================================
 */
GSL_EXPORT float  cblas_sdsdot(const int N, const float alpha, const float *X,
                               const int incX, const float *Y, const int incY);
GSL_EXPORT double cblas_dsdot(const int N, const float *X, const int incX, const float *Y,
                              const int incY);
GSL_EXPORT float  cblas_sdot(const int N, const float  *X, const int incX,
                             const float  *Y, const int incY);
GSL_EXPORT double cblas_ddot(const int N, const double *X, const int incX,
                             const double *Y, const int incY);

/*
 * Functions having prefixes Z and C only
 */
GSL_EXPORT void   cblas_cdotu_sub(const int N, const void *X, const int incX,
                                  const void *Y, const int incY, void *dotu);
GSL_EXPORT void   cblas_cdotc_sub(const int N, const void *X, const int incX,
                                  const void *Y, const int incY, void *dotc);

GSL_EXPORT void   cblas_zdotu_sub(const int N, const void *X, const int incX,
                                  const void *Y, const int incY, void *dotu);
GSL_EXPORT void   cblas_zdotc_sub(const int N, const void *X, const int incX,
                                  const void *Y, const int incY, void *dotc);

/*
 * Functions having prefixes S D SC DZ
 */
GSL_EXPORT float  cblas_snrm2(const int N, const float *X, const int incX);
GSL_EXPORT float  cblas_sasum(const int N, const float *X, const int incX);

GSL_EXPORT double cblas_dnrm2(const int N, const double *X, const int incX);
GSL_EXPORT double cblas_dasum(const int N, const double *X, const int incX);

GSL_EXPORT float  cblas_scnrm2(const int N, const void *X, const int incX);
GSL_EXPORT float  cblas_scasum(const int N, const void *X, const int incX);

GSL_EXPORT double cblas_dznrm2(const int N, const void *X, const int incX);
GSL_EXPORT double cblas_dzasum(const int N, const void *X, const int incX);

/*
 * Functions having standard 4 prefixes (S D C Z)
 */
GSL_EXPORT CBLAS_INDEX cblas_isamax(const int N, const float  *X, const int incX);
GSL_EXPORT CBLAS_INDEX cblas_idamax(const int N, const double *X, const int incX);
GSL_EXPORT CBLAS_INDEX cblas_icamax(const int N, const void   *X, const int incX);
GSL_EXPORT CBLAS_INDEX cblas_izamax(const int N, const void   *X, const int incX);

/*
 * ===========================================================================
 * Prototypes for level 1 BLAS routines
 * ===========================================================================
 */

/*
 * Routines with standard 4 prefixes (s, d, c, z)
 */
GSL_EXPORT void cblas_sswap(const int N, float *X, const int incX,
                            float *Y, const int incY);
GSL_EXPORT void cblas_scopy(const int N, const float *X, const int incX,
                            float *Y, const int incY);
GSL_EXPORT void cblas_saxpy(const int N, const float alpha, const float *X,
                            const int incX, float *Y, const int incY);

GSL_EXPORT void cblas_dswap(const int N, double *X, const int incX,
                            double *Y, const int incY);
GSL_EXPORT void cblas_dcopy(const int N, const double *X, const int incX,
                            double *Y, const int incY);
GSL_EXPORT void cblas_daxpy(const int N, const double alpha, const double *X,
                            const int incX, double *Y, const int incY);

GSL_EXPORT void cblas_cswap(const int N, void *X, const int incX,
                            void *Y, const int incY);
GSL_EXPORT void cblas_ccopy(const int N, const void *X, const int incX,
                            void *Y, const int incY);
GSL_EXPORT void cblas_caxpy(const int N, const void *alpha, const void *X,
                            const int incX, void *Y, const int incY);

GSL_EXPORT void cblas_zswap(const int N, void *X, const int incX,
                            void *Y, const int incY);
GSL_EXPORT void cblas_zcopy(const int N, const void *X, const int incX,
                            void *Y, const int incY);
GSL_EXPORT void cblas_zaxpy(const int N, const void *alpha, const void *X,
                            const int incX, void *Y, const int incY);

/*
 * Routines with S and D prefix only
 */
GSL_EXPORT void cblas_srotg(float *a, float *b, float *c, float *s);
GSL_EXPORT void cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P);
GSL_EXPORT void cblas_srot(const int N, float *X, const int incX,
                           float *Y, const int incY, const float c, const float s);
GSL_EXPORT void cblas_srotm(const int N, float *X, const int incX,
                           float *Y, const int incY, const float *P);

GSL_EXPORT void cblas_drotg(double *a, double *b, double *c, double *s);
GSL_EXPORT void cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P);
GSL_EXPORT void cblas_drot(const int N, double *X, const int incX,
                           double *Y, const int incY, const double c, const double  s);
GSL_EXPORT void cblas_drotm(const int N, double *X, const int incX,
                            double *Y, const int incY, const double *P);

/*
 * Routines with S D C Z CS and ZD prefixes
 */
GSL_EXPORT void cblas_sscal(const int N, const float alpha, float *X, const int incX);
GSL_EXPORT void cblas_dscal(const int N, const double alpha, double *X, const int incX);
GSL_EXPORT void cblas_cscal(const int N, const void *alpha, void *X, const int incX);
GSL_EXPORT void cblas_zscal(const int N, const void *alpha, void *X, const int incX);
GSL_EXPORT void cblas_csscal(const int N, const float alpha, void *X, const int incX);
GSL_EXPORT void cblas_zdscal(const int N, const double alpha, void *X, const int incX);

/*
 * ===========================================================================
 * Prototypes for level 2 BLAS
 * ===========================================================================
 */

/*
 * Routines with standard 4 prefixes (S, D, C, Z)
 */
GSL_EXPORT void cblas_sgemv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const float alpha, const float *A, const int lda,
                            const float *X, const int incX, const float beta,
                            float *Y, const int incY);
GSL_EXPORT void cblas_sgbmv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const int KL, const int KU, const float alpha,
                            const float *A, const int lda, const float *X,
                            const int incX, const float beta, float *Y, const int incY);
GSL_EXPORT void cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const float *A, const int lda,
                            float *X, const int incX);
GSL_EXPORT void cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const float *A, const int lda,
                            float *X, const int incX);
GSL_EXPORT void cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const float *Ap, float *X, const int incX);
GSL_EXPORT void cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const float *A, const int lda, float *X,
                            const int incX);
GSL_EXPORT void cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const float *A, const int lda,
                            float *X, const int incX);
GSL_EXPORT void cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const float *Ap, float *X, const int incX);

GSL_EXPORT void cblas_dgemv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const double alpha, const double *A, const int lda,
                            const double *X, const int incX, const double beta,
                            double *Y, const int incY);
GSL_EXPORT void cblas_dgbmv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const int KL, const int KU, const double alpha,
                            const double *A, const int lda, const double *X,
                            const int incX, const double beta, double *Y, const int incY);
GSL_EXPORT void cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const double *A, const int lda,
                            double *X, const int incX);
GSL_EXPORT void cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const double *A, const int lda,
                            double *X, const int incX);
GSL_EXPORT void cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const double *Ap, double *X, const int incX);
GSL_EXPORT void cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const double *A, const int lda, double *X,
                            const int incX);
GSL_EXPORT void cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const double *A, const int lda,
                            double *X, const int incX);
GSL_EXPORT void cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const double *Ap, double *X, const int incX);

GSL_EXPORT void cblas_cgemv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *X, const int incX, const void *beta,
                            void *Y, const int incY);
GSL_EXPORT void cblas_cgbmv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const int KL, const int KU, const void *alpha,
                            const void *A, const int lda, const void *X,
                            const int incX, const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *Ap, void *X, const int incX);
GSL_EXPORT void cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *A, const int lda, void *X,
                            const int incX);
GSL_EXPORT void cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *Ap, void *X, const int incX);

GSL_EXPORT void cblas_zgemv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *X, const int incX, const void *beta,
                            void *Y, const int incY);
GSL_EXPORT void cblas_zgbmv(const enum CBLAS_ORDER order,
                            const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
                            const int KL, const int KU, const void *alpha,
                            const void *A, const int lda, const void *X,
                            const int incX, const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *Ap, void *X, const int incX);
GSL_EXPORT void cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *A, const int lda, void *X,
                            const int incX);
GSL_EXPORT void cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const int K, const void *A, const int lda,
                            void *X, const int incX);
GSL_EXPORT void cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
                            const int N, const void *Ap, void *X, const int incX);

/*
 * Routines with S and D prefixes only
 */
GSL_EXPORT void cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const float alpha, const float *A,
                            const int lda, const float *X, const int incX,
                            const float beta, float *Y, const int incY);
GSL_EXPORT void cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const int K, const float alpha, const float *A,
                            const int lda, const float *X, const int incX,
                            const float beta, float *Y, const int incY);
GSL_EXPORT void cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const float alpha, const float *Ap,
                            const float *X, const int incX,
                            const float beta, float *Y, const int incY);
GSL_EXPORT void cblas_sger(const enum CBLAS_ORDER order, const int M, const int N,
                           const float alpha, const float *X, const int incX,
                           const float *Y, const int incY, float *A, const int lda);
GSL_EXPORT void cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const float alpha, const float *X,
                           const int incX, float *A, const int lda);
GSL_EXPORT void cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const float alpha, const float *X,
                           const int incX, float *Ap);
GSL_EXPORT void cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const float alpha, const float *X,
                            const int incX, const float *Y, const int incY, float *A,
                            const int lda);
GSL_EXPORT void cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const float alpha, const float *X,
                            const int incX, const float *Y, const int incY, float *A);

GSL_EXPORT void cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const double alpha, const double *A,
                            const int lda, const double *X, const int incX,
                            const double beta, double *Y, const int incY);
GSL_EXPORT void cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const int K, const double alpha, const double *A,
                            const int lda, const double *X, const int incX,
                            const double beta, double *Y, const int incY);
GSL_EXPORT void cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const double alpha, const double *Ap,
                            const double *X, const int incX,
                            const double beta, double *Y, const int incY);
GSL_EXPORT void cblas_dger(const enum CBLAS_ORDER order, const int M, const int N,
                           const double alpha, const double *X, const int incX,
                           const double *Y, const int incY, double *A, const int lda);
GSL_EXPORT void cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const double alpha, const double *X,
                           const int incX, double *A, const int lda);
GSL_EXPORT void cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const double alpha, const double *X,
                           const int incX, double *Ap);
GSL_EXPORT void cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const double alpha, const double *X,
                            const int incX, const double *Y, const int incY, double *A,
                            const int lda);
GSL_EXPORT void cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const double alpha, const double *X,
                            const int incX, const double *Y, const int incY, double *A);

/*
 * Routines with C and Z prefixes only
 */
GSL_EXPORT void cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const void *alpha, const void *A,
                            const int lda, const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const int K, const void *alpha, const void *A,
                            const int lda, const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const void *alpha, const void *Ap,
                            const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const float alpha, const void *X, const int incX,
                           void *A, const int lda);
GSL_EXPORT void cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const float alpha, const void *X,
                           const int incX, void *A);
GSL_EXPORT void cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *Ap);

GSL_EXPORT void cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const void *alpha, const void *A,
                            const int lda, const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const int K, const void *alpha, const void *A,
                            const int lda, const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                            const int N, const void *alpha, const void *Ap,
                            const void *X, const int incX,
                            const void *beta, void *Y, const int incY);
GSL_EXPORT void cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const double alpha, const void *X, const int incX,
                           void *A, const int lda);
GSL_EXPORT void cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
                           const int N, const double alpha, const void *X,
                           const int incX, void *A);
GSL_EXPORT void cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *A, const int lda);
GSL_EXPORT void cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
                            const void *alpha, const void *X, const int incX,
                            const void *Y, const int incY, void *Ap);

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

/*
 * Routines with standard 4 prefixes (S, D, C, Z)
 */
GSL_EXPORT void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                            const int K, const float alpha, const float *A,
                            const int lda, const float *B, const int ldb,
                            const float beta, float *C, const int ldc);
GSL_EXPORT void cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const float alpha, const float *A, const int lda,
                            const float *B, const int ldb, const float beta,
                            float *C, const int ldc);
GSL_EXPORT void cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const float alpha, const float *A, const int lda,
                            const float beta, float *C, const int ldc);
GSL_EXPORT void cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const float alpha, const float *A, const int lda,
                             const float *B, const int ldb, const float beta,
                             float *C, const int ldc);
GSL_EXPORT void cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const float alpha, const float *A, const int lda,
                            float *B, const int ldb);
GSL_EXPORT void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const float alpha, const float *A, const int lda,
                            float *B, const int ldb);

GSL_EXPORT void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                            const int K, const double alpha, const double *A,
                            const int lda, const double *B, const int ldb,
                            const double beta, double *C, const int ldc);
GSL_EXPORT void cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const double alpha, const double *A, const int lda,
                            const double *B, const int ldb, const double beta,
                            double *C, const int ldc);
GSL_EXPORT void cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const double alpha, const double *A, const int lda,
                            const double beta, double *C, const int ldc);
GSL_EXPORT void cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const double alpha, const double *A, const int lda,
                             const double *B, const int ldb, const double beta,
                             double *C, const int ldc);
GSL_EXPORT void cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const double alpha, const double *A, const int lda,
                            double *B, const int ldb);
GSL_EXPORT void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const double alpha, const double *A, const int lda,
                            double *B, const int ldb);

GSL_EXPORT void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                            const int K, const void *alpha, const void *A,
                            const int lda, const void *B, const int ldb,
                            const void *beta, void *C, const int ldc);
GSL_EXPORT void cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *B, const int ldb, const void *beta,
                            void *C, const int ldc);
GSL_EXPORT void cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const void *alpha, const void *A, const int lda,
                            const void *beta, void *C, const int ldc);
GSL_EXPORT void cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const void *alpha, const void *A, const int lda,
                             const void *B, const int ldb, const void *beta,
                             void *C, const int ldc);
GSL_EXPORT void cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            void *B, const int ldb);
GSL_EXPORT void cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            void *B, const int ldb);

GSL_EXPORT void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
                            const int K, const void *alpha, const void *A,
                            const int lda, const void *B, const int ldb,
                            const void *beta, void *C, const int ldc);
GSL_EXPORT void cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *B, const int ldb, const void *beta,
                            void *C, const int ldc);
GSL_EXPORT void cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const void *alpha, const void *A, const int lda,
                            const void *beta, void *C, const int ldc);
GSL_EXPORT void cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const void *alpha, const void *A, const int lda,
                             const void *B, const int ldb, const void *beta,
                             void *C, const int ldc);
GSL_EXPORT void cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            void *B, const int ldb);
GSL_EXPORT void cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
                            const enum CBLAS_DIAG Diag, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            void *B, const int ldb);

/*
 * Routines with prefixes C and Z only
 */
GSL_EXPORT void cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *B, const int ldb, const void *beta,
                            void *C, const int ldc);
GSL_EXPORT void cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const float alpha, const void *A, const int lda,
                            const float beta, void *C, const int ldc);
GSL_EXPORT void cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const void *alpha, const void *A, const int lda,
                             const void *B, const int ldb, const float beta,
                             void *C, const int ldc);

GSL_EXPORT void cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
                            const enum CBLAS_UPLO Uplo, const int M, const int N,
                            const void *alpha, const void *A, const int lda,
                            const void *B, const int ldb, const void *beta,
                            void *C, const int ldc);
GSL_EXPORT void cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                            const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                            const double alpha, const void *A, const int lda,
                            const double beta, void *C, const int ldc);
GSL_EXPORT void cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
                             const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
                             const void *alpha, const void *A, const int lda,
                             const void *B, const int ldb, const double beta,
                             void *C, const int ldc);

GSL_EXPORT void cblas_xerbla(int p, const char *rout, const char *form, ...);

__END_DECLS

#endif /* __GSL_CBLAS_H__ */


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

#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_multiset.h>

gsl_multiset *
gsl_multiset_alloc (const size_t n, const size_t k)
{
  gsl_multiset * c;

  if (n == 0)
    {
      GSL_ERROR_VAL ("multiset parameter n must be positive integer",
                        GSL_EDOM, 0);
    }
  if (k > n)
    {
      GSL_ERROR_VAL ("multiset length k must be an integer less than or equal to n",
                        GSL_EDOM, 0);
    }
  c = (gsl_multiset *) malloc (sizeof (gsl_multiset));

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

  if (k > 0)
    {
      c->data = (size_t *) malloc (k * sizeof (size_t));

      if (c->data == 0)
        {
          free (c);             /* exception in constructor, avoid memory leak */

          GSL_ERROR_VAL ("failed to allocate space for multiset data",
                         GSL_ENOMEM, 0);
        }
    }
  else
    {
      c->data = 0;
    }

  c->n = n;
  c->k = k;

  return c;
}

gsl_multiset *
gsl_multiset_calloc (const size_t n, const size_t k)
{
  size_t i;

  gsl_multiset * c =  gsl_multiset_alloc (n, k);

  if (c == 0)
    return 0;

  /* initialize multiset to repeated first element */

  for (i = 0; i < k; i++)
    {
      c->data[i] = 0;
    }

  return c;
}

void
gsl_multiset_init_first (gsl_multiset * c)
{
  const size_t k = c->k ;
  size_t i;

  /* initialize multiset to repeated first element */

  for (i = 0; i < k; i++)
    {
      c->data[i] = 0;
    }
}

void
gsl_multiset_init_last (gsl_multiset * c)
{
  const size_t k = c->k ;
  size_t i;
  size_t n = c->n;

  /* initialize multiset to repeated last element */

  for (i = 0; i < k; i++)
    {
      c->data[i] = n - 1;
    }
}

void
gsl_multiset_free (gsl_multiset * c)
{
  RETURN_IF_NULL (c);
  if (c->k > 0) free (c->data);
  free (c);
}


/**
 * @file xdegnome.c
 * @author Daniel R. Tabin
 * @brief Unit tests for Degnome
 */

#include "degnome.h"
#include <stdio.h>
#include <string.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <time.h>
#include <unistd.h>
#include <limits.h>

unsigned long rngseed=0;

int main(int argc, char **argv) {
	int verbose = 0;
	int seeded =0;

	if (argc == 2) {
		if (strncmp(argv[1], "-v", 2) != 0) {
			fprintf(stderr, "usage: xdegnome [-v] [-s] [0000000000]\n");
			exit(EXIT_FAILURE);
		}
		verbose = 1;
	}
	else if (argc == 3) {
		if (strncmp(argv[1], "-s", 2) != 0) {
			fprintf(stderr, "usage: xdegnome [-v] [-s] [0000000000]\n");
			exit(EXIT_FAILURE);
		}
		rngseed = (unsigned long) atoi(argv[2]);
	}
	else if (argc == 4) {
		if (strncmp(argv[1], "-v", 2) != 0) {
			fprintf(stderr, "usage: xdegnome [-v] [-s] [0000000000]\n");
			exit(EXIT_FAILURE);
		}
		else if (strncmp(argv[2], "-s", 2) != 0) {
			fprintf(stderr, "usage: xdegnome [-v] [-s]  [0000000000]\n");
			exit(EXIT_FAILURE);
		}
		verbose = 1;
		seeded = 1;
		rngseed = (unsigned long) atoi(argv[3]);

	}
	else if (argc != 1) {
		fprintf(stderr, "usage: xdegnome [-v] [-s] [seed]\n");
		exit(EXIT_FAILURE);
	}

	chrom_size = 15;

	if (verbose) {
		printf("Chromosome is length %u\n", chrom_size);
	}

	Degnome* bom_mom = Degnome_new(); // good parent
	Degnome* bad_dad = Degnome_new();	// bad parent
	Degnome* tst_bby = Degnome_new(); // their child

	// ============ change this to seed rn
	if (seeded == 0) {
		time_t currtime = time(NULL);                  // time
		unsigned long pid = (unsigned long) getpid();  // process id
		rngseed = currtime ^ pid;					   // random seed
	}
	gsl_rng* rng = gsl_rng_alloc(gsl_rng_taus);    // rand generator

	gsl_rng_set(rng, rngseed);
	rngseed = (rngseed == ULONG_MAX ? 0 : rngseed + 1);

	// ============ change this to seed rn

	for (int i = 0; i < chrom_size; i++) {
		bom_mom->dna_array[i] = 2*i;
		bad_dad->dna_array[i] = 1*i;

		bom_mom->hat_size += bom_mom->dna_array[i];
		bad_dad->hat_size += bad_dad->dna_array[i];
	}

	if (verbose) {
		printf("pre-mating values:\n");
		for (int i = 0; i < chrom_size; i++) {
			printf("Mom: %lf\t Dad: %f\n", bom_mom->dna_array[i], bad_dad->dna_array[i]);
		}
		printf("Mom hat_size: %lf\t Dad hat_size: %f\n", bom_mom->hat_size, bad_dad->hat_size);
	}

	Degnome_mate(tst_bby, bom_mom, bad_dad, rng, 0, 0,2);

	if (verbose) {
		printf("post-mating values:\n");
		for (int i = 0; i < chrom_size; i++) {
			printf("Mom: %lf\t Dad: %f\t Kid: %f\n", bom_mom->dna_array[i], bad_dad->dna_array[i], tst_bby->dna_array[i]);
		}
		printf("Mom hat_size: %lf\t Dad hat_size: %f\t Kid hat_size: %f\n", bom_mom->hat_size, bad_dad->hat_size, tst_bby->hat_size);
	}

	Degnome_free(bom_mom);
	Degnome_free(bad_dad);
	Degnome_free(tst_bby);

	gsl_rng_free(rng);

	printf("All tests for xdegnome completed\n");
}


///  @file rainbow-gen-userpk.c
///  @brief A command-line tool for generating the user public keys.

#include <rainbow_keypair.h>
#include <stdlib.h>
#include <stdio.h>
#include <api.h>
#include <utils.h>
#include <string.h>
#include <blas.h>

int main(int argc, char **argv) {

    printf("%s\n", CRYPTO_ALGNAME);

    printf("msk size: %lu\n", CRYPTO_MASTER_SECRET_KEY_BYTES);
    printf("mpk size: %lu\n", CRYPTO_MASTER_PUBLIC_KEY_BYTES);
    printf("hash size: %d\n", _HASH_LEN);
    printf("signature size: %d\n\n", CRYPTO_BYTES);

    if (4 != argc) {
        printf("Usage:\n\n\trainbow-gen-userpk mpk_file_name identity upk_file_name\n\n");
        return -1;
    }

    //malloc upk

    uint8_t *_mpk = malloc(CRYPTO_MASTER_PUBLIC_KEY_BYTES);
    FILE *fp;
    unsigned r;

    fp = fopen( argv[1] , "r");
    if( NULL == fp ) {
        printf("fail to open master key file.\n");
        return -1;
    }
    r = byte_fget(fp, _mpk, CRYPTO_MASTER_PUBLIC_KEY_BYTES);
    fclose(fp);
    if (CRYPTO_MASTER_PUBLIC_KEY_BYTES != r) {
        printf("fail to load key file.\n");
        return -1;
    }

    unsigned char * _identity = malloc((_ID+1)/2);
    r = 0;

    generate_identity_hash(_identity, (unsigned char *) argv[2], strlen(argv[2]));
    if( NULL == _identity ) {
        printf("fail to create identity hash.\n");
        return -1;
    }
    printf("identity hash: ");
    for(unsigned i = 0; i<_ID; i++){
        printf("%hhu ",gf16v_get_ele(_identity,i));
    }
    printf("\n\n");

    uint8_t *_upk = malloc(sizeof(upk_t));

    //calculate usk with mpk and ID

    int re = calculate_upk((upk_t *) _upk, (mpk_t *) _mpk, _identity);
    if (0 != re) {
        printf("%s generate user-public-key fails.\n", CRYPTO_ALGNAME);
        return -1;
    }

    //write upk to disk
    fp = fopen(argv[3], "w+");
    if (NULL == fp) {
        printf("fail to open user public key file.\n");
        return -1;
    }
    byte_fdump(fp, CRYPTO_ALGNAME " user-public-key", _upk, sizeof(upk_t)); //pk speichern und beschriften
    fclose(fp);

    //free upk and rest

    free(_mpk);
    free(_identity);
    free(_upk);

    return 0;
}


/*!
 *  Copyright (c) 2014 by Contributors
 * \file base.h
 * \brief definitions of base types, operators, macros functions
 *
 * \author Bing Xu, Tianqi Chen
 */
#ifndef MSHADOW_BASE_H_
#define MSHADOW_BASE_H_
#ifdef _MSC_VER
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
#endif
#define NOMINMAX
#endif
#include <cmath>
#include <cstdio>
#include <cfloat>
#include <climits>
#include <algorithm>
#include <functional>
#include <sstream>
#include <string>

#ifdef _MSC_VER
//! \cond Doxygen_Suppress
typedef signed char int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
//! \endcond
#else
#include <inttypes.h>
#endif
// macro defintiions
/*!
 * \brief if this macro is define to be 1,
 * mshadow should compile without any of other libs
 */
#ifndef MSHADOW_STAND_ALONE
#define MSHADOW_STAND_ALONE 0
#endif
/*! \brief whether do padding during allocation */
#ifndef MSHADOW_ALLOC_PAD
#define MSHADOW_ALLOC_PAD true
#endif
/*!
 * \brief
 *  x dimension of data must be bigger pad_size * ratio to be alloced padded memory,
 *  otherwise use tide allocation
 *  for example, if pad_ratio=2, GPU memory alignement size is 32,
 *  then we will only allocate padded memory if x dimension > 64
 *  set it to 0 then we will always allocate padded memory
 */
#ifndef MSHADOW_MIN_PAD_RATIO
  #define MSHADOW_MIN_PAD_RATIO 2
#endif

#if MSHADOW_STAND_ALONE
  #define MSHADOW_USE_CBLAS 0
  #define MSHADOW_USE_MKL   0
  #define MSHADOW_USE_CUDA  0
#endif

/*!
 * \brief force user to use GPU stream during computation
 *  error will be shot when default stream NULL is used
 */
#ifndef MSHADOW_FORCE_STREAM
#define MSHADOW_FORCE_STREAM 1
#endif

/*! \brief use CBLAS for CBLAS */
#ifndef MSHADOW_USE_CBLAS
  #define MSHADOW_USE_CBLAS 0
#endif
/*! \brief use MKL for BLAS */
#ifndef MSHADOW_USE_MKL
  #define MSHADOW_USE_MKL   1
#endif

/*!
 * \brief use CUDA support, must ensure that the cuda include path is correct,
 * or directly compile using nvcc
 */
#ifndef MSHADOW_USE_CUDA
  #define MSHADOW_USE_CUDA   1
#endif

/*!
 * \brief use CUDNN support, must ensure that the cudnn include path is correct
 */
#ifndef MSHADOW_USE_CUDNN
  #define MSHADOW_USE_CUDNN 0
#endif

/*!
 * \brief seems CUDAARCH is deprecated in future NVCC
 * set this to 1 if you want to use CUDA version smaller than 2.0
 */
#ifndef MSHADOW_OLD_CUDA
#define MSHADOW_OLD_CUDA 0
#endif

/*!
 * \brief macro to decide existence of c++11 compiler
 */
#ifndef MSHADOW_IN_CXX11
#define MSHADOW_IN_CXX11 (defined(__GXX_EXPERIMENTAL_CXX0X__) ||\
                          __cplusplus >= 201103L || defined(_MSC_VER))
#endif

/*! \brief whether use SSE */
#ifndef MSHADOW_USE_SSE
  #define MSHADOW_USE_SSE 1
#endif
/*! \brief whether use NVML to get dynamic info */
#ifndef MSHADOW_USE_NVML
  #define MSHADOW_USE_NVML 0
#endif
// SSE is conflict with cudacc
#ifdef __CUDACC__
  #undef MSHADOW_USE_SSE
  #define MSHADOW_USE_SSE 0
#endif

#if MSHADOW_USE_CBLAS
extern "C" {
    #include <cblas.h>
}
#elif MSHADOW_USE_MKL
  #include <mkl_blas.h>
  #include <mkl_cblas.h>
  #include <mkl_vsl.h>
  #include <mkl_vsl_functions.h>
#endif

#if MSHADOW_USE_CUDA
  #include <cuda.h>
  #include <cublas_v2.h>
  #include <curand.h>
#endif

#if MSHADOW_USE_CUDNN == 1
  #include <cudnn.h>
#endif

#if MSHADOW_USE_NVML
  #include <nvml.h>
#endif

// --------------------------------
// MSHADOW_XINLINE is used for inlining template code for both CUDA and CPU code
#ifdef MSHADOW_XINLINE
  #error "MSHADOW_XINLINE must not be defined"
#endif
#ifdef _MSC_VER
#define MSHADOW_FORCE_INLINE __forceinline
#pragma warning(disable : 4068)
#else
#define MSHADOW_FORCE_INLINE inline __attribute__((always_inline))
#endif
#ifdef __CUDACC__
  #define MSHADOW_XINLINE MSHADOW_FORCE_INLINE __device__ __host__
#else
  #define MSHADOW_XINLINE MSHADOW_FORCE_INLINE
#endif
/*! \brief cpu force inline */
#define MSHADOW_CINLINE MSHADOW_FORCE_INLINE

#if defined(__GXX_EXPERIMENTAL_CXX0X) ||\
    defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
  #define MSHADOW_CONSTEXPR constexpr
#else
  #define MSHADOW_CONSTEXPR const
#endif

/*!
 * \brief default data type for tensor string
 *  in code release, change it to default_real_t
 *  during development, change it to empty string so that missing
 *  template arguments can be detected
 */
#ifndef MSHADOW_DEFAULT_DTYPE
#define MSHADOW_DEFAULT_DTYPE = default_real_t
#endif

/*!
 * \brief DMLC marco for logging
 */
#ifndef MSHADOW_USE_GLOG
#define MSHADOW_USE_GLOG DMLC_USE_GLOG
#endif  // MSHADOW_USE_GLOG

#if DMLC_USE_CXX11
#define MSHADOW_THROW_EXCEPTION noexcept(false)
#define MSHADOW_NO_EXCEPTION  noexcept(true)
#else
#define MSHADOW_THROW_EXCEPTION
#define MSHADOW_NO_EXCEPTION
#endif

/*!
 * \brief Protected cuda call in mshadow
 * \param func Expression to call.
 * It checks for CUDA errors after invocation of the expression.
 */
#define MSHADOW_CUDA_CALL(func)                                    \
  {                                                                \
    cudaError_t e = (func);                                        \
    if (e == cudaErrorCudartUnloading) {                           \
      throw dmlc::Error(cudaGetErrorString(e));                    \
    }                                                              \
    CHECK(e == cudaSuccess)                                        \
        << "CUDA: " << cudaGetErrorString(e);                      \
  }

/*!
 * \brief Run function and catch error, log unknown error.
 * \param func Expression to call.
 */
#define MSHADOW_CATCH_ERROR(func)                                     \
  {                                                                   \
    try {                                                             \
      (func);                                                         \
    } catch (const dmlc::Error &e) {                                    \
      std::string what = e.what();                                      \
      if (what.find("driver shutting down") == std::string::npos) {     \
        LOG(ERROR) << "Ignore CUDA Error " << what;                     \
      }                                                                 \
    }                                                                   \
  }

#include "./half.h"
#include "./half2.h"
#include "./logging.h"
/*! \brief namespace for mshadow */
namespace mshadow {
/*! \brief buffer size for each random number generator */
const unsigned kRandBufferSize = 1000000;
/*! \brief pi  */
const float kPi = 3.1415926f;
/*! \brief type that will be used for index */
typedef unsigned index_t;

#ifdef _WIN32
  /*! \brief openmp index for windows */
  typedef int64_t openmp_index_t;
#else
  /*! \brief openmp index for linux */
  typedef index_t openmp_index_t;
#endif

/*! \brief float point type that will be used in default by mshadow */
typedef float default_real_t;

/*! \brief data type flag */
enum TypeFlag {
  kFloat32 = 0,
  kFloat64 = 1,
  kFloat16 = 2,
  kUint8 = 3,
  kInt32 = 4,
  kInt8  = 5
};

template<typename DType>
struct DataType;

template<>
struct DataType<float> {
  static const int kFlag = kFloat32;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_32F;
#endif
#if MSHADOW_USE_CUDNN
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_FLOAT;
  typedef float ScaleType;
#endif
#endif
};
template<>
struct DataType<double> {
  static const int kFlag = kFloat64;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_64F;
#endif
#if MSHADOW_USE_CUDNN
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_DOUBLE;
  typedef double ScaleType;
#endif
#endif
};
template<>
struct DataType<half::half_t> {
  static const int kFlag = kFloat16;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_16F;
#endif
#if MSHADOW_USE_CUDNN
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_HALF;
  typedef float ScaleType;
#endif
#endif
};
template<>
struct DataType<half::half2_t> {
  static const int kFlag = kFloat16;
  static const int kLanes = 2;
};
template<>
struct DataType<uint8_t> {
  static const int kFlag = kUint8;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_8U;
#endif
#if (MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 6)
  // no uint8 in cudnn for now
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_INT8;
  typedef uint8_t ScaleType;
#endif
#endif
};
template<>
struct DataType<int8_t> {
  static const int kFlag = kInt8;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_8I;
#endif
#if (MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 6)
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_INT8;
  typedef int8_t ScaleType;
#endif
#endif
};
template<>
struct DataType<int32_t> {
  static const int kFlag = kInt32;
  static const int kLanes = 1;
#if MSHADOW_USE_CUDA
#if (CUDA_VERSION >= 8000)
  static const cudaDataType_t kCudaFlag = CUDA_R_32I;
#endif
#if (MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 6)
  static const cudnnDataType_t kCudnnFlag = CUDNN_DATA_INT32;
  typedef int32_t ScaleType;
#endif
#endif
};

/*! \brief type enum value for default real type */
const int default_type_flag = DataType<default_real_t>::kFlag;

/*! layout flag */
enum LayoutFlag {
  kNCHW = 0,
  kNHWC,
  kCHWN,

  kNCW = 1 << 3,
  kNWC,
  kCWN,

  kNCDHW = 1 << 5,
  kNDHWC,
  kCDHWN
};

template<int layout>
struct LayoutType;

template<>
struct LayoutType<kNCHW> {
  static const index_t kNdim = 4;
#if (MSHADOW_USE_CUDA && MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 4)
  static const cudnnTensorFormat_t kCudnnFlag = CUDNN_TENSOR_NCHW;
#else
  static const int kCudnnFlag = -1;
#endif
};

template<>
struct LayoutType<kNHWC> {
  static const index_t kNdim = 4;
#if (MSHADOW_USE_CUDA && MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 4)
  static const cudnnTensorFormat_t kCudnnFlag = CUDNN_TENSOR_NHWC;
#else
  static const int kCudnnFlag = -1;
#endif
};

/*! \brief default layout for 4d tensor */
const int default_layout = kNCHW;

template<>
struct LayoutType<kNCDHW> {
  static const index_t kNdim = 5;
#if (MSHADOW_USE_CUDA && MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 4)
  static const cudnnTensorFormat_t kCudnnFlag = CUDNN_TENSOR_NCHW;
#else
  static const int kCudnnFlag = -1;
#endif
};

template<>
struct LayoutType<kNDHWC> {
  static const index_t kNdim = 5;
#if (MSHADOW_USE_CUDA && MSHADOW_USE_CUDNN == 1 && CUDNN_MAJOR >= 4)
  static const cudnnTensorFormat_t kCudnnFlag = CUDNN_TENSOR_NHWC;
#else
  static const int kCudnnFlag = -1;
#endif
};

/*! \brief default layout for 5d tensor */
const int default_layout_5d = kNCDHW;

/*! \brief namespace for operators */
namespace op {
// binary operator
/*! \brief mul operator */
struct mul{
  /*! \brief map a, b to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a, DType b) {
    return a * b;
  }
};
/*! \brief plus operator */
struct plus {
  /*! \brief map a, b to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a, DType b) {
    return a + b;
  }
};
/*! \brief minus operator */
struct minus {
  /*! \brief map a, b to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a, DType b) {
    return a - b;
  }
};
/*! \brief divide operator */
struct div {
  /*! \brief map a, b to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a, DType b) {
    return a / b;
  }
};
/*! \brief get rhs */
struct right {
  /*! \brief map a, b to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a, DType b) {
    return b;
  }
};
// unary operator/ function: example
// these operators can be defined by user,
// in the same style as binary and unary operator
// to use, simply write F<op::identity>( src )
/*! \brief identity function that maps a real number to it self */
struct identity{
  /*! \brief map a to result using defined operation */
  template<typename DType>
  MSHADOW_XINLINE static DType Map(DType a) {
    return a;
  }
};
}  // namespace op
/*! \brief namespace for savers */
namespace sv {
/*! \brief save to saver: = */
struct saveto {
  /*! \brief save b to a using save method */
  template<typename DType>
  MSHADOW_XINLINE static void Save(DType &a, DType b) { // NOLINT(*)
    a = b;
  }
  /*! \brief helper constant to use BLAS, alpha */
  inline static default_real_t AlphaBLAS(void) { return 1.0f; }
  /*! \brief helper constant to use BLAS, beta */
  inline static default_real_t BetaBLAS(void) { return 0.0f; }
  /*! \brief corresponding binary operator type */
  typedef op::right OPType;
};
/*! \brief save to saver: += */
struct plusto {
  /*! \brief save b to a using save method */
  template<typename DType>
  MSHADOW_XINLINE static void Save(DType &a, DType b) { // NOLINT(*)
    a += b;
  }
  /*! \brief helper constant to use BLAS, alpha */
  inline static default_real_t AlphaBLAS(void) { return 1.0f; }
  /*! \brief helper constant to use BLAS, beta */
  inline static default_real_t BetaBLAS(void) { return 1.0f; }
  /*! \brief corresponding binary operator type */
  typedef op::plus OPType;
};
/*! \brief minus to saver: -= */
struct minusto {
  /*! \brief save b to a using save method */
  template<typename DType>
  MSHADOW_XINLINE static void Save(DType &a, DType b) { // NOLINT(*)
    a -= b;
  }
  /*! \brief helper constant to use BLAS, alpha */
  inline static default_real_t AlphaBLAS(void) { return -1.0f; }
  /*! \brief helper constant to use BLAS, beta */
  inline static default_real_t BetaBLAS(void) { return 1.0f; }
  /*! \brief corresponding binary operator type */
  typedef op::minus OPType;
};
/*! \brief multiply to saver: *= */
struct multo {
  /*! \brief save b to a using save method */
  template<typename DType>
  MSHADOW_XINLINE static void Save(DType &a, DType b) { // NOLINT(*)
    a *= b;
  }
  /*! \brief corresponding binary operator type */
  typedef op::mul OPType;
};
/*! \brief divide to saver: /= */
struct divto {
  /*! \brief save b to a using save method */
  template<typename DType>
  MSHADOW_XINLINE static void Save(DType& a, DType b) { // NOLINT(*)
    a /= b;
  }
  /*! \brief corresponding binary operator type */
  typedef op::div OPType;
};
}  // namespace sv
/*! \brief namespace for potential reducer operations */
namespace red {
namespace limits {
/*!
 * \brief minimum value of certain types
 * \tparam DType data type
 */
template<typename DType>
MSHADOW_XINLINE DType MinValue(void);
/*! \brief minimum value of float */
template<>
MSHADOW_XINLINE float MinValue<float>(void) {
  return -FLT_MAX;
}
/*! \brief minimum value of double */
template<>
MSHADOW_XINLINE double MinValue<double>(void) {
  return -DBL_MAX;
}
/*! \brief minimum value of half */
template<>
MSHADOW_XINLINE half::half_t MinValue<half::half_t>(void) {
  return MSHADOW_HALF_MIN;
}
/*! \brief minimum value of uint8_t */
template<>
MSHADOW_XINLINE uint8_t MinValue<uint8_t>(void) {
  return 0;
}
/*! \brief minimum value of int8_t */
template<>
MSHADOW_XINLINE int8_t MinValue<int8_t>(void) {
  return SCHAR_MIN;
}
/*! \brief minimum value of int32_t */
template<>
MSHADOW_XINLINE int MinValue<int32_t>(void) {
  return INT_MIN;
}

/*!
 * \brief maximum value of certain types
 * \tparam DType data type
 */
template<typename DType>
MSHADOW_XINLINE DType MaxValue(void);
/*! \brief maximum value of float */
template<>
MSHADOW_XINLINE float MaxValue<float>(void) {
  return FLT_MAX;
}
/*! \brief maximum value of double */
template<>
MSHADOW_XINLINE double MaxValue<double>(void) {
  return DBL_MAX;
}
/*! \brief maximum value of uint8_t */
template<>
MSHADOW_XINLINE uint8_t MaxValue<uint8_t>(void) {
  return UCHAR_MAX;
}
/*! \brief maximum value of int8_t */
template<>
MSHADOW_XINLINE int8_t MaxValue<int8_t>(void) {
  return SCHAR_MAX;
}
/*! \brief maximum value of int32_t */
template<>
MSHADOW_XINLINE int MaxValue<int32_t>(void) {
  return INT_MAX;
}
}  // namespace limits

/*! \brief sum reducer */
struct sum {
  /*! \brief do reduction into dst */
  template<typename DType>
  MSHADOW_XINLINE static void Reduce(volatile DType& dst,  volatile DType src) { // NOLINT(*)
    dst += src;
  }
  /*!
   *\brief calculate gradient of redres with respect to redsrc,
   * redres: reduced result, redsrc: one of reduction element
   */
  template<typename DType>
  MSHADOW_XINLINE static DType PartialGrad(DType redres, DType redsrc) {
    return 1;
  }
  /*!
   *\brief set the initial value during reduction
   */
  template<typename DType>
  MSHADOW_XINLINE static void SetInitValue(DType &initv) { // NOLINT(*)
    initv = 0;
  }
};
/*! \brief maximum reducer */
struct maximum {
  /*! \brief do reduction into dst */
  template<typename DType>
  MSHADOW_XINLINE static void Reduce(volatile DType& dst,  volatile DType src) { // NOLINT(*)
    using namespace std;
#ifdef __CUDACC__
    dst = ::max(dst, src);
#else
    dst = max(dst, src);
#endif  // __CUDACC__
  }
  /*!
   * \brief calculate gradient of redres with respect to redsrc,
   * redres: reduced result, redsrc: one of reduction element
   */
  template<typename DType>
  MSHADOW_XINLINE static DType PartialGrad(DType redres, DType redsrc) {
    return redres == redsrc ? 1: 0;
  }
  /*!
   *\brief set the initial value during reduction
   */
  template<typename DType>
  MSHADOW_XINLINE static void SetInitValue(DType &initv) { // NOLINT(*)
    initv = limits::MinValue<DType>();
  }
};
/*! \brief minimum reducer */
struct minimum {
  /*! \brief do reduction into dst */
  template<typename DType>
  MSHADOW_XINLINE static void Reduce(volatile DType& dst,  volatile DType src) { // NOLINT(*)
    using namespace std;
#ifdef __CUDACC__
    dst = ::min(dst, src);
#else
    dst = min(dst, src);
#endif  // __CUDACC__
  }
  /*!
   * \brief calculate gradient of redres with respect to redsrc,
   * redres: reduced result, redsrc: one of reduction element
   */
  template<typename DType>
  MSHADOW_XINLINE static DType PartialGrad(DType redres, DType redsrc) {
    return redres == redsrc ? 1: 0;
  }
  /*!
   *\brief set the initial value during reduction
   */
  template<typename DType>
  MSHADOW_XINLINE static void SetInitValue(DType &initv) { // NOLINT(*)
    initv = -limits::MinValue<DType>();
  }
};
}  // namespace red

#define MSHADOW_TYPE_SWITCH(type, DType, ...)       \
  switch (type) {                                   \
  case mshadow::kFloat32:                           \
    {                                               \
      typedef float DType;                          \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat64:                           \
    {                                               \
      typedef double DType;                         \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat16:                           \
    {                                               \
      typedef mshadow::half::half_t DType;          \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kUint8:                             \
    {                                               \
      typedef uint8_t DType;                        \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kInt8:                              \
    {                                               \
      typedef int8_t DType;                         \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kInt32:                             \
    {                                               \
      typedef int32_t DType;                        \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  default:                                          \
    LOG(FATAL) << "Unknown type enum " << type;     \
  }

#define MSHADOW_TYPE_SWITCH_WITH_HALF2(type, DType, ...)  \
  switch (type) {                                         \
  case mshadow::kFloat32:                                 \
    {                                                     \
      typedef float DType;                                \
      {__VA_ARGS__}                                       \
    }                                                     \
    break;                                                \
  case mshadow::kFloat64:                                 \
    {                                                     \
      typedef double DType;                               \
      {__VA_ARGS__}                                       \
    }                                                     \
    break;                                                \
  case mshadow::kFloat16:                                 \
    {                                                     \
      typedef mshadow::half::half2_t DType;               \
      {__VA_ARGS__}                                       \
    }                                                     \
    break;                                                \
  case mshadow::kUint8:                                   \
    {                                                     \
      typedef uint8_t DType;                              \
      {__VA_ARGS__}                                       \
    }                                                     \
    break;                                                \
  case mshadow::kInt32:                                   \
    {                                                     \
      typedef int32_t DType;                              \
      {__VA_ARGS__}                                       \
    }                                                     \
    break;                                                \
  default:                                                \
    LOG(FATAL) << "Unknown type enum " << type;           \
  }

#define MSHADOW_REAL_TYPE_SWITCH(type, DType, ...)  \
  switch (type) {                                   \
  case mshadow::kFloat32:                           \
    {                                               \
      typedef float DType;                          \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat64:                           \
    {                                               \
      typedef double DType;                         \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat16:                           \
    {                                               \
      typedef mshadow::half::half_t DType;          \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kUint8:                             \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types not uint8"; \
    break;                                          \
  case mshadow::kInt8:                              \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types not int8";  \
    break;                                          \
  case mshadow::kInt32:                             \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types, not int32";\
    break;                                          \
  default:                                          \
    LOG(FATAL) << "Unknown type enum " << type;     \
  }

#define MSHADOW_REAL_TYPE_SWITCH_EX(type$, DType$, DLargeType$, ...)  \
  switch (type$) {                                  \
  case mshadow::kFloat32:                           \
    {                                               \
      typedef float DType$;                         \
      typedef float DLargeType$;                    \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat64:                           \
    {                                               \
      typedef double DType$;                        \
      typedef double DLargeType$;                   \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kFloat16:                           \
    {                                               \
      typedef mshadow::half::half_t DType$;         \
      typedef float DLargeType$;                    \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kUint8:                             \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types not uint8"; \
    break;                                          \
  case mshadow::kInt8:                              \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types not int8";  \
    break;                                          \
  case mshadow::kInt32:                             \
    LOG(FATAL) << "This operation only support "    \
                  "floating point types, not int32";\
    break;                                          \
  default:                                          \
    LOG(FATAL) << "Unknown type enum " << type$;    \
  }

#define MSHADOW_LAYOUT_SWITCH(layout, Layout, ...)  \
  switch (layout) {                                 \
  case mshadow::kNCHW:                              \
    {                                               \
      const int Layout = kNCHW;                     \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kNHWC:                              \
    {                                               \
      const int Layout = kNHWC;                     \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kNCDHW:                             \
    {                                               \
      const int Layout = kNCDHW;                    \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  case mshadow::kNDHWC:                             \
    {                                               \
      const int Layout = kNDHWC;                    \
      {__VA_ARGS__}                                 \
    }                                               \
    break;                                          \
  default:                                          \
    LOG(FATAL) << "Unknown layout enum " << layout; \
  }

/*! \brief get data type size from type enum */
inline size_t mshadow_sizeof(int type) {
  int size = 0;
  MSHADOW_TYPE_SWITCH(type, DType, size = sizeof(DType););
  return size;
}

}  // namespace mshadow
#endif  // MSHADOW_BASE_H_


#ifndef neo_hookean_h
#define neo_hookean_h

#include <petsc.h>
#include "../include/structs.h"

#ifndef PHYSICS_STRUCT_NH
#define PHYSICS_STRUCT_NH
typedef struct Physics_NH_ *Physics_NH;
struct Physics_NH_ {
  CeedScalar   nu;      // Poisson's ratio
  CeedScalar   E;       // Young's Modulus
};
#endif // PHYSICS_STRUCT_NH

// Create context object
PetscErrorCode PhysicsContext_NH(MPI_Comm comm, Ceed ceed, Units *units,
                                 CeedQFunctionContext *ctx);
PetscErrorCode PhysicsSmootherContext_NH(MPI_Comm comm, Ceed ceed,
    CeedQFunctionContext ctx, CeedQFunctionContext *ctx_smoother);

// Process physics options
PetscErrorCode ProcessPhysics_NH(MPI_Comm comm, Physics_NH phys, Units units);

#endif // neo_hookean_h


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

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

#include "find.c"

double
gsl_histogram_get (const gsl_histogram * h, size_t i)
{
  const size_t n = h->n;

  if (i >= n)
    {
      GSL_ERROR_VAL ("index lies outside valid range of 0 .. n - 1",
                        GSL_EDOM, 0);
    }

  return h->bin[i];
}

int
gsl_histogram_get_range (const gsl_histogram * h, size_t i,
                         double *lower, double *upper)
{
  const size_t n = h->n;

  if (i >= n)
    {
      GSL_ERROR ("index lies outside valid range of 0 .. n - 1", GSL_EDOM);
    }

  *lower = h->range[i];
  *upper = h->range[i + 1];

  return GSL_SUCCESS;
}

int
gsl_histogram_find (const gsl_histogram * h,
                    const double x, size_t * i)
{
  int status = find (h->n, h->range, x, i);

  if (status)
    {
      GSL_ERROR ("x not found in range of h", GSL_EDOM);
    }

  return GSL_SUCCESS;
}


/**
 * author: Jochen K"upper
 * created: Jan 2002
 * file: pygsl/src/statistics/longmodule.c
 * $Id: longmodule.c,v 1.10 2004/03/24 08:40:45 schnizer Exp $
 *
 * optional usage of Numeric module, available at http://numpy.sourceforge.net
 *"
 */

#include <Python.h>
#include <pygsl/error_helpers.h>
#include <pygsl/block_helpers.h>
#include <gsl/gsl_statistics.h>

/* include real functions for different data-types */

#define STATMOD_APPEND_PY_TYPE(X) X ## Int
#define STATMOD_APPEND_PYC_TYPE(X) X ## LONG
#define STATMOD_FUNC_EXT(X, Y) X ## _long ## Y
#define STATMOD_PY_AS_C PyInt_AsLong
#define STATMOD_C_TYPE long int
#include "functions.c"

/* initialization */
PyGSL_STATISTICS_INIT(long, "long")

/*
 * Local Variables:
 * mode: c
 * c-file-style: "Stroustrup"
 * End:
 */