/* multilarge.c
 *
 * Copyright (C) 2015 Patrick Alken
 *
 * 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 <gsl/gsl_math.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_multifit.h>
#include <gsl/gsl_multilarge.h>
#include <gsl/gsl_blas.h>

gsl_multilarge_linear_workspace *
gsl_multilarge_linear_alloc(const gsl_multilarge_linear_type *T,
                            const size_t p)
{
  gsl_multilarge_linear_workspace *w;

  w = calloc(1, sizeof(gsl_multilarge_linear_workspace));
  if (w == NULL)
    {
      GSL_ERROR_NULL("failed to allocate space for workspace",
                     GSL_ENOMEM);
    }

  w->type = T;

  w->state = w->type->alloc(p);
  if (w->state == NULL)
    {
      gsl_multilarge_linear_free(w);
      GSL_ERROR_NULL("failed to allocate space for multilarge state",
                     GSL_ENOMEM);
    }

  w->p = p;

  /* initialize newly allocated state */
  gsl_multilarge_linear_reset(w);

  return w;
}

void
gsl_multilarge_linear_free(gsl_multilarge_linear_workspace *w)
{
  RETURN_IF_NULL(w);

  if (w->state)
    w->type->free(w->state);

  free(w);
}

const char *
gsl_multilarge_linear_name(const gsl_multilarge_linear_workspace *w)
{
  return w->type->name;
}

int
gsl_multilarge_linear_reset(gsl_multilarge_linear_workspace *w)
{
  int status = w->type->reset(w->state);
  return status;
}

int
gsl_multilarge_linear_accumulate(gsl_matrix * X, gsl_vector * y,
                                 gsl_multilarge_linear_workspace * w)
{
  int status = w->type->accumulate(X, y, w->state);
  return status;
}

int
gsl_multilarge_linear_solve(const double lambda, gsl_vector * c,
                            double * rnorm, double * snorm,
                            gsl_multilarge_linear_workspace * w)
{
  int status = w->type->solve(lambda, c, rnorm, snorm, w->state);
  return status;
}

int
gsl_multilarge_linear_rcond(double *rcond, gsl_multilarge_linear_workspace * w)
{
  int status = w->type->rcond(rcond, w->state);
  return status;
}

int
gsl_multilarge_linear_lcurve(gsl_vector * reg_param, gsl_vector * rho,
                             gsl_vector * eta,
                             gsl_multilarge_linear_workspace * w)
{
  const size_t len = reg_param->size;

  if (len != rho->size)
    {
      GSL_ERROR ("reg_param and rho have different sizes", GSL_EBADLEN);
    }
  else if (len != eta->size)
    {
      GSL_ERROR ("reg_param and eta have different sizes", GSL_EBADLEN);
    }
  else
    {
      int status = w->type->lcurve(reg_param, rho, eta, w->state);
      return status;
    }
}

/*
gsl_multilarge_linear_wstdform1()
  Using regularization matrix
L = diag(l_1,l_2,...,l_p), transform to Tikhonov standard form:

X~ = sqrt(W) X L^{-1}
y~ = sqrt(W) y
c~ = L c

Inputs: L    - Tikhonov matrix as a vector of diagonal elements p-by-1;
               or NULL for L = I
        X    - least squares matrix n-by-p
        y    - right hand side vector n-by-1
        w    - weight vector n-by-1; or NULL for W = I
        Xs   - least squares matrix in standard form X~ n-by-p
        ys   - right hand side vector in standard form y~ n-by-1
        work - workspace

Return: success/error

Notes:
1) It is allowed for X = Xs and y = ys
*/

int
gsl_multilarge_linear_wstdform1 (const gsl_vector * L,
                                 const gsl_matrix * X,
                                 const gsl_vector * w,
                                 const gsl_vector * y,
                                 gsl_matrix * Xs,
                                 gsl_vector * ys,
                                 gsl_multilarge_linear_workspace * work)
{
  const size_t n = X->size1;
  const size_t p = X->size2;

  (void) work;

  if (L != NULL && p != L->size)
    {
      GSL_ERROR("L vector does not match X", GSL_EBADLEN);
    }
  else if (n != y->size)
    {
      GSL_ERROR("y vector does not match X", GSL_EBADLEN);
    }
  else if (w != NULL && n != w->size)
    {
      GSL_ERROR("weight vector does not match X", GSL_EBADLEN);
    }
  else if (n != Xs->size1 || p != Xs->size2)
    {
      GSL_ERROR("Xs matrix dimensions do not match X", GSL_EBADLEN);
    }
  else if (n != ys->size)
    {
      GSL_ERROR("ys vector must be length n", GSL_EBADLEN);
    }
  else
    {
      int status = GSL_SUCCESS;

      /* compute Xs = sqrt(W) X and ys = sqrt(W) y */
      status = gsl_multifit_linear_applyW(X, w, y, Xs, ys);
      if (status)
        return status;

      if (L != NULL)
        {
          size_t j;

          /* construct X~ = sqrt(W) X * L^{-1} matrix */
          for (j = 0; j < p; ++j)
            {
              gsl_vector_view Xj = gsl_matrix_column(Xs, j);
              double lj = gsl_vector_get(L, j);

              if (lj == 0.0)
                {
                  GSL_ERROR("L matrix is singular", GSL_EDOM);
                }

              gsl_vector_scale(&Xj.vector, 1.0 / lj);
            }
        }

      return status;
    }
}

int
gsl_multilarge_linear_stdform1 (const gsl_vector * L,
                                const gsl_matrix * X,
                                const gsl_vector * y,
                                gsl_matrix * Xs,
                                gsl_vector * ys,
                                gsl_multilarge_linear_workspace * work)
{
  int status;

  status = gsl_multilarge_linear_wstdform1(L, X, NULL, y, Xs, ys, work);

  return status;
}

int
gsl_multilarge_linear_L_decomp (gsl_matrix * L, gsl_vector * tau)
{
  const size_t m = L->size1;
  const size_t p = L->size2;

  if (m < p)
    {
      GSL_ERROR("m < p not yet supported", GSL_EBADLEN);
    }
  else
    {
      int status;

      status = gsl_multifit_linear_L_decomp(L, tau);

      return status;
    }
}

int
gsl_multilarge_linear_wstdform2 (const gsl_matrix * LQR,
                                 const gsl_vector * Ltau,
                                 const gsl_matrix * X,
                                 const gsl_vector * w,
                                 const gsl_vector * y,
                                 gsl_matrix * Xs,
                                 gsl_vector * ys,
                                 gsl_multilarge_linear_workspace * work)
{
  const size_t m = LQR->size1;
  const size_t n = X->size1;
  const size_t p = X->size2;

  (void) Ltau;

  if (p != work->p)
    {
      GSL_ERROR("X has wrong number of columns", GSL_EBADLEN);
    }
  else if (p != LQR->size2)
    {
      GSL_ERROR("LQR and X matrices have different numbers of columns", GSL_EBADLEN);
    }
  else if (n != y->size)
    {
      GSL_ERROR("y vector does not match X", GSL_EBADLEN);
    }
  else if (w != NULL && n != w->size)
    {
      GSL_ERROR("weights vector must be length n", GSL_EBADLEN);
    }
  else if (m < p)
    {
      GSL_ERROR("m < p not yet supported", GSL_EBADLEN);
    }
  else if (n != Xs->size1 || p != Xs->size2)
    {
      GSL_ERROR("Xs matrix must be n-by-p", GSL_EBADLEN);
    }
  else if (n != ys->size)
    {
      GSL_ERROR("ys vector must have length n", GSL_EBADLEN);
    }
  else
    {
      int status;
      size_t i;
      gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p);

      /* compute Xs = sqrt(W) X and ys = sqrt(W) y */
      status = gsl_multifit_linear_applyW(X, w, y, Xs, ys);
      if (status)
        return status;

      /* compute X~ = X R^{-1} using QR decomposition of L */
      for (i = 0; i < n; ++i)
        {
          gsl_vector_view v = gsl_matrix_row(Xs, i);

          /* solve: R^T y = X_i */
          gsl_blas_dtrsv(CblasUpper, CblasTrans, CblasNonUnit, &R.matrix, &v.vector);
        }

      return GSL_SUCCESS;
    }
}

int
gsl_multilarge_linear_stdform2 (const gsl_matrix * LQR,
                                const gsl_vector * Ltau,
                                const gsl_matrix * X,
                                const gsl_vector * y,
                                gsl_matrix * Xs,
                                gsl_vector * ys,
                                gsl_multilarge_linear_workspace * work)
{
  int status;

  status = gsl_multilarge_linear_wstdform2(LQR, Ltau, X, NULL, y, Xs, ys, work);

  return status;
}

/*
gsl_multilarge_linear_genform1()
  Backtransform regularized solution vector using matrix
L = diag(L)
*/

int
gsl_multilarge_linear_genform1 (const gsl_vector * L,
                                const gsl_vector * cs,
                                gsl_vector * c,
                                gsl_multilarge_linear_workspace * work)
{
  if (L->size != work->p)
    {
      GSL_ERROR("L vector does not match workspace", GSL_EBADLEN);
    }
  else if (L->size != cs->size)
    {
      GSL_ERROR("cs vector does not match L", GSL_EBADLEN);
    }
  else if (L->size != c->size)
    {
      GSL_ERROR("c vector does not match L", GSL_EBADLEN);
    }
  else
    {
      /* compute true solution vector c = L^{-1} c~ */
      gsl_vector_memcpy(c, cs);
      gsl_vector_div(c, L);

      return GSL_SUCCESS;
    }
}

int
gsl_multilarge_linear_genform2 (const gsl_matrix * LQR,
                                const gsl_vector * Ltau,
                                const gsl_vector * cs,
                                gsl_vector * c,
                                gsl_multilarge_linear_workspace * work)
{
  const size_t m = LQR->size1;
  const size_t p = LQR->size2;

  (void) Ltau;
  (void) work;

  if (p != c->size)
    {
      GSL_ERROR("c vector does not match LQR", GSL_EBADLEN);
    }
  else if (m < p)
    {
      GSL_ERROR("m < p not yet supported", GSL_EBADLEN);
    }
  else if (p != cs->size)
    {
      GSL_ERROR("cs vector size does not match c", GSL_EBADLEN);
    }
  else
    {
      int s;
      gsl_matrix_const_view R = gsl_matrix_const_submatrix(LQR, 0, 0, p, p); /* R factor of L */

      /* solve R c = cs for true solution c, using QR decomposition of L */
      gsl_vector_memcpy(c, cs);
      s = gsl_blas_dtrsv(CblasUpper, CblasNoTrans, CblasNonUnit, &R.matrix, c);

      return s;
    }
}

const gsl_matrix *
gsl_multilarge_linear_matrix_ptr (const gsl_multilarge_linear_workspace * work)
{
  return work->type->matrix_ptr(work->state);
}

const gsl_vector *
gsl_multilarge_linear_rhs_ptr (const gsl_multilarge_linear_workspace * work)
{
  return work->type->rhs_ptr(work->state);
}


/*
 * C version of Diffusive Nested Sampling (DNest4) by Brendon J. Brewer
 *
 * Yan-Rong Li, liyanrong@mail.ihep.ac.cn
 * Jun 30, 2016
 *
 */
#ifndef _DNESTVARS_H
#define _DNESTVARS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <gsl/gsl_rng.h>

#define DNEST_MAJOR_VERSION 0  // Dec 2, 2018
#define DNEST_MINOR_VERSION 1
#define DNEST_PATCH_VERSION 0

#define STR_MAX_LENGTH (100)
#define BUF_MAX_LENGTH (200)
#define LEVEL_NUM_MAX (2000)

/* output files */
extern FILE *fsample, *fsample_info;

/* random number generator */
extern const gsl_rng_type * dnest_gsl_T;
extern gsl_rng * dnest_gsl_r;

typedef struct
{
  double value;
  double tiebreaker;
}LikelihoodType;

typedef struct
{
  LikelihoodType log_likelihood;
  double log_X;
  unsigned long long int visits, exceeds;
  unsigned long long int accepts, tries;
}Level;

// struct for options
typedef struct
{
  unsigned int num_particles;
  unsigned int new_level_interval;
  unsigned int save_interval;
  unsigned int thread_steps;
  unsigned int max_num_levels;
  double lambda, beta;
  unsigned int max_num_saves;
  double max_ptol;

  char sample_file[STR_MAX_LENGTH];
  char sample_info_file[STR_MAX_LENGTH];
  char levels_file[STR_MAX_LENGTH];
  char sampler_state_file[STR_MAX_LENGTH];
  char posterior_sample_file[STR_MAX_LENGTH];
  char posterior_sample_info_file[STR_MAX_LENGTH];
  char limits_file[STR_MAX_LENGTH];
}Options;
extern Options options;
extern char options_file[STR_MAX_LENGTH];

typedef struct
{
  void (*from_prior)(void *model, const void *arg);
  double (*log_likelihoods_cal)(const void *model, const void *arg);
  double (*log_likelihoods_cal_initial)(const void *model, const void *arg);
  double (*log_likelihoods_cal_restart)(const void *model, const void *arg);
  double (*perturb)(void *model, const void *arg);
  void (*print_particle)(FILE *fp, const void *model, const void *arg);
  void (*read_particle)(FILE *fp, void *model);
  void (*restart_action)(int iflag);
  void (*accept_action)();
  void (*kill_action)(int i, int i_copy);
}DNestFptrSet;

extern void *particles;
extern int dnest_size_of_modeltype;
extern int particle_offset_size, particle_offset_double;

// sampler
extern bool save_to_disk;
extern unsigned int num_threads;
extern double compression;
extern unsigned int regularisation;

extern void *particles;
extern LikelihoodType *log_likelihoods;
extern unsigned int *level_assignments;

// number account of unaccepted times
extern unsigned int *account_unaccepts;

extern int size_levels;
extern Level *levels;
extern unsigned int count_saves, num_saves, num_saves_restart;
extern unsigned long long int count_mcmc_steps;
extern LikelihoodType *above;
extern unsigned int size_above;

extern int dnest_flag_restart, dnest_flag_postprc, dnest_flag_sample_info, dnest_flag_limits;
extern double dnest_post_temp;
extern char file_restart[STR_MAX_LENGTH], file_save_restart[STR_MAX_LENGTH];

extern double post_logz;
extern int dnest_num_params;
extern char dnest_sample_postfix[STR_MAX_LENGTH], dnest_sample_tag[STR_MAX_LENGTH], dnest_sample_dir[STR_MAX_LENGTH];

//the limits of parameters for each level;
extern double *limits, *copies_of_limits;

extern int dnest_which_particle_update; // which particle to be updated
extern int dnest_which_level_update;    // which level to be updated;
extern int *dnest_perturb_accept;
extern int dnest_root;

extern void *dnest_arg;
//***********************************************
/*                  functions                  */
extern double mod(double y, double x);
extern void dnest_wrap(double *x, double min, double max);
extern void wrap_limit(double *x, double min, double max);
extern int mod_int(int y, int x);
extern int dnest_cmp(const void *pa, const void *pb);

extern void options_load(int max_num_saves, double ptol);
extern void setup(int argc, char** argv, DNestFptrSet *fptrset, int num_params, char *sample_dir, int max_num_saves, double ptol);
extern void finalise();

extern double dnest(int argc, char **argv, DNestFptrSet *fptrset,  int num_params, char *sample_dir,
             int max_num_saves, double pdff, const void *arg);
extern void dnest_run();
extern void dnest_mcmc_run();
extern void update_particle(unsigned int which);
extern void update_level_assignment(unsigned int which);
extern double log_push(unsigned int which_level);
extern bool enough_levels(Level *l, int size_l);
extern void do_bookkeeping();
extern void save_levels();
extern void save_particle();
extern void save_limits();
extern void kill_lagging_particles();
extern void renormalise_visits();
extern void recalculate_log_X();
extern double dnest_randh();
extern double dnest_rand();
extern double dnest_randn();
extern int dnest_rand_int(int size);
extern void dnest_postprocess(double temperature, int max_num_saves, double ptol);
extern void postprocess(double temperature);
extern void initialize_output_file();
extern void close_output_file();
extern void dnest_save_restart();
extern void dnest_restart();
extern void dnest_restart_action(int iflag);
extern void dnest_accept_action();
extern void dnest_kill_action(int i, int i_copy);
extern void dnest_print_particle(FILE *fp, const void *model, const void *arg);
extern void dnest_read_particle(FILE *fp, void *model);
extern int dnest_get_size_levels();
extern int dnest_get_which_level_update();
extern int dnest_get_which_particle_update();
extern void dnest_get_posterior_sample_file(char *fname);
extern int dnest_check_version(char *verion_str);
extern unsigned int dnest_get_which_num_saves();
extern unsigned int dnest_get_count_saves();
extern unsigned long long int dnest_get_count_mcmc_steps();
extern void dnest_check_fptrset(DNestFptrSet *fptrset);
extern DNestFptrSet * dnest_malloc_fptrset();
extern void dnest_free_fptrset(DNestFptrSet * fptrset);
/*=====================================================*/
// users responsible for following functions
extern void (*print_particle)(FILE *fp, const void *model, const void *arg);
extern void (*read_particle)(FILE *fp, void *model);
extern void (*from_prior)(void *model, const void *arg);
extern double (*log_likelihoods_cal)(const void *model, const void *arg);
extern double (*log_likelihoods_cal_initial)(const void *model, const void *arg);
extern double (*log_likelihoods_cal_restart)(const void *model, const void *arg);
extern double (*perturb)(void *model, const void *arg);
extern void (*restart_action)(int iflag);
extern void (*accept_action)();
extern void (*kill_action)(int i, int i_copy);
/*=====================================================*/

#ifdef __cplusplus
}
#endif

#endif


#pragma once

#include <algorithm>
#include <array>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <sstream>
#include <string>

#include <absl/types/span.h>
#include <gsl/gsl>

#include "chainerx/axes.h"
#include "chainerx/constant.h"
#include "chainerx/dims.h"
#include "chainerx/error.h"

namespace chainerx {

class Strides;

class Shape : public Dims {
    using BaseVector = Dims;

public:
    using const_iterator = BaseVector::const_iterator;
    using const_reverse_iterator = BaseVector::const_reverse_iterator;
    // TODO(niboshi): Declare other types required for this class to be a container.

    Shape() = default;

    ~Shape() = default;

    // by iterators
    template <typename InputIt>
    Shape(InputIt first, InputIt last) {
        if (std::distance(first, last) > kMaxNdim) {
            throw DimensionError{"too many dimensions: ", std::distance(first, last)};
        }
        insert(begin(), first, last);
    }

    // by span
    explicit Shape(absl::Span<const int64_t> dims) : Shape{dims.begin(), dims.end()} {}

    // by initializer list
    Shape(std::initializer_list<int64_t> dims) : Shape{dims.begin(), dims.end()} {}

    // copy
    Shape(const Shape&) = default;
    Shape& operator=(const Shape&) = default;

    // move
    Shape(Shape&&) = default;
    Shape& operator=(Shape&&) = default;

    int64_t GetTotalSize() const;

    std::string ToString() const;

    int8_t ndim() const noexcept { return gsl::narrow_cast<int8_t>(size()); }

    const int64_t& operator[](int8_t index) const {
        if (!(0 <= index && static_cast<size_t>(index) < size())) {
            throw IndexError{"Shape index ", index, " out of bounds for shape with ", size(), " size."};
        }
        return this->Dims::operator[](index);
    }

    int64_t& operator[](int8_t index) {
        if (!(0 <= index && static_cast<size_t>(index) < size())) {
            throw IndexError{"Shape index ", index, " out of bounds for shape with ", size(), " size."};
        }
        return this->Dims::operator[](index);
    }

    // span
    absl::Span<const int64_t> span() const { return {*this}; }
};

namespace internal {

bool IsContiguous(const Shape& shape, const Strides& strides, int64_t item_size);

// Returns true if a reduction can take place under the given conditions, only considering the number of dimensions.
// Otherwise, returns false.
//
// TODO(hvy): Check the dimension lengths too and reconsider the interface. E.g. return void and assert inside the function if only used for
// assertions.
bool IsValidReductionShape(const Shape& in_shape, const Axes& axes, const Shape& out_shape, bool allow_keepdims);

int64_t CountItemsAlongAxes(const Shape& shape, const Axes& axes);

Shape BroadcastShapes(const Shape& shape0, const Shape& shape1);

// Returns a shape where axes are reduced.
Shape ReduceShape(const Shape& shape, const Axes& axes, bool keepdims);

// Returns a shape with additional axes, with length 1.
Shape ExpandShape(const Shape& shape, const Axes& axes);

Shape TransposeShape(const Shape& shape, const Axes& axes);

}  // namespace internal

std::ostream& operator<<(std::ostream& os, const Shape& shape);

void CheckEqual(const Shape& lhs, const Shape& rhs);

}  // namespace chainerx


/////////////////////////////////////////////////////////////////////
// = NMatrix
//
// A linear algebra library for scientific computation in Ruby.
// NMatrix is part of SciRuby.
//
// NMatrix was originally inspired by and derived from NArray, by
// Masahiro Tanaka: http://narray.rubyforge.org
//
// == Copyright Information
//
// SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
// NMatrix is Copyright (c) 2012, Ruby Science Foundation
//
// Please see LICENSE.txt for additional copyright notices.
//
// == Contributing
//
// By contributing source code to SciRuby, you agree to be bound by
// our Contributor Agreement:
//
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
//
// == cblas.c
//
// Functions in this file allow us to call CBLAS functions using
// arrays of function pointers, by ensuring that each has the same
// signature.

#ifndef CBLAS_C
# define CBLAS_C

#include <cblas.h>
#include "nmatrix.h"

//extern const enum CBLAS_ORDER;
//extern const enum CBLAS_TRANSPOSE;

inline void cblas_r32gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) r32gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.r[0], p.A, p.lda, p.B, p.ldb, p.beta.r[0], p.C, p.ldc);
  else                        r32gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.r[0], p.B, p.ldb, p.A, p.lda, p.beta.r[0], p.C, p.ldc);
}

inline void cblas_r32gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  r32gemv(TransA, p.M, p.N, p.alpha.r[0], p.A, p.lda, p.B, p.ldb, p.beta.r[0], p.C, p.ldc);
}

inline void cblas_r64gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) r64gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.ra[0], p.A, p.lda, p.B, p.ldb, p.beta.ra[0], p.C, p.ldc);
  else                        r64gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.ra[0], p.B, p.ldb, p.A, p.lda, p.beta.ra[0], p.C, p.ldc);
}

inline void cblas_r64gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  r64gemv(TransA, p.M, p.N, p.alpha.ra[0], p.A, p.lda, p.B, p.ldb, p.beta.ra[0], p.C, p.ldc);
}

inline void cblas_r128gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) r128gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.rat, p.A, p.lda, p.B, p.ldb, p.beta.rat, p.C, p.ldc);
  else                        r128gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.rat, p.B, p.ldb, p.A, p.lda, p.beta.rat, p.C, p.ldc);
}

inline void cblas_r128gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  r128gemv(TransA, p.M, p.N, p.alpha.rat, p.A, p.lda, p.B, p.ldb, p.beta.rat, p.C, p.ldc);
}

inline void cblas_bgemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  bgemv(TransA, p.M, p.N, p.alpha.b[0], p.A, p.lda, p.B, p.ldb, p.beta.b[0], p.C, p.ldc);
}

inline void cblas_bgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) bgemm(TransA, TransB, p.M, p.N, p.K, p.alpha.b[0], p.A, p.lda, p.B, p.ldb, p.beta.b[0], p.C, p.ldc);
  else                        bgemm(TransB, TransA, p.N, p.M, p.K, p.alpha.b[0], p.B, p.ldb, p.A, p.lda, p.beta.b[0], p.C, p.ldc);
}

inline void cblas_i8gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  i8gemv(TransA, p.M, p.N, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i8gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) i8gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
  else                        i8gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.i[0], p.B, p.ldb, p.A, p.lda, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i16gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  i16gemv(TransA, p.M, p.N, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i16gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) i16gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
  else                        i16gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.i[0], p.B, p.ldb, p.A, p.lda, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i32gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  i32gemv(TransA, p.M, p.N, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i32gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) i32gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
  else                        i32gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.i[0], p.B, p.ldb, p.A, p.lda, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i64gemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  i64gemv(TransA, p.M, p.N, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_i64gemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) i64gemm(TransA, TransB, p.M, p.N, p.K, p.alpha.i[0], p.A, p.lda, p.B, p.ldb, p.beta.i[0], p.C, p.ldc);
  else                        i64gemm(TransB, TransA, p.N, p.M, p.K, p.alpha.i[0], p.B, p.ldb, p.A, p.lda, p.beta.i[0], p.C, p.ldc);
}

inline void cblas_vgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  if (Order == CblasColMajor) vgemm(TransA, TransB, p.M, p.N, p.K, p.alpha.v[0], p.A, p.lda, p.B, p.ldb, p.beta.v[0], p.C, p.ldc);
  else                        vgemm(TransB, TransA, p.N, p.M, p.K, p.alpha.v[0], p.B, p.ldb, p.A, p.lda, p.beta.v[0], p.C, p.ldc);
}

inline void cblas_sgemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  cblas_sgemv(Order, TransA, p.M, p.N, p.alpha.d[0], p.A, p.lda, p.B, p.ldb, p.beta.d[0], p.C, p.ldc);
}

inline void cblas_sgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  cblas_sgemm(Order, TransA, TransB, p.M, p.N, p.K, p.alpha.d[0], p.A, p.lda, p.B, p.ldb, p.beta.d[0], p.C, p.ldc);
}

inline void cblas_dgemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  cblas_dgemv(Order, TransA, p.M, p.N, p.alpha.d[0], p.A, p.lda, p.B, p.ldb, p.beta.d[0], p.C, p.ldc);
}

inline void cblas_dgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  cblas_dgemm(Order, TransA, TransB, p.M, p.N, p.K, p.alpha.d[0], p.A, p.lda, p.B, p.ldb, p.beta.d[0], p.C, p.ldc);
}

inline void cblas_cgemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  cblas_cgemv(Order, TransA, p.M, p.N, &(p.alpha.c), p.A, p.lda, p.B, p.ldb, &(p.beta.c), p.C, p.ldc);
}

inline void cblas_cgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  cblas_cgemm(Order, TransA, TransB, p.M, p.N, p.K, &(p.alpha.c), p.A, p.lda, p.B, p.ldb, &(p.beta.c), p.C, p.ldc);
}

inline void cblas_zgemv_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, DENSE_PARAM p) {
  cblas_zgemv(Order, TransA, p.M, p.N, &(p.alpha.z), p.A, p.lda, p.B, p.ldb, &(p.beta.z), p.C, p.ldc);
}

inline void cblas_zgemm_(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_TRANSPOSE TransB, DENSE_PARAM p) {
  cblas_zgemm(Order, TransA, TransB, p.M, p.N, p.K, &(p.alpha.z), p.A, p.lda, p.B, p.ldb, &(p.beta.z), p.C, p.ldc);
}

#endif


// Copyright (c) 2005 - 2010 Marc de Kamps
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//    * 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.
//    * Neither the name of the copyright holder 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.
//
//      If you use this software in work leading to a scientific publication, you should cite
//      the 'currently valid reference', which can be found at http://miind.sourceforge.net
#ifndef _CODE_LIBS_NUMTOOLSLIB_NODE_GSLOBJECTS_INCLUDE_GUARD
#define _CODE_LIBS_NUMTOOLSLIB_NODE_GSLOBJECTS_INCLUDE_GUARD

#include <boost/shared_ptr.hpp>
#include <gsl/gsl_odeiv.h>
#include <gsl/gsl_errno.h>
#include "Precision.h"

using boost::shared_ptr;

namespace NumtoolsLib {
  typedef unsigned int Number;

	typedef int (*Function)   (double t, const double y[], double dydt[], void * params);
	typedef int (*Derivative) (double t, const double y[], double * dfdy, double dfdt[], void * params);

	//! auxilliary struct to clean up some of the code of AbstractDVIntegrator
	struct GSLObjects{

		const gsl_odeiv_step_type*		_p_step_algorithm; //!< pointer to function, so no ownership issues
		gsl_odeiv_step*					_p_step;
		gsl_odeiv_control*				_p_controller;
		gsl_odeiv_evolve*				_p_evolver;
		gsl_odeiv_system				_system;

		GSLObjects
		(
			const gsl_odeiv_step_type*,	//<! choice for solver type
			Number,						//<! state size
			const Precision&			//<! absolute and relative precision conform GSL documentation
		);

		~GSLObjects();

	};
}

#endif // include guard


/* Initialize topic and POV assignments uniformly at random, and set
   various hyper-parameters needed for inference. Assignments must be
   initialized before doing inference for the first time. */

#include <assert.h>
#include <gsl/gsl_rng.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "index.h"
#include "parse_mmaps.h"
#include "sample.h"

int main(int argc, char **argv) {
  if (argc != 11) {
    printf("Usage: %s mmap_directory num_topics pov_per_topic num_threads psi_alpha "
	   "psi_beta gamma_alpha gamma_beta beta alpha\n",
           argv[0]);
    exit(1);
  }
  int num_threads = atoi(argv[4]);
  char *endptr;
  create_indexes(argv[1],
		 strtod(argv[5], &endptr),
		 strtod(argv[6], &endptr),
		 strtod(argv[7], &endptr),
		 strtod(argv[8], &endptr),
		 strtod(argv[9], &endptr),
		 strtod(argv[10], &endptr),
		 atoi(argv[2]),
		 atoi(argv[3]),
		 num_threads);
  struct mmap_info mmap_info = open_mmaps_mmap(argv[1]);

  // If revisions are numbered from zero, make sure the first
  // revision gets assigned a null topic/POV
  struct revision_assignment* first_assignment
    = get_revision_assignment(&mmap_info, 0);
  first_assignment->topic = -1;
  first_assignment->pov = -1;

  struct sample_threads sample_threads;
  initialize_threads(&sample_threads, num_threads, &mmap_info);
  resample_null(&sample_threads);
  resample_uniform(&sample_threads);

  destroy_threads(&sample_threads);
  close_mmaps(mmap_info);
}


#ifndef OPERATOR_H
#define OPERATOR_H

#include <chrono>
#include <iostream>
#include <utility>
#include <vector>
#include <memory>
#include <string>
#include <sstream>

#include <gsl/gsl_matrix.h>
#include <gsl/gsl_spmatrix.h>
#include <gsl/gsl_splinalg.h>

#include "constants.h"

using std::array;
using std::pair;
using std::shared_ptr;
using std::tuple;
using std::vector;
using std::string;

// Smart pointer to matrix
using mat_operator = shared_ptr<gsl_spmatrix>;

// Shorthand for template types
using ComputeStatus = vector<pair<size_t, std::string>>;
using ListCmu = const vector<mat_operator>;
using VecPair = pair<gsl_vector *, gsl_vector *>;
using VecTriplet = tuple<gsl_vector *, gsl_vector *, gsl_vector *>;

// Generate operator L
gsl_matrix *computeL();

// Generate operator C
void computeC();

gsl_spmatrix *computeSingleC(size_t mu);

void findValidCs(vector<bool>& toStore);

void setFilenames(string& raw, string& compressed, size_t mu);

gsl_spmatrix *loadMat(size_t mu);
void storeMat(const gsl_spmatrix *C_mu, size_t mu);

#endif // OPERATOR_H


// Server settings and option parsing
#ifndef _SETTINGS_H
#define _SETTINGS_H

#include <gsl/gsl_rng.h>
#include <stdbool.h>

// Settings the server has
typedef struct _settings {
	int verbose;
	int threads;
	int tcpport;
	double dist_arg1; // normal distribution mean
	double dist_arg2; // normal distribution stddev
	bool use_dist;
	gsl_rng *r;
} settings;

void usage(void);
settings settings_init(void);
bool settings_parse(int argc, char **argv, settings *s);

#endif


#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <gsl/gsl_rng.h>

#include "allvars.h"
#include "proto.h"
#include "domain.h"

static FILE *fd;

static void in(int *x, int modus);
static void byten(void *x, int n, int modus);

/* This function reads or writes the restart files.
 * Each processor writes its own restart file, with the
 * I/O being done in parallel. To avoid congestion of the disks
 * you can tell the program to restrict the number of files
 * that are simultaneously written to NumFilesWrittenInParallel.
 *
 * If modus>0  the restart()-routine reads,
 * if modus==0 it writes a restart file.
 */
void restart(int modus)
{
  char buf[200], buf_bak[200], buf_mv[500];
  double save_PartAllocFactor;
  int i, nprocgroup, masterTask, groupTask, old_MaxPart, old_MaxNodes;
  struct global_data_all_processes all_task0;

#if defined(SFR) || defined(BLACK_HOLES)
#ifdef NO_TREEDATA_IN_RESTART
  if(modus == 0)
    {
      rearrange_particle_sequence();
      All.NumForcesSinceLastDomainDecomp = (long long) (1 + All.TreeDomainUpdateFrequency * All.TotNumPart);	/* ensures that new tree will be constructed */
    }
#endif
#endif

  if(ThisTask == 0 && modus == 0)
    {
      sprintf(buf, "%s/restartfiles", All.OutputDir);
      mkdir(buf, 02755);
    }
  MPI_Barrier(MPI_COMM_WORLD);

  sprintf(buf, "%s/restartfiles/%s.%d", All.OutputDir, All.RestartFile, ThisTask);
  sprintf(buf_bak, "%s/restartfiles/%s.%d.bak", All.OutputDir, All.RestartFile, ThisTask);
  sprintf(buf_mv, "mv %s %s", buf, buf_bak);

  if((NTask < All.NumFilesWrittenInParallel))
    {
      printf
	("Fatal error.\nNumber of processors must be a smaller or equal than `NumFilesWrittenInParallel'.\n");
      endrun(2131);
    }

  nprocgroup = NTask / All.NumFilesWrittenInParallel;

  if((NTask % All.NumFilesWrittenInParallel))
    {
      nprocgroup++;
    }

  masterTask = (ThisTask / nprocgroup) * nprocgroup;

  for(groupTask = 0; groupTask < nprocgroup; groupTask++)
    {
      if(ThisTask == (masterTask + groupTask))
	{
	  if(!modus)
	    {
#ifndef NOCALLSOFSYSTEM
	      int ret;

	      ret = system(buf_mv);	/* move old restart files to .bak files */
#endif
	    }
	}
    }

  for(groupTask = 0; groupTask < nprocgroup; groupTask++)
    {
      if(ThisTask == (masterTask + groupTask))	/* ok, it's this processor's turn */
	{
	  if(modus)
	    {
	      if(!(fd = fopen(buf, "r")))
		{
		  printf("Restart file '%s' not found.\n", buf);
		  endrun(7870);
		}
	    }
	  else
	    {
	      if(!(fd = fopen(buf, "w")))
		{
		  printf("Restart file '%s' cannot be opened.\n", buf);
		  endrun(7878);
		}
	    }

	  save_PartAllocFactor = All.PartAllocFactor;

	  /* common data  */
	  byten(&All, sizeof(struct global_data_all_processes), modus);

	  if(ThisTask == 0 && modus > 0)
	    all_task0 = All;

	  if(modus > 0 && groupTask == 0)	/* read */
	    {
	      MPI_Bcast(&all_task0, sizeof(struct global_data_all_processes), MPI_BYTE, 0, MPI_COMM_WORLD);
	    }

	  old_MaxPart = All.MaxPart;
	  old_MaxNodes = (int) (All.TreeAllocFactor * All.MaxPart) + NTopnodes;

	  if(modus)		/* read */
	    {
	      if(All.PartAllocFactor != save_PartAllocFactor)
		{
		  All.PartAllocFactor = save_PartAllocFactor;
		  All.MaxPart = (int) (All.PartAllocFactor * (All.TotNumPart / NTask));
		  All.MaxPartSph = (int) (All.PartAllocFactor * (All.TotN_gas / NTask));
#ifdef INHOMOG_GASDISTR_HINT
		  All.MaxPartSph = All.MaxPart;
#endif
		  save_PartAllocFactor = -1;
		}

	      if(all_task0.Time != All.Time)
		{
		  printf("The restart file on task=%d is not consistent with the one on task=0\n", ThisTask);
		  fflush(stdout);
		  endrun(16);
		}

	      allocate_memory();
	    }

	  in(&NumPart, modus);

	  if(NumPart > All.MaxPart)
	    {
	      printf
		("it seems you have reduced(!) 'PartAllocFactor' below the value of %g needed to load the restart file.\n",
		 NumPart / (((double) All.TotNumPart) / NTask));
	      printf("fatal error\n");
	      endrun(22);
	    }

	  /* Particle data  */
	  byten(&P[0], NumPart * sizeof(struct particle_data), modus);

	  in(&N_gas, modus);

	  if(N_gas > 0)
	    {
	      if(N_gas > All.MaxPartSph)
		{
		  printf
		    ("SPH: it seems you have reduced(!) 'PartAllocFactor' below the value of %g needed to load the restart file.\n",
		     N_gas / (((double) All.TotN_gas) / NTask));
		  printf("fatal error\n");
		  endrun(222);
		}
	      /* Sph-Particle data  */
	      byten(&SphP[0], N_gas * sizeof(struct sph_particle_data), modus);
	    }

	  /* write state of random number generator */
	  byten(gsl_rng_state(random_generator), gsl_rng_size(random_generator), modus);

	  /* now store relevant data for tree */
#ifdef SFR
	  in(&Stars_converted, modus);
#endif

#ifndef NO_TREEDATA_IN_RESTART
	  /* now store relevant data for tree */
	  int nmulti = MULTIPLEDOMAINS;

	  in(&nmulti, modus);
	  if(modus != 0 && nmulti != MULTIPLEDOMAINS)
	    {
	      if(ThisTask == 0)
		printf
		  ("Looks like you changed MULTIPLEDOMAINS from %d to %d.\nWill discard tree stored in restart files and construct a new one.\n",
		   nmulti, (int) MULTIPLEDOMAINS);

	      All.NumForcesSinceLastDomainDecomp = (long long) (1 + All.TreeDomainUpdateFrequency * All.TotNumPart);	/* ensures that new tree will be constructed */
	    }
	  else
	    {
	      in(&NTopleaves, modus);
	      in(&NTopnodes, modus);

	      if(modus)		/* read */
		{
		  domain_allocate();
		  force_treeallocate((int) (All.TreeAllocFactor * All.MaxPart) + NTopnodes, All.MaxPart);
		}

	      in(&Numnodestree, modus);

	      if(Numnodestree > MaxNodes)
		{
		  printf
		    ("Tree storage: it seems you have reduced(!) 'PartAllocFactor' below the value needed to load the restart file (task=%d). "
		     "Numnodestree=%d  MaxNodes=%d\n", ThisTask, Numnodestree, MaxNodes);
		  endrun(221);
		}

	      byten(Nodes_base, Numnodestree * sizeof(struct NODE), modus);
	      byten(Extnodes_base, Numnodestree * sizeof(struct extNODE), modus);

	      byten(Father, NumPart * sizeof(int), modus);

	      byten(Nextnode, NumPart * sizeof(int), modus);
	      byten(Nextnode + All.MaxPart, NTopnodes * sizeof(int), modus);

	      byten(DomainStartList, NTask * MULTIPLEDOMAINS * sizeof(int), modus);
	      byten(DomainEndList, NTask * MULTIPLEDOMAINS * sizeof(int), modus);
	      byten(DomainTask, NTopnodes * sizeof(int), modus);
	      byten(DomainNodeIndex, NTopleaves * sizeof(int), modus);

	      byten(DomainCorner, 3 * sizeof(double), modus);
	      byten(DomainCenter, 3 * sizeof(double), modus);
	      byten(&DomainLen, sizeof(double), modus);
	      byten(&DomainFac, sizeof(double), modus);

	      if(modus)		/* read */
		if(All.PartAllocFactor != save_PartAllocFactor)
		  {
		    for(i = 0; i < NumPart; i++)
		      Father[i] += (All.MaxPart - old_MaxPart);

		    for(i = 0; i < NumPart; i++)
		      if(Nextnode[i] >= old_MaxPart)
			{
			  if(Nextnode[i] >= old_MaxPart + old_MaxNodes)
			    Nextnode[i] += (All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxPart);
			  else
			    Nextnode[i] += (All.MaxPart - old_MaxPart);
			}

		    for(i = 0; i < Numnodestree; i++)
		      {
			if(Nodes_base[i].u.d.sibling >= old_MaxPart)
			  {
			    if(Nodes_base[i].u.d.sibling >= old_MaxPart + old_MaxNodes)
			      Nodes_base[i].u.d.sibling +=
				(All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxNodes);
			    else
			      Nodes_base[i].u.d.sibling += (All.MaxPart - old_MaxPart);
			  }

			if(Nodes_base[i].u.d.father >= old_MaxPart)
			  {
			    if(Nodes_base[i].u.d.father >= old_MaxPart + old_MaxNodes)
			      Nodes_base[i].u.d.father +=
				(All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxNodes);
			    else
			      Nodes_base[i].u.d.father += (All.MaxPart - old_MaxPart);
			  }

			if(Nodes_base[i].u.d.nextnode >= old_MaxPart)
			  {
			    if(Nodes_base[i].u.d.nextnode >= old_MaxPart + old_MaxNodes)
			      Nodes_base[i].u.d.nextnode +=
				(All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxNodes);
			    else
			      Nodes_base[i].u.d.nextnode += (All.MaxPart - old_MaxPart);
			  }
		      }

		    for(i = 0; i < NTopnodes; i++)
		      if(Nextnode[i + All.MaxPart] >= old_MaxPart)
			{
			  if(Nextnode[i + All.MaxPart] >= old_MaxPart + old_MaxNodes)
			    Nextnode[i + All.MaxPart] +=
			      (All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxNodes);
			  else
			    Nextnode[i + All.MaxPart] += (All.MaxPart - old_MaxPart);
			}

		    for(i = 0; i < NTopnodes; i++)
		      if(DomainNodeIndex[i] >= old_MaxPart)
			{
			  if(DomainNodeIndex[i] >= old_MaxPart + old_MaxNodes)
			    DomainNodeIndex[i] += (All.MaxPart - old_MaxPart) + (MaxNodes - old_MaxNodes);
			  else
			    DomainNodeIndex[i] += (All.MaxPart - old_MaxPart);
			}
		  }
	    }
#endif
	  fclose(fd);
	}
      else			/* wait inside the group */
	{
	  if(modus > 0 && groupTask == 0)	/* read */
	    {
	      MPI_Bcast(&all_task0, sizeof(struct global_data_all_processes), MPI_BYTE, 0, MPI_COMM_WORLD);
	    }
	}

      MPI_Barrier(MPI_COMM_WORLD);
    }
#ifdef HEALPIX
  //this should be readed in the parameterfile
  All.Nside=8;
  //
  if(ThisTask==0)
  printf(" Restart calculation of Healpix %i with %i \n",All.Nside,NSIDE2NPIX(All.Nside));
  // initialize the healpix array (just in case)
  All.healpixmap=(float *) malloc(NSIDE2NPIX(All.Nside) * sizeof(float));
  for(i=0;i<NSIDE2NPIX(All.Nside);i++)All.healpixmap[i]=0;
  healpix_halo(All.healpixmap);
#endif
}

/* reads/writes n bytes
 */
void byten(void *x, int n, int modus)
{
  if(modus)
    my_fread(x, n, 1, fd);
  else
    my_fwrite(x, n, 1, fd);
}

/* reads/writes one int
 */
void in(int *x, int modus)
{
  if(modus)
    my_fread(x, 1, sizeof(int), fd);
  else
    my_fwrite(x, 1, sizeof(int), fd);
}


/* ieee-utils/fp-darwin86.c
 *
 * Copyright (C) 2006 Erik Schnetter
 *
 * 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 <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_errno.h>

/* Here is the dirty part. Set up your 387 through the control word
 * (cw) register.
 *
 *     15-13    12  11-10  9-8     7-6     5    4    3    2    1    0
 * | reserved | IC | RC  | PC | reserved | PM | UM | OM | ZM | DM | IM
 *
 * IM: Invalid operation mask
 * DM: Denormalized operand mask
 * ZM: Zero-divide mask
 * OM: Overflow mask
 * UM: Underflow mask
 * PM: Precision (inexact result) mask
 *
 * Mask bit is 1 means no interrupt.
 *
 * PC: Precision control
 * 11 - round to extended precision
 * 10 - round to double precision
 * 00 - round to single precision
 *
 * RC: Rounding control
 * 00 - rounding to nearest
 * 01 - rounding down (toward - infinity)
 * 10 - rounding up (toward + infinity)
 * 11 - rounding toward zero
 *
 * IC: Infinity control
 * That is for 8087 and 80287 only.
 *
 * The hardware default is 0x037f which we use.
 */

/* masking of interrupts */
#define _FPU_MASK_IM  0x01
#define _FPU_MASK_DM  0x02
#define _FPU_MASK_ZM  0x04
#define _FPU_MASK_OM  0x08
#define _FPU_MASK_UM  0x10
#define _FPU_MASK_PM  0x20

/* precision control */
#define _FPU_EXTENDED 0x300	/* libm requires double extended precision.  */
#define _FPU_DOUBLE   0x200
#define _FPU_SINGLE   0x0

/* rounding control */
#define _FPU_RC_NEAREST 0x0    /* RECOMMENDED */
#define _FPU_RC_DOWN    0x400
#define _FPU_RC_UP      0x800
#define _FPU_RC_ZERO    0xC00

#define _FPU_RESERVED 0xF0C0  /* Reserved bits in cw */

/* The fdlibm code requires strict IEEE double precision arithmetic,
   and no interrupts for exceptions, rounding to nearest.  */

#define _FPU_DEFAULT  0x037f

/* IEEE:  same as above.  */
#define _FPU_IEEE     0x037f

/* Type of the control word.  */
typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__)));

/* Macros for accessing the hardware control word.

   Note that the use of these macros is no sufficient anymore with
   recent hardware.  Some floating point operations are executed in
   the SSE/SSE2 engines which have their own control and status register.  */
#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw))
#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw))

/* Default control word set at startup.  */
extern fpu_control_t __fpu_control;

#define _FPU_GETMXCSR(cw_sse) asm volatile ("stmxcsr %0" : "=m" (cw_sse))
#define _FPU_SETMXCSR(cw_sse) asm volatile ("ldmxcsr %0" : : "m" (cw_sse))

int
gsl_ieee_set_mode (int precision, int rounding, int exception_mask)
{
  fpu_control_t mode, mode_sse;

  _FPU_GETCW (mode) ;
  mode &= _FPU_RESERVED ;

  switch (precision)
    {
    case GSL_IEEE_SINGLE_PRECISION:
      mode |= _FPU_SINGLE ;
      break ;
    case GSL_IEEE_DOUBLE_PRECISION:
      mode |= _FPU_DOUBLE ;
      break ;
    case GSL_IEEE_EXTENDED_PRECISION:
      mode |= _FPU_EXTENDED ;
      break ;
    default:
      mode |= _FPU_EXTENDED ;
    }

  switch (rounding)
    {
    case GSL_IEEE_ROUND_TO_NEAREST:
      mode |= _FPU_RC_NEAREST ;
      break ;
    case GSL_IEEE_ROUND_DOWN:
      mode |= _FPU_RC_DOWN ;
      break ;
    case GSL_IEEE_ROUND_UP:
      mode |= _FPU_RC_UP ;
      break ;
    case GSL_IEEE_ROUND_TO_ZERO:
      mode |= _FPU_RC_ZERO ;
      break ;
    default:
      mode |= _FPU_RC_NEAREST ;
    }

  if (exception_mask & GSL_IEEE_MASK_INVALID)
    mode |= _FPU_MASK_IM ;

  if (exception_mask & GSL_IEEE_MASK_DENORMALIZED)
    mode |= _FPU_MASK_DM ;

  if (exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
    mode |= _FPU_MASK_ZM ;

  if (exception_mask & GSL_IEEE_MASK_OVERFLOW)
    mode |= _FPU_MASK_OM ;

  if (exception_mask & GSL_IEEE_MASK_UNDERFLOW)
    mode |= _FPU_MASK_UM ;

  if (exception_mask & GSL_IEEE_TRAP_INEXACT)
    {
      mode &= ~ _FPU_MASK_PM ;
    }
  else
    {
      mode |= _FPU_MASK_PM ;
    }

  _FPU_SETCW (mode) ;

  _FPU_GETMXCSR (mode_sse) ;
  mode_sse &= 0xFFFF0000 ;

  if (exception_mask & GSL_IEEE_MASK_INVALID)
    mode_sse |= _FPU_MASK_IM << 7 ;

  if (exception_mask & GSL_IEEE_MASK_DENORMALIZED)
    mode_sse |= _FPU_MASK_DM << 7 ;

  if (exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
    mode_sse |= _FPU_MASK_ZM << 7 ;

  if (exception_mask & GSL_IEEE_MASK_OVERFLOW)
    mode_sse |= _FPU_MASK_OM << 7 ;

  if (exception_mask & GSL_IEEE_MASK_UNDERFLOW)
    mode_sse |= _FPU_MASK_UM << 7 ;

  if (exception_mask & GSL_IEEE_TRAP_INEXACT)
    {
      mode_sse &= ~ _FPU_MASK_PM << 7 ;
    }
  else
    {
      mode_sse |= _FPU_MASK_PM << 7 ;
    }

  _FPU_SETMXCSR (mode_sse) ;

  return GSL_SUCCESS ;
}


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

#include <math.h>
#include <ieeefp.h>
#include <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_errno.h>

int
gsl_ieee_set_mode (int precision, int rounding, int exception_mask)
{
  fp_except mode = 0 ;
  fp_rnd    rnd  = 0 ;

  switch (precision)
    {
    case GSL_IEEE_SINGLE_PRECISION:
      GSL_ERROR ("solaris only supports default precision rounding",
                 GSL_EUNSUP) ;
      break ;
    case GSL_IEEE_DOUBLE_PRECISION:
      GSL_ERROR ("solaris only supports default precision rounding",
                 GSL_EUNSUP) ;
      break ;
    case GSL_IEEE_EXTENDED_PRECISION:
      GSL_ERROR ("solaris only supports default precision rounding",
                 GSL_EUNSUP) ;
      break ;
    }

  switch (rounding)
    {
    case GSL_IEEE_ROUND_TO_NEAREST:
      rnd = FP_RN ;
      fpsetround (rnd) ;
      break ;
    case GSL_IEEE_ROUND_DOWN:
      rnd = FP_RM ;
      fpsetround (rnd) ;
      break ;
    case GSL_IEEE_ROUND_UP:
      rnd = FP_RP ;
      fpsetround (rnd) ;
      break ;
    case GSL_IEEE_ROUND_TO_ZERO:
      rnd = FP_RZ ;
      fpsetround (rnd) ;
      break ;
    default:
      rnd = FP_RN ;
      fpsetround (rnd) ;
    }

  /* Turn on all the exceptions apart from 'inexact' */

  mode = FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL ;

  if (exception_mask & GSL_IEEE_MASK_INVALID)
    mode &= ~ FP_X_INV ;

  if (exception_mask & GSL_IEEE_MASK_DENORMALIZED)
    {
      /* do nothing */
    }
  else
    {
      GSL_ERROR ("solaris does not support the denormalized operand exception. "
                 "Use 'mask-denormalized' to work around this.",
                 GSL_EUNSUP) ;
    }

  if (exception_mask & GSL_IEEE_MASK_DIVISION_BY_ZERO)
    mode &= ~ FP_X_DZ ;

  if (exception_mask & GSL_IEEE_MASK_OVERFLOW)
    mode &= ~ FP_X_OFL ;

  if (exception_mask & GSL_IEEE_MASK_UNDERFLOW)
    mode &=  ~ FP_X_UFL ;

  if (exception_mask & GSL_IEEE_TRAP_INEXACT)
    {
      mode |= FP_X_IMP ;
    }
  else
    {
      mode &= ~ FP_X_IMP ;
    }

  fpsetmask (mode) ;

  return GSL_SUCCESS ;

}


/* monte/gsl_monte_plain.h
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Michael Booth
 *
 * 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.
 */

/* Plain Monte-Carlo. */

/* Author: MJB */

#ifndef __GSL_MONTE_PLAIN_H__
#define __GSL_MONTE_PLAIN_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 <stdio.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_rng.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 dim;
  double *x;
} gsl_monte_plain_state;

GSL_FUN int
gsl_monte_plain_integrate (const gsl_monte_function * f,
                           const double xl[], const double xu[],
                           const size_t dim,
                           const size_t calls,
                           gsl_rng * r,
                           gsl_monte_plain_state * state,
                           double *result, double *abserr);

GSL_FUN gsl_monte_plain_state* gsl_monte_plain_alloc(size_t dim);

GSL_FUN int gsl_monte_plain_init(gsl_monte_plain_state* state);

GSL_FUN void gsl_monte_plain_free (gsl_monte_plain_state* state);

__END_DECLS

#endif /* __GSL_MONTE_PLAIN_H__ */


// --------------------------------------------------------------------------
//                   OpenMS -- Open-Source Mass Spectrometry
// --------------------------------------------------------------------------
// Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
// ETH Zurich, and Freie Universitaet Berlin 2002-2013.
//
// This software is released under a three-clause BSD license:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * 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.
//  * Neither the name of any author or any participating institution
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
// For a full list of authors, refer to the file AUTHORS.
// --------------------------------------------------------------------------
// 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 ANY OF THE AUTHORS OR THE CONTRIBUTING
// INSTITUTIONS 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.
//
// --------------------------------------------------------------------------
// $Maintainer: $
// $Authors: Hendrik Weisser $
// --------------------------------------------------------------------------

#ifndef OPENMS_ANALYSIS_MAPMATCHING_TRANSFORMATIONMODEL_H
#define OPENMS_ANALYSIS_MAPMATCHING_TRANSFORMATIONMODEL_H

#include <OpenMS/DATASTRUCTURES/Param.h>

#include <gsl/gsl_bspline.h>
#include <gsl/gsl_interp.h>

namespace OpenMS
{
  /**
       @brief Base class for transformation models

       Implements the identity (no transformation). Parameters and data are ignored.

       @ingroup MapAlignment
  */
  class OPENMS_DLLAPI TransformationModel
  {
public:
    /// Coordinate pair
    typedef std::pair<DoubleReal, DoubleReal> DataPoint;
    /// Vector of coordinate pairs
    typedef std::vector<DataPoint> DataPoints;

    /// Constructor
    TransformationModel() {}

    /// Alternative constructor (derived classes should implement this one!)
    TransformationModel(const TransformationModel::DataPoints &,
                        const Param &) :
      params_() {}

    /// Destructor
    virtual ~TransformationModel() {}

    /// Evaluates the model at the given value
    virtual DoubleReal evaluate(const DoubleReal value) const
    {
      return value;
    }

    /// Gets the (actual) parameters
    void getParameters(Param & params) const
    {
      params = params_;
    }

    /// Gets the default parameters
    static void getDefaultParameters(Param & params)
    {
      params.clear();
    }

protected:
    /// Parameters
    Param params_;
  };

  /**
       @brief Linear model for transformations

       The model can be inferred from data or specified using explicit parameters. If data is given, a least squares fit is used to find the model parameters (slope and intercept). Depending on parameter @p symmetric_regression, a normal regression (@e y on @e x) or symmetric regression (@f$ y - x @f$ on @f$ y + x @f$) is performed.

       Without data, the model can be specified by giving the parameters @p slope and @p intercept explicitly.

       @ingroup MapAlignment
  */
  class OPENMS_DLLAPI TransformationModelLinear :
    public TransformationModel
  {
public:
    /**
        @brief Constructor

        @exception IllegalArgument is thrown if neither data points nor explicit parameters (slope/intercept) are given.
    */
    TransformationModelLinear(const DataPoints & data, const Param & params);

    /// Destructor
    ~TransformationModelLinear();

    /// Evaluates the model at the given value
    virtual DoubleReal evaluate(const DoubleReal value) const;

    using TransformationModel::getParameters;

    /// Gets the "real" parameters
    void getParameters(DoubleReal & slope, DoubleReal & intercept) const;

    /// Gets the default parameters
    static void getDefaultParameters(Param & params);

    /**
         @brief Computes the inverse

         @exception DivisionByZero is thrown if the slope is zero.
    */
    void invert();

protected:
    /// Parameters of the linear model
    DoubleReal slope_, intercept_;
    /// Was the model estimated from data?
    bool data_given_;
    /// Use symmetric regression?
    bool symmetric_;
  };

  /**
       @brief Interpolation model for transformations

       Between the data points, the interpolation uses the neighboring points. Outside the range spanned by the points, we extrapolate using a line through the first and the last point.

       Different types of interpolation (controlled by the parameter @p interpolation_type) are supported: "linear", "polynomial", "cspline", and "akima". Note that the number of required data points may differ between types.

       @ingroup MapAlignment
  */
  class OPENMS_DLLAPI TransformationModelInterpolated :
    public TransformationModel
  {
public:
    /**
         @brief Constructor

         @exception IllegalArgument is thrown if there are not enough data points or if an unknown interpolation type is given.
    */
    TransformationModelInterpolated(const DataPoints & data,
                                    const Param & params);

    /// Destructor
    ~TransformationModelInterpolated();

    /// Evaluates the model at the given value
    DoubleReal evaluate(const DoubleReal value) const;

    /// Gets the default parameters
    static void getDefaultParameters(Param & params);

protected:
    /// Data coordinates
    std::vector<double> x_, y_;
    /// Number of data points
    size_t size_;
    /// Look-up accelerator
    gsl_interp_accel * acc_;
    /// Interpolation function
    gsl_interp * interp_;
    /// Linear model for extrapolation
    TransformationModelLinear * lm_;
  };

  /**
       @brief B-spline model for transformations

       In the range of the data points, the transformation is evaluated from a cubic smoothing spline fit to the points. The number of breakpoints is given as a parameter (@p num_breakpoints). Outside of this range, linear extrapolation through the last point with the slope of the spline at that point is used.

       Positioning of the breakpoints is controlled by the parameter @p break_positions. Valid choices are "uniform" (equidistant spacing on the data range) and "quantiles" (equal numbers of data points in every interval).

       @ingroup MapAlignment
  */
  class OPENMS_DLLAPI TransformationModelBSpline :
    public TransformationModel
  {
public:
    /**
         @brief Constructor

         @exception IllegalArgument is thrown if not enough data points are given or if the required parameter @p num_breakpoints is missing.
    */
    TransformationModelBSpline(const DataPoints & data, const Param & params);

    /// Destructor
    ~TransformationModelBSpline();

    /// Evaluates the model at the given value
    DoubleReal evaluate(const DoubleReal value) const;

    /// Gets the default parameters
    static void getDefaultParameters(Param & params);

protected:
    /**
        @brief Finds quantile values

        @param x Data vector to find quantiles in
        @param quantiles Quantiles to find (values between 0 and 1)
        @param results Resulting quantiles (vector must be already allocated to the correct size!)
    */
    void getQuantiles_(const gsl_vector * x, const std::vector<double> &
                       quantiles, gsl_vector * results);

    /// Computes the B-spline fit
    void computeFit_();

    /// Computes the linear extrapolation
    void computeLinear_(const double pos, double & slope, double & offset,
                        double & sd_err);

    /// Vectors for B-spline computation
    gsl_vector * x_, * y_, * w_, * bsplines_, * coeffs_;
    /// Covariance matrix
    gsl_matrix * cov_;
    /// B-spline workspace
    gsl_bspline_workspace * workspace_;
    /// Number of data points and coefficients
    size_t size_, ncoeffs_;
    // First/last breakpoint
    double xmin_, xmax_;
    /// Parameters for linear extrapolation
    double slope_min_, slope_max_, offset_min_, offset_max_;
    /// Fitting errors of linear extrapolation
    double sd_err_left_, sd_err_right_;
  };

} // end of namespace OpenMS

#endif // OPENMS_ANALYSIS_MAPMATCHING_TRANSFORMATIONMODEL_H


/*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*
**                                                                                **
** This file forms part of the Underworld geophysics modelling application.         **
**                                                                                **
** For full license and copyright information, please refer to the LICENSE.md file  **
** located at the project root, or contact the authors.                             **
**                                                                                **
**~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*/
/*
This provides a couple of routines which allowed the time per iteration
to be stored. This is achieved useing the KSPMonitors. The issue with using
these monitors is the petsc support for these is terrible. We need to be
able to access our user monitor context, but petsc only lets you get the
context from the FIRST monitor, which we cannot guarentee will be the one
defined to store the timing information.

To get around this we store the index into the monitor array which our
monitor gets inersted into. This works, but we have no 'nice' way to
recover the user monitor context except via the monitor_index. Thus when
the monitor is set, we return the value of the monitor index. This number
is required whenever you wish to extract the timing information.

*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif /* _GNU_SOURCE needed for asprintf */
#include <stdio.h>
#include <stdlib.h>

#include <petsc.h>
#include <petscvec.h>
#include <petscmat.h>
#include <petscksp.h>

#include <StGermain/StGermain.h>
#include <StgDomain/StgDomain.h>

#include "common-driver-utils.h"

#include <petscversion.h>
#if ( (PETSC_VERSION_MAJOR >= 3) && (PETSC_VERSION_MINOR >=3) )
  #if (PETSC_VERSION_MINOR >=6)
     #include "petsc/private/kspimpl.h"
  #else
     #include "petsc-private/kspimpl.h"
  #endif
#else
  #include "private/kspimpl.h"
#endif

struct timed_cvg_ctx {
	PetscInt monitor_index;
	PetscInt hist_len, hist_len_max;
	PetscLogDouble *time_log;
	PetscLogDouble time;
	PetscReal *r_log;
};

/* ~~~~~~~~~~~~~~~~ SolverMonitor routines ~~~~~~~~~~~~~~~~~~~~~~ */
/*
I shouldn't need to include the residual log, but the petsc one does strange things, when used
with gmres and fgmres. I know it's related to restarts but I just don't get it. This one will
produce the same data as that which is displayed on the screen when you used -ksp_monitor.
*/

#undef __FUNCT__
#define __FUNCT__ "BSSCR_check_validity_of_timing_monitor"
PetscErrorCode BSSCR_check_validity_of_timing_monitor( KSP ksp, PetscInt monitor_index )
{

	if( monitor_index < 0 ) {
		Stg_SETERRQ1( PETSC_ERR_ARG_WRONG, "Monitor index cannot be negative. You had %D", monitor_index );
	}
	if( monitor_index >= ksp->numbermonitors ) {
		Stg_SETERRQ2( PETSC_ERR_ARG_WRONG, "Monitor index >= number of monitors set (%D). You had %D", ksp->numbermonitors, monitor_index );
	}

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogHistory"
PetscErrorCode BSSCR_KSPLogHistory(struct timed_cvg_ctx *ctx,PetscReal norm)
{
	PetscLogDouble t, time;

	PetscGetTime(&t);
	time = t - ctx->time;
	if (ctx->hist_len==0) {
		/* Get reference time and zero first result */
		PetscGetTime(&ctx->time);
		time = 0.0;
	}

	if (ctx->r_log && ctx->time_log && ctx->hist_len_max > ctx->hist_len) {
		ctx->r_log[ctx->hist_len] = norm;
		ctx->time_log[ctx->hist_len] = time;

		ctx->hist_len++;
	}

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_timed_cvg_test"
PetscErrorCode BSSCR_timed_cvg_test(KSP ksp, int it, PetscReal rnorm, void *mctx)
{
	struct timed_cvg_ctx *ctx = (struct timed_cvg_ctx*)(mctx);

	BSSCR_KSPLogHistory(ctx,rnorm);

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogDestroyMonitor"
PetscErrorCode BSSCR_KSPLogDestroyMonitor(void *_ctx)
{
	struct timed_cvg_ctx *ctx = (struct timed_cvg_ctx*)_ctx;

	PetscFree( ctx->r_log );
	PetscFree( ctx->time_log );
	PetscFree( ctx );

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogSetMonitor"
PetscErrorCode BSSCR_KSPLogSetMonitor(KSP ksp,PetscInt len,PetscInt *monitor_index)
{
	PetscLogDouble *time_log;
	PetscReal *r_log;
	struct timed_cvg_ctx *ctx;

	PetscMalloc( sizeof(PetscLogDouble)*len, &time_log );
	PetscMalloc( sizeof(PetscReal)*len, &r_log );
	PetscMalloc( sizeof(struct timed_cvg_ctx), &ctx );

	ctx->hist_len_max  = len;
	ctx->hist_len      = 0;
	ctx->time_log      = time_log;
	ctx->r_log         = r_log;

	ctx->monitor_index = ksp->numbermonitors;
	*monitor_index = ksp->numbermonitors;

	//KSPSetConvergenceTest(ksp,timed_cvg_test,(void*)ctx );
	KSPMonitorSet( ksp, BSSCR_timed_cvg_test, (void*)ctx, BSSCR_KSPLogDestroyMonitor );

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogGetTimeHistory"
PetscErrorCode BSSCR_KSPLogGetTimeHistory(KSP ksp,PetscInt monitor_index, PetscInt *na,PetscLogDouble **log)
{
	struct timed_cvg_ctx *ctx;
	PetscInt its;

	ctx = (struct timed_cvg_ctx*)ksp->monitorcontext[ monitor_index ];

	KSPGetIterationNumber(ksp,&its);
	its = its + 1;
	*na = PetscMin( (PetscInt)(its), (PetscInt)(ctx->hist_len_max) );
	*log = ctx->time_log;

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogGetResidualHistory"
PetscErrorCode BSSCR_KSPLogGetResidualHistory(KSP ksp,PetscInt monitor_index, PetscInt *na,PetscReal **rlog)
{
	struct timed_cvg_ctx *ctx;
	PetscInt its;

	ctx = (struct timed_cvg_ctx*)ksp->monitorcontext[ monitor_index ];
	KSPGetIterationNumber(ksp,&its);
	its = its + 1;
	*na = PetscMin( (PetscInt)(its), (PetscInt)(ctx->hist_len_max) );
	*rlog = ctx->r_log;

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogGetResidualTimeHistory"
PetscErrorCode BSSCR_KSPLogGetResidualTimeHistory(KSP ksp,PetscInt monitor_index, PetscInt *na,PetscReal **rlog,PetscLogDouble **tlog)
{
	struct timed_cvg_ctx *ctx;
	PetscInt its;

	KSPGetIterationNumber(ksp,&its);
	ctx = (struct timed_cvg_ctx*)ksp->monitorcontext[ monitor_index ];
	its = its + 1;
	*na = PetscMin( (PetscInt)(its), (PetscInt)(ctx->hist_len_max) );
	*rlog = ctx->r_log;
	*tlog = ctx->time_log;

	PetscFunctionReturn(0);
}

KSPNormType  BS_NO_PC=  KSP_NORM_UNPRECONDITIONED;
KSPNormType  BS_W_PC=   KSP_NORM_PRECONDITIONED;

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPGetNormType"
PetscErrorCode BSSCR_KSPGetNormType(KSP ksp, KSPNormType *normtype) {
	*normtype = ksp->normtype;
	return(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_KSPLogSolve"
PetscErrorCode BSSCR_KSPLogSolve(PetscViewer v,PetscInt monitor_index, KSP ksp)
{
	Vec b,u;
	PetscInt i;
	KSPType type;
	PetscReal b_nrm, *rlog;
	PC pc;
	PetscLogDouble *log;
	PetscInt nits;
	KSPNormType ntype;
	PCSide side;
	PetscTruth has_unpc_config, ksp_matches;
	const char *list[]            = { "cg"   , "bicg" , "bcgs" , "gmres" , "fgmres", "minres", "lgmres", 0 };
	const PCSide   pc_side[]      = { PC_LEFT, PC_LEFT, PC_LEFT, PC_RIGHT, PC_RIGHT, PC_LEFT , PC_RIGHT, 0 };
	const KSPNormType norm_type[] = { BS_NO_PC  , BS_NO_PC  , BS_NO_PC  , BS_W_PC    , BS_NO_PC   , BS_NO_PC   , BS_W_PC    , 0 };

	KSPGetRhs( ksp, &b );
	KSPGetSolution( ksp, &u );

	KSPGetType( ksp, &type );
	BSSCR_KSPGetNormType( ksp, &ntype );
	KSPGetPreconditionerSide( ksp, &side );
	has_unpc_config = PETSC_FALSE;

	i = 0;
	while (list[i]) {
		PetscStrcmp( "fgmres", type, &ksp_matches );
		if (ksp_matches) {
			has_unpc_config = PETSC_TRUE;
			break;
		}

		PetscStrcmp( list[i],type,&ksp_matches );
		if (ksp_matches) {
			if( pc_side[i] == side && ntype == norm_type[i] ) {
				has_unpc_config = PETSC_TRUE;
				break;
			}
		}
		i++;
	}

	if (has_unpc_config) {
		PetscViewerASCIIPrintf( v, "[%s] Detected options consistent with unpreconditioned norm: using side=%d, norm_type=%d \n", type, side, ntype );
	}

	BSSCR_KSPLogGetResidualTimeHistory(ksp,monitor_index, &nits,&rlog,&log);
	if (!rlog || !log) {
		Stg_SETERRQ( PETSC_ERR_ORDER, "You need to call BSSCR_KSPLogSetMonitor() before BSSCR_KSPLogGetResidualTimeHistory()" );
	}

	if (!has_unpc_config) {
		Vec pc_b;
		VecDuplicate( u, &pc_b );
		KSPGetPC( ksp, &pc );
		PCApply( pc, b, pc_b );
		VecNorm( pc_b, NORM_2, &b_nrm );

		Stg_VecDestroy(&pc_b );

		PetscViewerASCIIPrintf( v, "# it        |Qr|               |Qr0|              |f|             |Qr|/|Qr0|         log10(Qr/Qr0)       |Qr|/|Qf|          log10(Qr/Qf)           time\n" );
	}
	else if (has_unpc_config) {
		VecNorm( b, NORM_2, &b_nrm );
		PetscViewerASCIIPrintf( v, "# it         |r|               |r0|               |f|              |r|/|r0|          log10(r/r0)          |r|/|f|           log10(r/f)            time\n" );
	}

	for( i=0; i<nits; i++ ) {
		PetscViewerASCIIPrintf( v, "%1.4d %14.12e %14.12e %14.12e %14.12e %14.12e %14.12e %14.12e %14.12e\n",
				i, rlog[i],rlog[0],b_nrm, rlog[i]/rlog[0],log10(rlog[i]/rlog[0]), rlog[i]/b_nrm,log10(rlog[i]/b_nrm), log[i] );
	}

	PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "BSSCR_BSSCR_KSPLogSolveSummary"
PetscErrorCode BSSCR_BSSCR_KSPLogSolveSummary(PetscViewer v,PetscInt monitor_index, KSP ksp)
{
	KSPConvergedReason reason;
	char *reas;
	PetscReal *rlog;
	PetscLogDouble *log;
	PetscInt nits;

	KSPGetConvergedReason( ksp, &reason );
	if( reason == KSP_CONVERGED_RTOL )
		asprintf(&reas, "KSP_CONVERGED_RTOL" );
	else if( reason == KSP_CONVERGED_ATOL )
		asprintf(&reas, "KSP_CONVERGED_ATOL" );
	else if( reason == KSP_CONVERGED_ITS )
		asprintf(&reas, "KSP_CONVERGED_ITS" );
	else if( reason == KSP_DIVERGED_ITS )
		asprintf(&reas, "KSP_DIVERGED_ITS" );
	else if( reason == KSP_DIVERGED_DTOL )
		asprintf(&reas, "KSP_DIVERGED_DTOL" );
	else if( reason == KSP_DIVERGED_INDEFINITE_PC )
		asprintf(&reas, "KSP_DIVERGED_INDEFINITE_PC" );
	else {
		Stg_SETERRQ( PETSC_ERR_SUP, "unknown convergence reason detected");
	}

	BSSCR_KSPLogGetResidualTimeHistory(ksp,monitor_index, &nits,&rlog,&log);
	if (!rlog || !log) {
		Stg_SETERRQ( PETSC_ERR_ORDER, "You need to call BSSCR_KSPLogSetMonitor() before BSSCR_KSPLogGetResidualTimeHistory()" );
	}
	PetscViewerASCIIPrintf( v, "\n");
	PetscViewerASCIIPrintf( v, "# ===========================================================\n");
	PetscViewerASCIIPrintf( v, "#  KSP summary \n" );
	PetscViewerASCIIPrintf( v, "#  time (its) [rnorm] reason \n" );
	PetscViewerASCIIPrintf( v, "#  %.2f (%d) %.2e %s \n", log[nits-1], nits-1, rlog[nits-1], reas );
	PetscViewerASCIIPrintf( v, "# ===========================================================\n");

	PetscFunctionReturn(0);
}


$NetBSD: patch-Src___dotblas.c,v 1.1 2015/01/27 05:05:30 dbj Exp $

--- Src/_dotblas.c.orig	2006-07-24 20:11:35.000000000 +0000
+++ Src/_dotblas.c
@@ -12,7 +12,11 @@ static char module_doc[] =
 #include "Python.h"
 #include "libnumarray.h"
 #include "arrayobject.h"
+#ifdef __APPLE__
+#include <Accelerate/Accelerate.h>
+#else
 #include <cblas.h>
+#endif

 #include <stdio.h>


// matrix/kaldi-blas.h

// Copyright 2009-2011  Ondrej Glembek;  Microsoft Corporation

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

// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
#ifndef KALDI_MATRIX_KALDI_BLAS_H_
#define KALDI_MATRIX_KALDI_BLAS_H_

// This file handles the #includes for BLAS, LAPACK and so on.
// It manipulates the declarations into a common format that kaldi can handle.
// However, the kaldi code will check whether HAVE_ATLAS is defined as that
// code is called a bit differently from CLAPACK that comes from other sources.

// There are three alternatives:
//   (i) you have ATLAS, which includes the ATLAS implementation of CBLAS
//   plus a subset of CLAPACK (but with clapack_ in the function declarations).
//   In this case, define HAVE_ATLAS and make sure the relevant directories are
//   in the include path.

//   (ii) you have CBLAS (some implementation thereof) plus CLAPACK.
//   In this case, define HAVE_CLAPACK.
//   [Since CLAPACK depends on BLAS, the presence of BLAS is implicit].

//  (iii) you have the MKL library, which includes CLAPACK and CBLAS.

// Note that if we are using ATLAS, no Svd implementation is supplied,
// so we define HAVE_Svd to be zero and this directs our implementation to
// supply its own "by hand" implementation which is based on TNT code.

#if (defined(HAVE_CLAPACK) && (defined(HAVE_ATLAS) || defined(HAVE_MKL))) \
    || (defined(HAVE_ATLAS) && defined(HAVE_MKL))
#error "Do not define more than one of HAVE_CLAPACK, HAVE_ATLAS and HAVE_MKL"
#endif

#ifdef HAVE_ATLAS
  extern "C" {
    #include <cblas.h>
    #include <clapack.h>
  }
#elif defined(HAVE_CLAPACK)
  #ifdef __APPLE__
    #include <Accelerate/Accelerate.h>
    typedef __CLPK_integer          integer;
    typedef __CLPK_logical          logical;
    typedef __CLPK_real             real;
    typedef __CLPK_doublereal       doublereal;
    typedef __CLPK_complex          complex;
    typedef __CLPK_doublecomplex    doublecomplex;
    typedef __CLPK_ftnlen           ftnlen;
  #else
    extern "C" {
      // May be in /usr/[local]/include if installed; else this uses the one
      // from the external/CLAPACK-* directory.
      #include <cblas.h>
      #include <f2c.h>
      #include <clapack.h>

      // get rid of macros from f2c.h -- these are dangerous.
      #undef abs
      #undef dabs
      #undef min
      #undef max
      #undef dmin
      #undef dmax
      #undef bit_test
      #undef bit_clear
      #undef bit_set
    }
  #endif
#elif defined(HAVE_MKL)
  extern "C" {
    #include <mkl.h>
  }
#else
  #error "You need to define (using the preprocessor) either HAVE_CLAPACK or HAVE_ATLAS or HAVE_MKL (but not more than one)"
#endif

#ifdef HAVE_CLAPACK
typedef integer KaldiBlasInt;
#endif
#ifdef HAVE_MKL
typedef MKL_INT KaldiBlasInt;
#endif

#ifdef HAVE_ATLAS
// in this case there is no need for KaldiBlasInt-- this typedef is only needed
// for Svd code which is not included in ATLAS (we re-implement it).
#endif

#endif  // KALDI_MATRIX_KALDI_BLAS_H_


#ifndef COMPUTE_SIGNAL_H
#define COMPUTE_SIGNAL_H

#include <gsl/gsl_rng.h>
#include <gsl/gsl_histogram.h>

void compute_signal(double * signal, const size_t length, const double delta,
    gsl_rng * r, gsl_histogram * hist);

#endif


/*
 * global.h
 *
 *  Created on: Apr 5, 2013
 *      Authors: vgomez, Sep Thijssen
 */

#ifndef GLOBAL_H_
#define GLOBAL_H_

#include <vector>
#include <math.h>
#include <iostream>

#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

#include <ctime>

#include <hal_quadrotor/State.h>

#define SIZE_MSG	5

using namespace std;

// Message structure
//	IIIII.XXX.xxx.YYY.yyy.ZZZ.zzz.UUU.uuu.VVV.vvv.WWW.vvv
//	IIIII		identifier of the UVA
//	XXX.xxx	position x
//	YYY.yyy	position y
//	ZZZ.zzz	position z
//	UUU.uuu	velocity x
//	VVV.vvv	velocity y
//	WWW.www	velocity z

typedef vector<double> vec;
typedef vector<vec> vvec;

template<typename G>
ostream& operator<<(ostream& os, const vector<G>& v)
{
	typename vector<G>::const_iterator it;
	for (it=v.begin(); it!=v.end(); it++)
		os << *it << " ";
	os << endl;
	return os;
}

string getState(const hal_quadrotor::State::ConstPtr& msg);

#endif /* GLOBAL_H_ */


#ifndef REMESHER_GSL_HELPERS_HEADER
#define REMESHER_GSL_HELPERS_HEADER

#include <iostream>
#include <iomanip>
#include <string>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>

namespace GSL
{
  void
  pretty_print_matrix (gsl_matrix* m, std::string const& name)
  {
    std::cout << name << " = [";
    for (std::size_t i = 0; i < m->size2; ++i)
    {
      if (i != 0) std::cout << ";" << std::endl << "     ";
      for (std::size_t j = 0; j < m->size1; ++j)
      {
        if (j != 0) std::cout << ", ";
        std::cout << std::setw(6) << std::fixed << std::setprecision(2)
            << gsl_matrix_get(m, i, j);
      }
    }
    std::cout << "];" << std::endl;
  }

  void
  pretty_print_vector (gsl_vector* v, std::string const& name)
  {
    std::cout << name << " = [";
    for (std::size_t i = 0; i < v->size; ++i)
    {
      if (i != 0) std::cout << "; ";
      std::cout << std::setw(6) << std::fixed << std::setprecision(2)
            << gsl_vector_get(v, i);
    }
    std::cout << "];" << std::endl;
  }

}

#endif /* REMESHER_GSL_HELPERS_HEADER */


#include <errno.h>
#include <getopt.h>
#include <gsl/gsl_spmatrix.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

static int clock = 1;
static int results = 0;
static int verbose = 0;
static int help = 0;

int test (size_t m,
          size_t n,
          size_t nnz,
          const size_t *ptr,
          const size_t *ind,
          size_t B,
          double epsilon,
          double delta,
          int trials,
          int clock,
          int results,
          int verbose);

char *name ();

static void usage () {
  fprintf(stderr,"usage: %s [options] <input>\n"
  "  <input>                    MatrixMarket file (estimate fill of this matrix)\n"
  "  -B, --max-block-size <arg> Maximum block dimension for fill estimates\n"
  "  -e, --epsilon <arg>        Be accurate to relative error epsilon\n"
  "  -d, --delta <arg>          With probability (1 - delta)\n"
  "  -t, --trials <arg>         Number of trials to run\n"
  "  -c, --clock                Display timing information\n"
  "  -C, --noclock              Do not display timing information\n"
  "  -r, --results              Display fill estimates for all trials\n"
  "  -R, --noresults            Do not display fill estimates\n"
  "  -v, --verbose              Verbose mode\n"
  "  -q, --quiet                Quiet mode\n"
  "  -h, --help                 Display help message\n", name());
}

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

  size_t B = 12;
  double epsilon = 0.1;
  double delta = 0.01;
  int trials = 1;

  /* Beware. Option parsing below. */
  long longarg;
  double doublearg;
  while (1) {
    static char *options = "B:e:d:t:cCrRvqh";
    static struct option long_options[] = {
        {"max-block-size", required_argument, 0, 'B'},
        {"trials",         required_argument, 0, 't'},
        {"epsilon", required_argument, 0, 'e'},
        {"delta", required_argument, 0, 'd'},
        {"clock",     no_argument, &clock,   1},
        {"noclock",   no_argument, &clock,   0},
        {"results",   no_argument, &results, 1},
        {"noresults", no_argument, &results, 0},
        {"verbose",   no_argument, &verbose, 1},
        {"quiet",     no_argument, &verbose, 0},
        {"help",      no_argument, &help,    1},
        {0, 0, 0, 0}
      };

    /* getopt_long stores the option index here. */
    int option_index = 0;

    int c = getopt_long (argc, argv, options,
                     long_options, &option_index);

    /* Detect the end of the options. */
    if (c == -1)
      break;

    if (c == 0 && long_options[option_index].flag == 0)
      c = long_options[option_index].val;

    switch (c) {
      case 0:
        /* If this option set a flag, do nothing else now. */
        break;

      case 'B':
        errno = 0;
        longarg = strtol(optarg, 0, 10);
        if (errno != 0 || longarg < 1) {
          printf("option -B takes an integer maximum block size >= 1\n");
          usage();
          return 1;
        }
        B = longarg;
        break;

      case 'e':
        errno = 0;
        doublearg = strtod(optarg, 0);
        if (errno != 0 || doublearg < 0.0) {
          printf("option -e takes a desired relative error >= 0.0\n");
          usage();
          return 1;
        }
        epsilon = doublearg;
        break;

      case 'd':
        errno = 0;
        doublearg = strtod(optarg, 0);
        if (errno != 0 || doublearg < 0.0 || doublearg > 1.0) {
          printf("option -d takes a desired probability >= 0.0 and <= 1.0\n");
          usage();
          return 1;
        }
        delta = doublearg;
        break;

      case 't':
        errno = 0;
        longarg = strtol(optarg, 0, 10);
        if (errno != 0 || longarg < 1) {
          printf("option -t takes an integer number of trials >= 1\n");
          usage();
          return 1;
        }
        trials = longarg;
        break;

      case 'c':
        clock = 1;
        break;

      case 'C':
        clock = 0;
        break;

      case 'r':
        results = 1;
        break;

      case 'R':
        results = 0;
        break;

      case 'v':
        verbose = 1;
        break;

      case 'q':
        verbose = 0;
        break;

      case 'h':
        help = 1;
        break;

      case '?':
        usage();
        return 1;

      default:
        abort();
    }
  }

  if (help) {
    printf("Run a fill estimation algorithm!\n");
    usage();
    return 0;
  }

  if (argc - optind > 1) {
    printf("<input> cannot be more than one file\n");
    usage();
    return 1;
  }

  if (argc - optind < 1) {
    printf("<input> not specified\n");
    usage();
    return 1;
  }

  struct stat statthing;
  if (stat(argv[optind], &statthing) < 0 || !S_ISREG(statthing.st_mode)){
    printf("<input> must be filename of MatrixMarket matrix\n");
    usage();
    return 1;
  }

  FILE *f = fopen(argv[optind], "r");
  gsl_spmatrix *triples = gsl_spmatrix_fscanf(f);
  fclose(f);
  if (triples == 0) {
    printf("<input> must be filename of MatrixMarket matrix\n");
    usage();
    return 1;
  }

  gsl_spmatrix *csr = gsl_spmatrix_crs(triples);
  gsl_spmatrix_free(triples);

  //gsl_spmatrix_fprintf(stdout, csr, "%g");

  int ret = test(csr->size1, csr->size2, csr->nz, csr->p, csr->i, B, epsilon, delta, trials, clock, results, verbose);

  gsl_spmatrix_free(csr);

  return ret;
}