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

#ifndef __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__
#define __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__

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

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_complex_long_double.h>
#include <gsl/gsl_blas_types.h>

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

__BEGIN_DECLS

typedef struct
{
  size_t size1;
  size_t size2;
  size_t tda;
  long double * data;
  gsl_block_complex_long_double * block;
  int owner;
} gsl_matrix_complex_long_double ;

typedef struct
{
  gsl_matrix_complex_long_double matrix;
} _gsl_matrix_complex_long_double_view;

typedef _gsl_matrix_complex_long_double_view gsl_matrix_complex_long_double_view;

typedef struct
{
  gsl_matrix_complex_long_double matrix;
} _gsl_matrix_complex_long_double_const_view;

typedef const _gsl_matrix_complex_long_double_const_view gsl_matrix_complex_long_double_const_view;

/* Allocation */

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_calloc (const size_t n1, const size_t n2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc_from_block (gsl_block_complex_long_double * b,
                                           const size_t offset,
                                           const size_t n1, const size_t n2, const size_t d2);

GSL_FUN gsl_matrix_complex_long_double *
gsl_matrix_complex_long_double_alloc_from_matrix (gsl_matrix_complex_long_double * b,
                                            const size_t k1, const size_t k2,
                                            const size_t n1, const size_t n2);

GSL_FUN gsl_vector_complex_long_double *
gsl_vector_complex_long_double_alloc_row_from_matrix (gsl_matrix_complex_long_double * m,
                                                const size_t i);

GSL_FUN gsl_vector_complex_long_double *
gsl_vector_complex_long_double_alloc_col_from_matrix (gsl_matrix_complex_long_double * m,
                                                const size_t j);

GSL_FUN void gsl_matrix_complex_long_double_free (gsl_matrix_complex_long_double * m);

/* Views */

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_submatrix (gsl_matrix_complex_long_double * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_row (gsl_matrix_complex_long_double * m, const size_t i);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_column (gsl_matrix_complex_long_double * m, const size_t j);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_diagonal (gsl_matrix_complex_long_double * m);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subdiagonal (gsl_matrix_complex_long_double * m, const size_t k);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_superdiagonal (gsl_matrix_complex_long_double * m, const size_t k);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subrow (gsl_matrix_complex_long_double * m,
                                 const size_t i, const size_t offset,
                                 const size_t n);

GSL_FUN _gsl_vector_complex_long_double_view
gsl_matrix_complex_long_double_subcolumn (gsl_matrix_complex_long_double * m,
                                    const size_t j, const size_t offset,
                                    const size_t n);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_array (long double * base,
                             const size_t n1,
                             const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_array_with_tda (long double * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_vector (gsl_vector_complex_long_double * v,
                              const size_t n1,
                              const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_view
gsl_matrix_complex_long_double_view_vector_with_tda (gsl_vector_complex_long_double * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_submatrix (const gsl_matrix_complex_long_double * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_row (const gsl_matrix_complex_long_double * m,
                            const size_t i);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_column (const gsl_matrix_complex_long_double * m,
                               const size_t j);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_diagonal (const gsl_matrix_complex_long_double * m);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subdiagonal (const gsl_matrix_complex_long_double * m,
                                    const size_t k);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_superdiagonal (const gsl_matrix_complex_long_double * m,
                                      const size_t k);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subrow (const gsl_matrix_complex_long_double * m,
                                       const size_t i, const size_t offset,
                                       const size_t n);

GSL_FUN _gsl_vector_complex_long_double_const_view
gsl_matrix_complex_long_double_const_subcolumn (const gsl_matrix_complex_long_double * m,
                                          const size_t j, const size_t offset,
                                          const size_t n);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_array (const long double * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_array_with_tda (const long double * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_vector (const gsl_vector_complex_long_double * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_FUN _gsl_matrix_complex_long_double_const_view
gsl_matrix_complex_long_double_const_view_vector_with_tda (const gsl_vector_complex_long_double * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_FUN void gsl_matrix_complex_long_double_set_zero (gsl_matrix_complex_long_double * m);
GSL_FUN void gsl_matrix_complex_long_double_set_identity (gsl_matrix_complex_long_double * m);
GSL_FUN void gsl_matrix_complex_long_double_set_all (gsl_matrix_complex_long_double * m, gsl_complex_long_double x);

GSL_FUN int gsl_matrix_complex_long_double_fread (FILE * stream, gsl_matrix_complex_long_double * m) ;
GSL_FUN int gsl_matrix_complex_long_double_fwrite (FILE * stream, const gsl_matrix_complex_long_double * m) ;
GSL_FUN int gsl_matrix_complex_long_double_fscanf (FILE * stream, gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_fprintf (FILE * stream, const gsl_matrix_complex_long_double * m, const char * format);

GSL_FUN int gsl_matrix_complex_long_double_memcpy(gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);
GSL_FUN int gsl_matrix_complex_long_double_swap(gsl_matrix_complex_long_double * m1, gsl_matrix_complex_long_double * m2);
GSL_FUN int gsl_matrix_complex_long_double_tricpy(CBLAS_UPLO_t Uplo, CBLAS_DIAG_t Diag, gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);

GSL_FUN int gsl_matrix_complex_long_double_swap_rows(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_swap_columns(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_swap_rowcol(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);

GSL_FUN int gsl_matrix_complex_long_double_transpose (gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_transpose_memcpy (gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);
GSL_FUN int gsl_matrix_complex_long_double_transpose_tricpy(CBLAS_UPLO_t Uplo_src, CBLAS_DIAG_t Diag, gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);

GSL_FUN int gsl_matrix_complex_long_double_conjtrans_memcpy (gsl_matrix_complex_long_double * dest, const gsl_matrix_complex_long_double * src);

GSL_FUN int gsl_matrix_complex_long_double_equal (const gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);

GSL_FUN int gsl_matrix_complex_long_double_isnull (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_ispos (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_isneg (const gsl_matrix_complex_long_double * m);
GSL_FUN int gsl_matrix_complex_long_double_isnonneg (const gsl_matrix_complex_long_double * m);

GSL_FUN int gsl_matrix_complex_long_double_add (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_sub (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_mul_elements (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_div_elements (gsl_matrix_complex_long_double * a, const gsl_matrix_complex_long_double * b);
GSL_FUN int gsl_matrix_complex_long_double_scale (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);
GSL_FUN int gsl_matrix_complex_long_double_scale_rows (gsl_matrix_complex_long_double * a, const gsl_vector_complex_long_double * x);
GSL_FUN int gsl_matrix_complex_long_double_scale_columns (gsl_matrix_complex_long_double * a, const gsl_vector_complex_long_double * x);
GSL_FUN int gsl_matrix_complex_long_double_add_constant (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);
GSL_FUN int gsl_matrix_complex_long_double_add_diagonal (gsl_matrix_complex_long_double * a, const gsl_complex_long_double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_FUN int gsl_matrix_complex_long_double_get_row(gsl_vector_complex_long_double * v, const gsl_matrix_complex_long_double * m, const size_t i);
GSL_FUN int gsl_matrix_complex_long_double_get_col(gsl_vector_complex_long_double * v, const gsl_matrix_complex_long_double * m, const size_t j);
GSL_FUN int gsl_matrix_complex_long_double_set_row(gsl_matrix_complex_long_double * m, const size_t i, const gsl_vector_complex_long_double * v);
GSL_FUN int gsl_matrix_complex_long_double_set_col(gsl_matrix_complex_long_double * m, const size_t j, const gsl_vector_complex_long_double * v);
/***********************************************************************/

/* inline functions if you are using GCC */

GSL_FUN INLINE_DECL gsl_complex_long_double gsl_matrix_complex_long_double_get(const gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL void gsl_matrix_complex_long_double_set(gsl_matrix_complex_long_double * m, const size_t i, const size_t j, const gsl_complex_long_double x);

GSL_FUN INLINE_DECL gsl_complex_long_double * gsl_matrix_complex_long_double_ptr(gsl_matrix_complex_long_double * m, const size_t i, const size_t j);
GSL_FUN INLINE_DECL const gsl_complex_long_double * gsl_matrix_complex_long_double_const_ptr(const gsl_matrix_complex_long_double * m, const size_t i, const size_t j);

#ifdef HAVE_INLINE

INLINE_FUN
gsl_complex_long_double
gsl_matrix_complex_long_double_get(const gsl_matrix_complex_long_double * m,
                     const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (GSL_RANGE_COND(1))
    {
      gsl_complex_long_double zero = {{0,0}};

      if (i >= m->size1)
        {
          GSL_ERROR_VAL("first index out of range", GSL_EINVAL, zero) ;
        }
      else if (j >= m->size2)
        {
          GSL_ERROR_VAL("second index out of range", GSL_EINVAL, zero) ;
        }
    }
#endif
  return *(gsl_complex_long_double *)(m->data + 2*(i * m->tda + j)) ;
}

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

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

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

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_MATRIX_COMPLEX_LONG_DOUBLE_H__ */


/*
Copyright (c) 2015, Patrick Weltevrede
All rights reserved.

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

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

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

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

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <gsl/gsl_sort.h>
#include "psrsalsa.h"
int main(int argc, char **argv)
{
  int read_log, centered_at_zero, file_column1, file_column2, colspecified, polspecified, filename, truncate, cdf, select;
  long ndata, i, j, k, nrbins, nrbinsy, *distr;
  float *cmap, *distr_float;
  double *data_x, *data_y, min_x_data, max_x_data, min_y_data, max_y_data;
  double min_x, max_x, min_y, max_y, dx, dy, x, y, s, rangex_min, rangex_max, rangey_min, rangey_max, extra_phase, select1, select2;
  int nrbins_specified, dx_specified, dy_specified, output_sigma, output_fraction, nrbins_specifiedy, twoDmode, showGraphics, rangex_set, rangey_set, plotlog, file_column2_defined, xlabelset, linewidth;
  char title[500], *filename_ptr, output_suffix[100], *oname;
  FILE *ofile;
  double min, max;
  psrsalsaApplication application;
  datafile_definition datain;
  pgplot_options_definition pgplot_options;
  pgplot_clear_options(&pgplot_options);
  initApplication(&application, "pdist", "[options] inputfile(s)");
  application.switch_verbose = 1;
  application.switch_debug = 1;
  application.switch_iformat = 1;
  application.switch_formatlist = 1;
  application.switch_device = 1;
  application.switch_cmap = 1;
  application.switch_cmaplist = 1;
  nrbins_specified = 0;
  nrbins_specifiedy = 0;
  dx_specified = 0;
  dy_specified = 0;
  output_sigma = 0;
  output_fraction = 0;
  read_log = 0;
  twoDmode = 0;
  centered_at_zero = 1;
  extra_phase = 0;
  showGraphics = 0;
  xlabelset = 0;
  sprintf(title, "Distribution");
  rangex_set = 0;
  rangey_set = 0;
  file_column1 = 1;
  file_column2 = 2;
  colspecified = 0;
  polspecified = 0;
  plotlog = 0;
  file_column2_defined = 1;
  application.cmap = PPGPLOT_HEAT;
  strcpy(output_suffix, "hist");
  filename = 0;
  truncate = 0;
  cdf = 0;
  select = 0;
  linewidth = 1;
  if(argc < 2) {
    printf("Program to generate or plot a histogram by binning data. Also a cummulative\n");
    printf("distribution can be generated. Usage:\n\n");
    printApplicationHelp(&application);
    printf("Input options:\n");
    printf("-2               Turn on 2D mode: Read in two columns of data, resulting in the\n");
    printf("                 distribution N(x,y) rathern than N(x).\n");
    printf("-col \"c1 c2\"     Specify two column numbers (counting from 1) to be used.\n");
    printf("                 Without the -2 option only one value needs to be specified.\n");
    printf("                 This option implies the input files are ascii files with each\n");
    printf("                 line having an equal number of columns. Lines starting with a #\n");
    printf("                 will be ignored.\n");
    printf("-pol \"p1 p2\"     This option implies that the input file is recognized as a\n");
    printf("                 pulsar format. Polarization p1 (and p2 in 2D mode), counting\n");
    printf("                 from zero, are used (all bins, freqs and subints). The default\n");
    printf("                 default is \"0 1\", or the integrated onpulse pulse energy for\n");
    printf("                 penergy output files in mode 1.\n");
    printf("\nOutput options:\n");
    printf("-ext             Specify suffix, default is '%s'\n", output_suffix);
    printf("-output filename Write output to this file [def=.%s extension].\n", output_suffix);
    printf("-frac            Output fraction of counts per bin rather than counts.\n");
    printf("-sigma           Generate extra column with the sqrt of the nr of counts.\n");
    printf("\nDistribution options:\n");
    printf("-cdf             The cummulative distribution is generated. Use no -dx or -n.\n");
    printf("-dx value        Specify bin width (can also use -n).\n");
    printf("-dy value        Specify bin width used for the second column if -2 is used.\n");
    printf("-log             The base-10 log of the input values is used.\n");
    printf("-n nr            The range of input values is divided in nr bins.\n");
    printf("-nx nr           Same as -n\n");
    printf("-ny nr           Similar to -nx, but now for the second column if -2 is used.\n");
    printf("-rangex \"x1 x2\"  The range of bins produced in output will cover x1..x2, which\n");
    printf("                 should include all input values (see also -trunc). It therefore\n");
    printf("                 allows more bins to be generated than strictly necessary.\n");
    printf("-rangey          As -rangex, but now for second input column.\n");
    printf("-select \"v1 v2\"  Enabling this option will no longer result in a distribution.\n");
    printf("                 Instead all samples within the range of values specified with\n");
    printf("                 v1 and v2 will be outputted as two columns: the sample number\n");
    printf("                 and the value.\n");
    printf("-trunc           Modifies behaviour of -rangex and -rangey. Values outside the\n");
    printf("                 specified range are set to the extremes of the range.\n");
    printf("-zero            By default one of the bins will be centred at zero. This option\n");
    printf("                 results in the edge of a bin to coincides with zero. In both\n");
    printf("                 cases the reported locations of the bins are their centres.\n");
    printf("                 This means that in gnuplot you want to use \"with histeps\".\n");
    printf("-zeroshift off   Put in an extra offset off to where zero would fall with\n");
    printf("                 respect to a bin. -zero is equivalent to -zeroshift 0.5. \n");
    printf("\nPlot options:\n");
    printf("-plot            Plot the distribution rather than writing output to file.\n");
    printf("-plotlog         The log10 of the counts is plotted (implies -plot and bins with\n");
    printf("                 zero counts are set to 1).\n");
    printf("-overplot        Like plot, but multiple input files are overplotted. The ranges\n");
    printf("                 are determined by first input file.\n");
    printf("-title  'title'  Set the title of the plot.\n");
    printf("-xlabel 'label'  Set label on horizontal axis.\n");
    printf("-labels           \"label_ch label_lw label_f box_ch box_lw box_f\"\n");
    printf("                  default is \"%.1f %d %d %.1f %d %d\"\n", pgplot_options.box.label_ch, pgplot_options.box.label_lw, pgplot_options.box.label_f, pgplot_options.box.box_labelsize, pgplot_options.box.box_lw, pgplot_options.box.box_f);
    printf("-lw              Set line width of the histogram.\n");
    printf("-vp              \"left right bottom top\"\n");
    printf("                 Modify the dimensions of the plot. Default is \"%.2f %.2f %.2f %.2f\"\n", pgplot_options.viewport.dxplot, pgplot_options.viewport.xsize, pgplot_options.viewport.dyplot, pgplot_options.viewport.ysize);
    printf("\n");
    printf("Please use the appropriate citation when using results of this software in your publications:\n\n");
    printf("More information about fitting distributions (in the context of pulse energies) can be found in:\n");
    printf(" - Weltevrede et al. 2006, A&A, 458, 269\n\n");
    printCitationInfo();
    terminateApplication(&application);
    return 0;
  }else {
    for(i = 1; i < argc; i++) {
      int index;
      index = i;
      if(processCommandLine(&application, argc, argv, &index)) {
 i = index;
      }else if(strcmp(argv[i], "-2") == 0) {
 twoDmode = 1;
      }else if(strcmp(argv[i], "-plot") == 0) {
 showGraphics = 1;
      }else if(strcmp(argv[i], "-overplot") == 0) {
 showGraphics = 2;
      }else if(strcmp(argv[i], "-plotlog") == 0) {
 plotlog = 1;
 if(showGraphics == 0)
   showGraphics = 1;
      }else if(strcmp(argv[i], "-xlabel") == 0) {
 xlabelset = i+1;
 i++;
      }else if(strcmp(argv[i], "-title") == 0) {
 strcpy(title, argv[i+1]);
 i++;
      }else if(strcmp(argv[i], "-output") == 0) {
 filename = i+1;
 i++;
      }else if(strcmp(argv[i], "-ext") == 0) {
 strcpy(output_suffix, argv[i+1]);
 i++;
      }else if(strcmp(argv[i], "-labels") == 0) {
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%f %d %d %f %d %d", &(pgplot_options.box.label_ch), &(pgplot_options.box.label_lw), &(pgplot_options.box.label_f), &(pgplot_options.box.box_labelsize), &(pgplot_options.box.box_lw), &(pgplot_options.box.box_f), NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-lw") == 0) {
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%d", &linewidth, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-vp") == 0) {
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%f %f %f %f", &(pgplot_options.viewport.dxplot), &(pgplot_options.viewport.xsize), &(pgplot_options.viewport.dyplot), &(pgplot_options.viewport.ysize), NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-col") == 0 || strcmp(argv[i], "-pol") == 0) {
 if(strcmp(argv[i], "-pol") == 0)
   polspecified = 1;
 else
   colspecified = 1;
 int ret;
 ret = parse_command_string(application.verbose_state, argc, argv, i+1, 0, 1, "%d %d", &file_column1, &file_column2, NULL);
 file_column2_defined = 0;
 if(ret == 2) {
   file_column2_defined = 1;
 }else if(ret == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse %s option, need 1 or 2 integer values.\n", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "-nx") == 0) {
 if(dx_specified) {
   printerror(application.verbose_state.debug, "Cannot use -n and -dx option simultaniously.\n");
   return 0;
 }
 nrbins_specified = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%ld", &nrbins, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-ny") == 0) {
 if(dy_specified) {
   printerror(application.verbose_state.debug, "Cannot use -ny and -dy option simultaniously.\n");
   return 0;
 }
 nrbins_specifiedy = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%ld", &nrbinsy, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-dx") == 0) {
 if(nrbins_specified) {
   printerror(application.verbose_state.debug, "Cannot use -n and -dx option simultaniously.\n");
   return 0;
 }
 dx_specified = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf", &dx, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-dy") == 0) {
 if(nrbins_specifiedy) {
   printerror(application.verbose_state.debug, "Cannot use -ny and -dy option simultaniously.\n");
   return 0;
 }
 dy_specified = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf", &dy, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-rangex") == 0) {
 rangex_set = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf %lf", &rangex_min, &rangex_max, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-rangey") == 0) {
 rangey_set = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf %lf", &rangey_min, &rangey_max, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-select") == 0) {
 select = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf %lf", &select1, &select2, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-trunc") == 0) {
 truncate = 1;
      }else if(strcmp(argv[i], "-sigma") == 0) {
 output_sigma = 1;
      }else if(strcmp(argv[i], "-log") == 0) {
 read_log = 1;
      }else if(strcmp(argv[i], "-zero") == 0) {
 centered_at_zero = 0;
      }else if(strcmp(argv[i], "-zeroshift") == 0) {
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%lf", &extra_phase, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-frac") == 0) {
 output_fraction = 1;
      }else if(strcmp(argv[i], "-cdf") == 0) {
 cdf = 1;
      }else {
 if(argv[i][0] == '-') {
   printerror(application.verbose_state.debug, "pdist: Unknown option: %s\n\nRun pdist without command line arguments to show help", argv[i]);
   terminateApplication(&application);
   return 0;
 }else {
   if(applicationAddFilename(i, application.verbose_state) == 0)
     return 0;
 }
      }
    }
  }
  if(applicationFilenameList_checkConsecutive(argv, application.verbose_state) == 0) {
    return 0;
  }
  if(numberInApplicationFilenameList(&application, argv, application.verbose_state) == 0) {
    printerror(application.verbose_state.debug, "ERROR pdist: No files specified");
    return 0;
  }
  if(select) {
    if(twoDmode) {
      printerror(application.verbose_state.debug, "ERROR pdist: The -2 option cannot be used with -select.\n");
      return 0;
    }
    if(cdf) {
      printerror(application.verbose_state.debug, "ERROR pdist: The -cdf option cannot be used with -select.\n");
      return 0;
    }
    if(showGraphics) {
      printerror(application.verbose_state.debug, "ERROR pdist: No plots can be generated when using -select.\n");
      return 0;
    }
    if(output_fraction) {
      printerror(application.verbose_state.debug, "ERROR pdist: The -frac option cannot be used with -select.\n");
      return 0;
    }
    if(output_sigma) {
      printerror(application.verbose_state.debug, "ERROR pdist: The -sigma option cannot be used with -select.\n");
      return 0;
    }
  }
  if(cdf) {
    if(nrbins_specified || dx_specified) {
      printerror(application.verbose_state.debug, "ERROR pdist: For a cdf -n and -dx should not be used.\n");
      return 0;
    }
    if(twoDmode) {
      printerror(application.verbose_state.debug, "ERROR pdist: For a cdf only one input column is expected.\n");
      return 0;
    }
    if(output_sigma) {
      printerror(application.verbose_state.debug, "ERROR pdist: For a cdf -sigma is not supported.\n");
      return 0;
    }
    if(rangex_set || rangey_set || truncate) {
      printerror(application.verbose_state.debug, "ERROR pdist: For a cdf the -rangex and -rangey options are not supported.\n");
      return 0;
    }
  }else {
    if(select == 0) {
      if(nrbins_specified == 0 && dx_specified == 0) {
 printerror(application.verbose_state.debug, "ERROR pdist: Specify resolution with the -n or -dx option.\n");
 return 0;
      }
      if(twoDmode) {
 if(nrbins_specifiedy == 0 && dy_specified == 0) {
 printerror(application.verbose_state.debug, "ERROR pdist: Specify resolution with the -ny or -dy option.\n");
 return 0;
 }
      }
    }
  }
  int initial_iformat, currentfile;
  currentfile = 1;
  initial_iformat = application.iformat;
  while((filename_ptr = getNextFilenameFromList(&application, argv, application.verbose_state)) != NULL) {
    application.iformat = initial_iformat;
    if(application.iformat <= 0 && colspecified == 0) {
      application.iformat = guessPSRData_format(filename_ptr, 1, application.verbose_state);
      if(application.iformat == -2 || application.iformat == -3)
 return 0;
    }
    if(colspecified)
      application.iformat = -1;
    if(polspecified && application.iformat <= 0) {
      printerror(application.verbose_state.debug, "ERROR pdist: Input file cannot be opened. Please check if file %s exists and otherwise specify the correct input format with the -iformat option if the format is supported, but not automatically recognized. Data is not recognized as pulsar data, but -pol was used. Use -col for ascii files.\n", filename_ptr);
      return 0;
    }
    if(application.iformat > 0) {
      verbose_definition verbose;
      cleanVerboseState(&verbose);
      copyVerboseState(application.verbose_state, &verbose);
      if(application.iformat == PSRCHIVE_ASCII_format) {
 if(verbose.debug == 0)
   verbose.verbose = 0;
      }
      i = openPSRData(&datain, filename_ptr, application.iformat, 0, 1, 1, verbose);
      if(i == 0) {
 printerror(application.verbose_state.debug, "ERROR pdist: Error opening data");
 return 0;
      }
      if(polspecified == 0) {
 file_column1 = 0;
 file_column2 = 1;
      }
      if(application.iformat == PSRCHIVE_ASCII_format && datain.gentype == GENTYPE_PENERGY) {
 if(application.verbose_state.verbose)
   printf("The file is a penergy file generated in mode 1.\n");
 if(polspecified == 0) {
   printwarning(application.verbose_state.debug, "WARNING pdist: -pol not specified, default in the integrated on-pulse energy (-pol 2)");
   file_column1 = 2;
 }
      }
      if(application.verbose_state.verbose)
 printf("Loading %ld points", datain.NrSubints*datain.NrFreqChan*datain.NrBins);
      if(twoDmode)
 printf(" times two input polarizations");
      printf("\n");
      data_x = malloc(datain.NrSubints*datain.NrFreqChan*datain.NrBins*sizeof(double));
      data_y = malloc(datain.NrSubints*datain.NrFreqChan*datain.NrBins*sizeof(double));
      if(data_x == NULL || data_y == NULL) {
 printerror(application.verbose_state.debug, "ERROR pdist: Memory allocation error.\n");
 return 0;
      }
      long subintnr, freqnr, binnr;
      long double total_x, total_y;
      ndata = 0;
      total_x = 0;
      total_y = 0;
      min_x_data = max_x_data = 0;
      for(subintnr = 0; subintnr < datain.NrSubints; subintnr++) {
 for(freqnr = 0; freqnr < datain.NrFreqChan; freqnr++) {
   for(binnr = 0; binnr < datain.NrBins; binnr++) {
     float dummy_float;
     if(readPulsePSRData(&datain, subintnr, file_column1, freqnr, binnr, 1, &dummy_float, application.verbose_state) == 0) {
       printerror(application.verbose_state.debug, "ERROR pdist: Read error, shouldn't happen.\n");
       return 0;
     }
     data_x[ndata] = dummy_float;
     if(read_log) {
       if(data_x[ndata] <= 0) {
  printerror(application.verbose_state.debug, "ERROR pdist: Cannot take logarithm of a value <= 0.\n");
  return 0;
       }
       data_x[ndata] = log10(data_x[ndata]);
     }
     if(data_x[ndata] > max_x_data || ndata == 0) {
       max_x_data = data_x[ndata];
     }
     if(data_x[ndata] < min_x_data || ndata == 0) {
       min_x_data = data_x[ndata];
     }
     total_x += data_x[ndata];
     if(twoDmode) {
       if(readPulsePSRData(&datain, subintnr, file_column2, freqnr, binnr, 1, &dummy_float, application.verbose_state) == 0) {
  printerror(application.verbose_state.debug, "ERROR pdist: Read error, shouldn't happen.\n");
  return 0;
       }
       data_y[ndata] = dummy_float;
       if(read_log) {
  if(data_y[ndata] <= 0) {
    printerror(application.verbose_state.debug, "ERROR pdist: Cannot take logarithm of a value <= 0.\n");
    return 0;
  }
  data_y[ndata] = log10(data_y[ndata]);
       }
       if(ndata == 0) {
  max_y_data = data_y[ndata];
  min_y_data = data_y[ndata];
       }
       if(data_y[ndata] > max_y_data) {
  max_y_data = data_y[ndata];
       }
       if(data_y[ndata] < min_y_data) {
  min_y_data = data_y[ndata];
       }
       total_y += data_y[ndata];
     }
     ndata++;
   }
 }
      }
      if(application.verbose_state.verbose) {
 printf("xrange = %e ... %e\n", min_x_data, max_x_data);
 printf("average = %Le\n", total_x/(long double)ndata);
 if(twoDmode) {
   printf("yrange = %e ... %e\n", min_y_data, max_y_data);
   printf("average = %Le\n", total_y/(long double)ndata);
 }
      }
      closePSRData(&datain, 0, application.verbose_state);
    }else {
      int skiplines = 0;
      if(twoDmode) {
 if(application.verbose_state.verbose)
   fprintf(stdout, "Loading x values from ascii file\n");
 if(read_ascii_column_double(filename_ptr, skiplines, '#', -1, 1, &ndata, file_column1, 1.0, read_log, &data_x, &min_x_data, &max_x_data, NULL, application.verbose_state, 1) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: cannot load file.\n");
   if(colspecified) {
     printwarning(application.verbose_state.debug, "WARNING pdist: Using the -col option implies the input file is a simple ascii file. For penergy output (in mode 1), or an other recognized pulsar format, use the -pol option instead.\n");
   }
   return 0;
 }
 if(application.verbose_state.verbose)
   fprintf(stdout, "Loading y values from ascii file\n");
 if(file_column2_defined == 0) {
   printerror(application.verbose_state.debug, "In 2D mode, two input columns should be specified with the -col option.\n");
   return 0;
 }
 if(read_ascii_column_double(filename_ptr, skiplines, '#', -1, 1, &ndata, file_column2, 1.0, read_log, &data_y, &min_y_data, &max_y_data, NULL, application.verbose_state, 1) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: cannot load file.\n");
   if(colspecified) {
     printwarning(application.verbose_state.debug, "WARNING pdist: Using the -col option implies the input file is a simple ascii file. For penergy output (in mode 1), or an other recognized pulsar format, use the -pol option instead.\n");
   }
   return 0;
 }
      }else {
 if(application.verbose_state.verbose)
   fprintf(stdout, "Loading values from ascii file\n");
 if(read_ascii_column_double(filename_ptr, skiplines, '#', -1, 1, &ndata, file_column1, 1.0, read_log, &data_x, &min_x_data, &max_x_data, NULL, application.verbose_state, 1) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: cannot load file.\n");
   if(colspecified) {
     printwarning(application.verbose_state.debug, "WARNING pdist: Using the -col option implies the input file is a simple ascii file. For penergy output (in mode 1), or an other recognized pulsar format, use the -pol option instead.\n");
   }
   return 0;
 }
 data_y = malloc(ndata*sizeof(double));
 if(data_y == NULL) {
   printerror(application.verbose_state.debug, "ERROR pdist: Memory allocation error.\n");
   return 0;
 }
      }
    }
    if(cdf == 0 && select == 0) {
      switch(set_binning_histogram(min_x_data, max_x_data, rangex_set, rangex_min, rangex_max, nrbins_specified, nrbins, centered_at_zero, extra_phase, &min_x, &max_x, &dx, application.verbose_state)) {
      case 0: break;
      case 1:
      case 2: return 0;
      default: {
 printerror(application.verbose_state.debug, "ERROR pdist: Unknown return value for call to set_binning_histogram.\n");
 return 0;
      }
      }
      if(rangex_set) {
 if(min_x > min_x_data || max_x < max_x_data) {
   if(truncate == 0) {
     printerror(application.verbose_state.debug, "ERROR pdist: Values are outside specified -rangex option. You may want to use -trunc?\n");
     return 0;
   }
 }
      }
      if(twoDmode) {
 switch(set_binning_histogram(min_y_data, max_y_data, rangey_set, rangey_min, rangey_max, nrbins_specifiedy, nrbinsy, centered_at_zero, extra_phase, &min_y, &max_y, &dy, application.verbose_state)) {
 case 0: break;
 case 1:
 case 2: return 0;
 default: {
   printerror(application.verbose_state.debug, "ERROR pdist: Unknown return value for call to set_binning_histogram.\n");
   return 0;
 }
 }
 if(application.verbose_state.verbose) {
   fprintf(stdout, "Going to use binsize dx=%e and dy=%e.\n", dx, dy);
 }
      }
      if(rangey_set) {
 if(min_y > min_y_data || max_y < max_y_data) {
   if(truncate == 0) {
     printerror(application.verbose_state.debug, "ERROR pdist: Values are outside specified -rangey option. You may want to use -trunc?\n");
     return 0;
   }
 }
      }
    }
    if(cdf == 0) {
      if(truncate) {
 if(rangex_set) {
   for(i = 0; i < ndata; i++) {
     if(data_x[i] < min_x)
       data_x[i] = min_x;
     if(data_x[i] > max_x)
       data_x[i] = max_x;
   }
 }
 if(rangey_set) {
   for(i = 0; i < ndata; i++) {
     if(data_y[i] < min_y)
       data_y[i] = min_y;
     if(data_y[i] > max_y)
       data_y[i] = max_y;
   }
 }
      }
    }
    if(cdf == 0 && select == 0)
      nrbins = calculate_bin_number(max_x, dx, min_x, centered_at_zero, extra_phase) + 1;
    else
      nrbins = ndata;
    if(select == 0)
      fprintf(stdout, "Distribution will have %ld bins.\n", nrbins);
    if(twoDmode) {
      nrbinsy = calculate_bin_number(max_y, dy, min_y, centered_at_zero, extra_phase)+ 1;
      fprintf(stdout, "Distribution will have %ld y-bins.\n", nrbinsy);
    }else {
      nrbinsy = 1;
    }
    distr = (long *)malloc(nrbins*nrbinsy*sizeof(long));
    if(distr == NULL) {
      printerror(application.verbose_state.debug, "ERROR pdist: Cannot allocate memory.\n");
      return 0;
    }
    for(i = 0; i < nrbins*nrbinsy; i++)
      distr[i] = 0;
    if(showGraphics) {
      pgplot_options.box.drawtitle = 1;
      strcpy(pgplot_options.box.title, title);
      if(xlabelset) {
 strcpy(pgplot_options.box.xlabel, argv[xlabelset]);
      }else {
 if(read_log)
   strcpy(pgplot_options.box.xlabel, "log X");
 else
   strcpy(pgplot_options.box.xlabel, "X");
      }
      if(twoDmode) {
 if(read_log)
   strcpy(pgplot_options.box.ylabel, "log Y");
 else
   strcpy(pgplot_options.box.ylabel, "Y");
      }else {
 if(plotlog)
   strcpy(pgplot_options.box.ylabel, "log N");
 else
   strcpy(pgplot_options.box.ylabel, "N");
      }
      strcpy(pgplot_options.viewport.plotDevice, application.pgplotdevice);
      if(showGraphics == 2) {
 pgplot_options.viewport.dontclose = 1;
      }
      if(currentfile > 1 && showGraphics == 2) {
 pgplot_options.viewport.noclear = 1;
 pgplot_options.viewport.dontopen = 1;
 pgplot_options.box.drawbox = 0;
 pgplot_options.box.drawtitle = 0;
 pgplot_options.box.drawlabels = 0;
      }
    }else {
      if(filename != 0) {
 oname = (char *) calloc(strlen(argv[filename])+1, 1);
      }else {
 oname = (char *) calloc(strlen(filename_ptr)+strlen(output_suffix)+2, 1);
      }
      if(oname == NULL) {
 printerror(application.verbose_state.debug, "ERROR pdist: Memory allocation error.\n");
 return 0;
      }
      if(filename != 0) {
 strcpy(oname, argv[filename]);
      }else {
 sprintf(oname,"%s.%s", filename_ptr, output_suffix);
      }
      printf("Output Ascii to %s\n",oname);
      ofile = fopen(oname,"w+");
      if(ofile == NULL) {
 printerror(application.verbose_state.debug, "ERROR pdist: Cannot open '%s'", oname);
 perror("");
 return 0;
      }
    }
    if(twoDmode) {
      for(i = 0; i < ndata; i++) {
 j = calculate_bin_number(data_x[i], dx, min_x, centered_at_zero, extra_phase);
 k = calculate_bin_number(data_y[i], dy, min_y, centered_at_zero, extra_phase);
 if(j < 0 || j >= nrbins) {
   printerror(application.verbose_state.debug, "BUG!\n");
   return 0;
 }
 if(k < 0 || k >= nrbinsy) {
   printerror(application.verbose_state.debug, "BUG!\n");
   return 0;
 }
 distr[k*nrbins+j] += 1;
      }
      for(i = 0; i < nrbins; i++) {
 for(j = 0; j < nrbinsy; j++) {
   x = calculate_bin_location(i, dx, min_x, centered_at_zero, extra_phase);
   y = calculate_bin_location(j, dy, min_y, centered_at_zero, extra_phase);
   if(!showGraphics) {
       fprintf(ofile, "%e %e", x, y);
     if(!output_fraction)
       fprintf(ofile, " %ld", distr[j*nrbins+i]);
     else
       fprintf(ofile, " %e", distr[j*nrbins+i]/(double)ndata);
     if(output_sigma) {
       if(distr[j*nrbins+i] == 0)
  s = 1;
       else
  s = sqrt(distr[j*nrbins+i]);
       if(output_fraction)
  s /= (double)ndata;
  fprintf(ofile, " %e", s);
     }
   }
   if(!showGraphics) {
     fprintf(ofile, "\n");
   }
 }
      }
      if(showGraphics) {
 cmap = (float *)malloc(nrbins*nrbinsy*sizeof(float));
 if(cmap == NULL) {
   printerror(application.verbose_state.debug, "Cannot allocate memory.\n");
   return 0;
 }
 if(plotlog) {
   if(distr[0] > 0) {
     min = log10(distr[0]);
     max = log10(distr[0]);
   }else {
     min = max = 0;
   }
 }else {
   min = distr[0];
   max = distr[0];
 }
 for(i = 0; i < nrbins; i++) {
   for(j = 0; j <nrbinsy; j++) {
     if(plotlog) {
       if(distr[i*nrbinsy+j] > 0)
  cmap[i*nrbinsy+j] = log10(distr[i*nrbinsy+j]);
       else
  cmap[i*nrbinsy+j] = 0;
     }
     else
       cmap[i*nrbinsy+j] = distr[i*nrbinsy+j];
     if(cmap[i*nrbinsy+j] > max)
       max = cmap[i*nrbinsy+j];
     if(cmap[i*nrbinsy+j] < min)
       min = cmap[i*nrbinsy+j];
   }
 }
 printf("Count range: %f to %f\n", min, max);
 int showwedge = 0;
 if(pgplotMap(&pgplot_options, cmap, nrbins, nrbinsy,
       calculate_bin_location(0, dx, min_x, centered_at_zero, extra_phase),
       calculate_bin_location(0, dx, max_x, centered_at_zero, extra_phase),
       calculate_bin_location(0, dx, min_x, centered_at_zero, extra_phase)-0.5*dx,
       calculate_bin_location(0, dx, max_x, centered_at_zero, extra_phase)+0.5*dx,
       calculate_bin_location(0, dy, min_y, centered_at_zero, extra_phase),
       calculate_bin_location(0, dy, max_y, centered_at_zero, extra_phase),
       calculate_bin_location(0, dy, min_y, centered_at_zero, extra_phase)-0.5*dy,
       calculate_bin_location(0, dy, max_y, centered_at_zero, extra_phase)+0.5*dy,
       application.cmap, 0, 0, 0, NULL, 0, 0, 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, showwedge, 0, 0, application.verbose_state) == 0) {
   printerror(application.verbose_state.debug, "ERROR pdist: Plotting failed.\n");
   return 0;
 }
 free(cmap);
      }
    }else {
      if(select) {
 nrbins = 0;
 for(i = 0; i < ndata; i++) {
   if(data_x[i] >= select1 && data_x[i] <= select2) {
     nrbins++;
   }
 }
 j = 0;
 for(i = 0; i < ndata; i++) {
   if(data_x[i] >= select1 && data_x[i] <= select2) {
     distr[j] = i;
     data_y[j] = data_x[i];
     j++;
   }
 }
      }else {
 if(cdf == 0) {
   for(i = 0; i < ndata; i++) {
     j = calculate_bin_number(data_x[i], dx, min_x, centered_at_zero, extra_phase);
     if(j < 0 || j >= nrbins) {
       printerror(application.verbose_state.debug, "BUG! bin number %ld outside range.\n", j);
       exit(0);
     }
     distr[j] += 1;
   }
 }else {
   gsl_sort(data_x, 1, ndata);
   for(i = 0; i < ndata; i++) {
     data_y[i] = (i+1)/(double)(ndata);
   }
 }
      }
      if(!showGraphics) {
 for(i = 0; i < nrbins; i++) {
   x = i*dx;
     if(cdf == 0) {
       if(select == 0) {
  fprintf(ofile, "%e", calculate_bin_location(i, dx, min_x, centered_at_zero, extra_phase));
       }else {
  fprintf(ofile, "%ld", distr[i]);
       }
     }else {
       fprintf(ofile, "%e", data_x[i]);
     }
   if(!output_fraction) {
       if(cdf == 0) {
  if(select == 0) {
    fprintf(ofile, " %ld", distr[i]);
  }else {
    fprintf(ofile, " %e", data_y[i]);
  }
       }else {
  fprintf(ofile, " %e", data_y[i]);
       }
   }else {
       if(cdf == 0) {
  fprintf(ofile, " %e", distr[i]/(double)ndata);
       }else {
  fprintf(ofile, " %e", data_y[i]);
       }
   }
   if(output_sigma) {
     if(distr[i] == 0)
       s = 1;
     else
       s = sqrt(distr[i]);
     if(output_fraction)
       s /= (double)ndata;
     fprintf(ofile, " %e", s);
   }
   fprintf(ofile, "\n");
 }
      }else {
 float *distr_x_float;
 distr_float = malloc(nrbins*sizeof(float));
 if(distr_float == NULL) {
   printerror(application.verbose_state.debug, "ERROR pdist: Cannot allocate memory\n");
   return 0;
 }
 if(cdf == 0) {
   for(i = 0; i < nrbins; i++) {
     distr_float[i] = distr[i];
     if(output_fraction)
       distr_float[i] /= (double)ndata;
     if(plotlog) {
       if(distr[i] > 0) {
  distr_float[i] = log10(distr_float[i]);
       }else {
  if(output_fraction) {
    distr_float[i] = log10(1.0/(float)ndata);
  }else {
    distr_float[i] = 0;
  }
       }
     }
   }
 }else {
   distr_x_float = malloc(nrbins*sizeof(float));
   if(distr_x_float == NULL) {
     printerror(application.verbose_state.debug, "ERROR pdist: Cannot allocate memory\n");
     return 0;
   }
   for(i = 0; i < nrbins; i++) {
     distr_float[i] = data_y[i];
     distr_x_float[i] = data_x[i];
   }
 }
 int forceMinZero, dontsetranges, colour;
 forceMinZero = 1;
 if(plotlog)
   forceMinZero = 0;
 dontsetranges = 0;
 colour = 1;
 if(showGraphics == 2) {
   if(currentfile > 1)
     dontsetranges = 1;
   colour = currentfile;
 }
 if(cdf == 0) {
   if(pgplotGraph1(&pgplot_options, distr_float, NULL, NULL, nrbins,
     calculate_bin_location(0, dx, min_x, centered_at_zero, extra_phase),
     calculate_bin_location(nrbins-1, dx, min_x, centered_at_zero, extra_phase),
     dontsetranges,
     calculate_bin_location(0, dx, min_x, centered_at_zero, extra_phase) - dx,
     calculate_bin_location(nrbins-1, dx, min_x, centered_at_zero, extra_phase) + dx,
     0, 0, forceMinZero, 1, 0, linewidth, 0, colour, 1, NULL, -1, application.verbose_state) == 0) {
     printerror(application.verbose_state.debug, "ERROR pdist: Cannot plot graph\n");
     return 0;
   }
 }else {
   if(pgplotGraph1(&pgplot_options, distr_float, distr_x_float, NULL, nrbins,
     0,
     0,
     dontsetranges,
     0,
     0,
     0, 0, forceMinZero, 1*0, 0, linewidth, 0, colour, 1, NULL, -1, application.verbose_state) == 0) {
     printerror(application.verbose_state.debug, "ERROR pdist: Cannot plot graph\n");
     return 0;
   }
   free(distr_x_float);
 }
 free(distr_float);
      }
    }
    free(data_x);
    free(data_y);
    free(distr);
    if(showGraphics == 0) {
      fclose(ofile);
      free(oname);
    }
    if(showGraphics == 1) {
      if(currentfile != numberInApplicationFilenameList(&application, argv, application.verbose_state)) {
 i = pgplot_device_type(application.pgplotdevice, application.verbose_state);
 if(i < 3 || i > 10) {
   printf("Press a key to continue\n");
   fflush(stdout);
   pgetch();
 }
      }
    }
    currentfile += 1;
  }
  if(showGraphics == 2) {
    ppgend();
  }
  terminateApplication(&application);
  return 0;
}


/* histogram/ntuple.h
 *
 * Copyright (C) 2000 Simone Piccardi
 *
 * 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.
 *
 */

/* Jan/2001 Modified by Brian Gough. Minor changes for GSL */

#ifndef __GSL_NTUPLE_H__
#define __GSL_NTUPLE_H__

#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_histogram.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 {
    FILE * file;
    void * ntuple_data;
    size_t size;
} gsl_ntuple;

typedef struct {
  int (* function) (void * ntuple_data, void * params);
  void * params;
} gsl_ntuple_select_fn;

typedef struct {
  double (* function) (void * ntuple_data, void * params);
  void * params;
} gsl_ntuple_value_fn;

gsl_ntuple *
gsl_ntuple_open (char * filename, void * ntuple_data, size_t size);

gsl_ntuple *
gsl_ntuple_create (char * filename, void * ntuple_data, size_t size);

int gsl_ntuple_write (gsl_ntuple * ntuple);
int gsl_ntuple_read (gsl_ntuple * ntuple);

int gsl_ntuple_bookdata (gsl_ntuple * ntuple);  /* synonym for write */

int gsl_ntuple_project (gsl_histogram * h, gsl_ntuple * ntuple,
                        gsl_ntuple_value_fn *value_func,
                        gsl_ntuple_select_fn *select_func);

int gsl_ntuple_close (gsl_ntuple * ntuple);

__END_DECLS

#endif /* __GSL_NTUPLE_H__ */


#ifndef ARRUS_CORE_DEVICES_TXRXPARAMETERS_H
#define ARRUS_CORE_DEVICES_TXRXPARAMETERS_H

#include <gsl/gsl>
#include <utility>
#include <ostream>

#include "arrus/core/api/common/Interval.h"
#include "arrus/core/api/common/Tuple.h"
#include "arrus/core/api/common/types.h"
#include "arrus/common/format.h"
#include "arrus/core/common/collections.h"
#include "arrus/core/api/ops/us4r/Pulse.h"

namespace arrus::devices {

class TxRxParameters {
public:
    static const TxRxParameters US4OEM_NOP;

    static TxRxParameters createRxNOPCopy(const TxRxParameters& op) {
        return TxRxParameters(
            op.txAperture,
            op.txDelays,
            op.txPulse,
            BitMask(op.rxAperture.size(), false),
            op.rxSampleRange,
            op.rxDecimationFactor,
            op.pri,
            op.rxPadding
        );
    }

    /**
     *
     * ** tx aperture, tx delays and rx aperture should have the same size
     * (tx delays is NOT limited to the tx aperture active elements -
     * the whole array must be provided).**
     *
     * @param txAperture
     * @param txDelays
     * @param txPulse
     * @param rxAperture
     * @param rxSampleRange [start, end) range of samples to acquire, starts from 0
     * @param rxDecimationFactor
     * @param pri
     * @param rxPadding how many 0-channels padd from the left and right
     */
    TxRxParameters(std::vector<bool> txAperture,
                   std::vector<float> txDelays,
                   const ops::us4r::Pulse &txPulse,
                   std::vector<bool> rxAperture,
                   Interval<uint32> rxSampleRange,
                   uint32 rxDecimationFactor, float pri,
                   Tuple<ChannelIdx> rxPadding = {0, 0})
        : txAperture(std::move(txAperture)), txDelays(std::move(txDelays)),
          txPulse(txPulse),
          rxAperture(std::move(rxAperture)), rxSampleRange(std::move(rxSampleRange)),
          rxDecimationFactor(rxDecimationFactor), pri(pri),
          rxPadding(std::move(rxPadding)){}

    [[nodiscard]] const std::vector<bool> &getTxAperture() const {
        return txAperture;
    }

    [[nodiscard]] const std::vector<float> &getTxDelays() const {
        return txDelays;
    }

    [[nodiscard]] const ops::us4r::Pulse &getTxPulse() const {
        return txPulse;
    }

    [[nodiscard]] const std::vector<bool> &getRxAperture() const {
        return rxAperture;
    }

    [[nodiscard]] const Interval<uint32> &getRxSampleRange() const {
        return rxSampleRange;
    }

    [[nodiscard]] uint32 getNumberOfSamples() const {
        return rxSampleRange.end() - rxSampleRange.start();
    }

    [[nodiscard]] int32 getRxDecimationFactor() const {
        return rxDecimationFactor;
    }

    [[nodiscard]] float getPri() const {
        return pri;
    }

    [[nodiscard]] const Tuple<ChannelIdx> &getRxPadding() const {
        return rxPadding;
    }

    [[nodiscard]] bool isNOP() const  {
        auto atLeastOneTxActive = ::arrus::reduce(
            std::begin(txAperture),
            std::end(txAperture),
            false, [](auto a, auto b) {return a | b;});
        auto atLeastOneRxActive = ::arrus::reduce(
            std::begin(rxAperture),
            std::end(rxAperture),
            false, [](auto a, auto b) {return a | b;});
        return !atLeastOneTxActive && !atLeastOneRxActive;
    }

    [[nodiscard]] bool isRxNOP() const {
        auto atLeastOneRxActive = ::arrus::reduce(
            std::begin(rxAperture),
            std::end(rxAperture),
            false, [](auto a, auto b) {return a | b;});
        return !atLeastOneRxActive;
    }

    friend std::ostream &
    operator<<(std::ostream &os, const TxRxParameters &parameters) {
        os << "Tx/Rx: ";
        os << "TX: ";
        os << "aperture: " << ::arrus::toString(parameters.getTxAperture())
           << ", delays: " << ::arrus::toString(parameters.getTxDelays())
           << ", center frequency: " << parameters.getTxPulse().getCenterFrequency()
           << ", n. periods: " << parameters.getTxPulse().getNPeriods()
           << ", inverse: " << parameters.getTxPulse().isInverse();
        os << "; RX: ";
        os << "aperture: " << ::arrus::toString(parameters.getRxAperture());
        os << "sample range: " << parameters.getRxSampleRange().start() << ", "
           << parameters.getRxSampleRange().end();
        os << ", fs divider: " << parameters.getRxDecimationFactor();
        os << std::endl;
        return os;
    }

    bool operator==(const TxRxParameters &rhs) const {
        return txAperture == rhs.txAperture &&
               txDelays == rhs.txDelays &&
               txPulse == rhs.txPulse &&
               rxAperture == rhs.rxAperture &&
               rxSampleRange == rhs.rxSampleRange &&
               rxDecimationFactor == rhs.rxDecimationFactor &&
               pri == rhs.pri;
    }

    bool operator!=(const TxRxParameters &rhs) const {
        return !(rhs == *this);
    }
private:
    ::std::vector<bool> txAperture;
    ::std::vector<float> txDelays;
    ::arrus::ops::us4r::Pulse txPulse;
    ::std::vector<bool> rxAperture;
    // TODO change to a simple pair
    Interval<uint32> rxSampleRange;
    int32 rxDecimationFactor;
    float pri;
    Tuple<ChannelIdx> rxPadding;
};

using TxRxParamsSequence = std::vector<TxRxParameters>;

/**
 * Returns the number of actual ops, that is, a the number of ops excluding RxNOPs.
 */
uint16 getNumberOfNoRxNOPs(const TxRxParamsSequence &seq);

}

#endif //ARRUS_CORE_DEVICES_TXRXPARAMETERS_H


/* Copyright 2013 Perttu Luukko

 * This file is part of libeemd.

 * libeemd 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.

 * libeemd 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 libeemd.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _EEMD_H_
#define _EEMD_H_

#ifndef EEMD_DEBUG
#define EEMD_DEBUG 0
#endif

#if EEMD_DEBUG == 0
#ifndef NDEBUG
#define NDEBUG
#endif
#endif

#include <assert.h>
#include <limits.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <gsl/gsl_statistics_double.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_poly.h>

#ifdef _OPENMP
#include <omp.h>
#endif

// Possible error codes returned by functions eemd, ceemdan and
// emd_evaluate_spline
typedef enum {
	EMD_SUCCESS = 0,
	// Errors from invalid parameters
	EMD_INVALID_ENSEMBLE_SIZE = 1,
	EMD_INVALID_NOISE_STRENGTH = 2,
	EMD_NOISE_ADDED_TO_EMD = 3,
	EMD_NO_NOISE_ADDED_TO_EEMD = 4,
	EMD_NO_CONVERGENCE_POSSIBLE = 5,
	EMD_NOT_ENOUGH_POINTS_FOR_SPLINE = 6,
	EMD_INVALID_SPLINE_POINTS = 7,
	// Other errors
	EMD_GSL_ERROR = 8
} libeemd_error_code;

// Helper functions to print an error message if an error occured
void emd_report_if_error(libeemd_error_code err);
void emd_report_to_file_if_error(FILE* file, libeemd_error_code err);

// Main EEMD decomposition routine as described in:
//   Z. Wu and N. Huang,
//   Ensemble Empirical Mode Decomposition: A Noise-Assisted Data Analysis
//   Method, Advances in Adaptive Data Analysis,
//   Vol. 1, No. 1 (2009) 1–41
//
// Parameters 'input' and 'N' denote the input data and its length,
// respectively. Output from the routine is written to array 'output', which
// needs to be able to store at least N*M doubles, where M is the number of
// Intrinsic Mode Functions (IMFs) to compute. If M is set to zero, a value of
// M = emd_num_imfs(N) will be used, which corresponds to a maximal number of
// IMFs. Note that the final residual is also counted as an IMF in this
// respect, so you most likely want at least num_imfs=2. The following
// parameters are the ensemble size and the relative noise standard deviation,
// respectively. These are followed by the parameters for the stopping
// criterion. The stopping parameter can be defined by a S-number (see the
// article for details) or a fixed number of siftings. If both are specified,
// the sifting ends when either criterion is fulfilled. The final parameter is
// the seed given to the random number generator. A value of zero denotes a
// RNG-specific default value.
libeemd_error_code eemd(double const* restrict input, size_t N,
		double* restrict output, size_t M,
		unsigned int ensemble_size, double noise_strength, unsigned int
		S_number, unsigned int num_siftings, unsigned long int rng_seed);

// A complete variant of EEMD as described in:
//   M. Torres et al,
//   A Complete Ensemble Empirical Mode Decomposition with Adaptive Noise
//   IEEE Int. Conf. on Acoust., Speech and Signal Proc. ICASSP-11,
//   (2011) 4144-4147
//
// Parameters are identical to routine eemd
libeemd_error_code ceemdan(double const* restrict input, size_t N,
		double* restrict output, size_t M,
		unsigned int ensemble_size, double noise_strength, unsigned int
		S_number, unsigned int num_siftings, unsigned long int rng_seed);

// A method for finding the local minima and maxima from input data specified
// with parameters x and N. The memory for storing the coordinates of the
// extrema and their number are passed as the rest of the parameters. The
// arrays for the coordinates must be at least size N. The method also counts
// the number of zero crossings in the data, and saves the results into the
// pointer given as num_zero_crossings_ptr.
void emd_find_extrema(double const* restrict x, size_t N,
		double* restrict maxx, double* restrict maxy, size_t* num_max_ptr,
		double* restrict minx, double* restrict miny, size_t* num_min_ptr,
		size_t* num_zero_crossings_ptr);

// Return the number of IMFs that can be extracted from input data of length N,
// including the final residual.
size_t emd_num_imfs(size_t N);

// This routine evaluates a cubic spline with nodes defined by the arrays x and
// y, each of length N. The spline is evaluated using the not-a-node end point
// conditions (same as Matlab). The y values of the spline curve will be
// evaluated at integer points from 0 to x[N-1], and these y values will be
// written to the array spline_y. The endpoint x[N-1] is assumed to be an
// integer, and the x values are assumed to be in ascending order, with x[0]
// equal to 0. The workspace required is 5*N-10 doubles, except that N==2
// requires no extra memory. For N<=3 the routine falls back to polynomial
// interpolation, same as Matlab.
//
// This routine is mainly exported so that it can be tested separately to
// produce identical results to the Matlab routine 'spline'.
libeemd_error_code emd_evaluate_spline(double const* restrict x, double const* restrict y,
		size_t N, double* restrict spline_y, double* spline_workspace);

#endif // _EEMD_H_


#ifndef COMMON_HEADER_H
#define COMMON_HEADER_H
//Include Standard Headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
//Math Libraries

//#include <math.h>
#include <limits.h>
//#include <gsl/gsl_sf_bessel.h>
//RNG Libraries:
#include <linux/random.h>

//POSIX libraries:
#include <unistd.h>
#include <pthread.h>

//Ncurses
//#include <ncurses.h>
#endif


#include <qdm.h>

#include <gsl/gsl_math.h>
#include <gsl/gsl_randist.h>
#include <hdf5.h>
#include <hdf5_hl.h>

static
void
qdm_mcmc_workspace_init(
    qdm_mcmc *mcmc
)
{
  mcmc->w.xi      = gsl_vector_calloc(mcmc->p.xi->size);
  mcmc->w.xi_acc  = gsl_vector_calloc(mcmc->p.xi->size);
  mcmc->w.xi_p    = gsl_vector_calloc(mcmc->p.xi->size);
  mcmc->w.xi_tune = gsl_vector_calloc(mcmc->p.xi->size);

  gsl_vector_memcpy(mcmc->w.xi,   mcmc->p.xi);
  gsl_vector_memcpy(mcmc->w.xi_p, mcmc->p.xi);

  gsl_vector_set_all(mcmc->w.xi_tune, mcmc->p.xi_tune_sd);

  mcmc->w.ll   = gsl_vector_calloc(mcmc->p.ll->size);
  mcmc->w.ll_p = gsl_vector_calloc(mcmc->p.ll->size);

  gsl_vector_memcpy(mcmc->w.ll,   mcmc->p.ll);
  gsl_vector_memcpy(mcmc->w.ll_p, mcmc->p.ll);

  mcmc->w.tau   = gsl_vector_calloc(mcmc->p.tau->size);
  mcmc->w.tau_p = gsl_vector_calloc(mcmc->p.tau->size);

  gsl_vector_memcpy(mcmc->w.tau,   mcmc->p.tau);
  gsl_vector_memcpy(mcmc->w.tau_p, mcmc->p.tau);

  mcmc->w.theta        = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);
  mcmc->w.theta_acc    = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);
  mcmc->w.theta_p      = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);
  mcmc->w.theta_star   = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);
  mcmc->w.theta_star_p = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);
  mcmc->w.theta_tune   = gsl_matrix_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2);

  gsl_matrix_memcpy(mcmc->w.theta,      mcmc->p.theta);
  gsl_matrix_memcpy(mcmc->w.theta_star, mcmc->p.theta);

  gsl_matrix_set_all(mcmc->w.theta_tune, mcmc->p.theta_tune_sd);
}

static
void
qdm_mcmc_workspace_fini(
    qdm_mcmc *mcmc
)
{
  gsl_vector_free(mcmc->w.xi);
  gsl_vector_free(mcmc->w.xi_acc);
  gsl_vector_free(mcmc->w.xi_p);
  gsl_vector_free(mcmc->w.xi_tune);

  gsl_vector_free(mcmc->w.ll);
  gsl_vector_free(mcmc->w.ll_p);

  gsl_vector_free(mcmc->w.tau);
  gsl_vector_free(mcmc->w.tau_p);

  gsl_matrix_free(mcmc->w.theta);
  gsl_matrix_free(mcmc->w.theta_acc);
  gsl_matrix_free(mcmc->w.theta_p);
  gsl_matrix_free(mcmc->w.theta_star);
  gsl_matrix_free(mcmc->w.theta_star_p);
  gsl_matrix_free(mcmc->w.theta_tune);

  mcmc->w.xi      = NULL;
  mcmc->w.xi_acc  = NULL;
  mcmc->w.xi_p    = NULL;
  mcmc->w.xi_tune = NULL;

  mcmc->w.ll   = NULL;
  mcmc->w.ll_p = NULL;

  mcmc->w.tau   = NULL;
  mcmc->w.tau_p = NULL;

  mcmc->w.theta        = NULL;
  mcmc->w.theta_acc    = NULL;
  mcmc->w.theta_p      = NULL;
  mcmc->w.theta_star   = NULL;
  mcmc->w.theta_star_p = NULL;
  mcmc->w.theta_tune   = NULL;
}

static
void
qdm_mcmc_results_init(
    qdm_mcmc *mcmc
)
{
  mcmc->r.s = mcmc->p.iter / mcmc->p.thin;

  mcmc->r.theta      = qdm_ijk_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2, mcmc->r.s);
  mcmc->r.theta_star = qdm_ijk_calloc(mcmc->p.theta->size1, mcmc->p.theta->size2, mcmc->r.s);

  mcmc->r.ll  = qdm_ijk_calloc(1, mcmc->p.ll->size, mcmc->r.s);
  mcmc->r.tau = qdm_ijk_calloc(1, mcmc->p.tau->size, mcmc->r.s);

  mcmc->r.xi = qdm_ijk_calloc(1, mcmc->p.xi->size, mcmc->r.s);
}

static
void
qdm_mcmc_results_fini(
    qdm_mcmc *mcmc
)
{
  qdm_ijk_free(mcmc->r.theta);
  qdm_ijk_free(mcmc->r.theta_star);

  qdm_ijk_free(mcmc->r.ll);
  qdm_ijk_free(mcmc->r.tau);

  qdm_ijk_free(mcmc->r.xi);

  mcmc->r.theta      = NULL;
  mcmc->r.theta_star = NULL;

  mcmc->r.ll  = NULL;
  mcmc->r.tau = NULL;

  mcmc->r.xi = NULL;
}

qdm_mcmc *
qdm_mcmc_alloc(
    qdm_mcmc_parameters p
)
{
  qdm_mcmc *mcmc = malloc(sizeof(qdm_mcmc));

  mcmc->p = p;

  qdm_mcmc_workspace_init(mcmc);
  qdm_mcmc_results_init(mcmc);

  return mcmc;
}

void
qdm_mcmc_free(
    qdm_mcmc *mcmc
)
{
  if (mcmc == NULL) {
    return;
  }

  qdm_mcmc_results_fini(mcmc);
  qdm_mcmc_workspace_fini(mcmc);

  free(mcmc);
}

int
qdm_mcmc_run(
    qdm_mcmc *mcmc
)
{
  int status = 0;

  for (size_t i = 0; i < mcmc->p.burn; i++) {
    status = qdm_mcmc_next(mcmc);
    if (status != 0) {
      goto cleanup;
    }

    if (i % mcmc->p.acc_check == 0) {
      qdm_mcmc_update_tune(mcmc);
    }
  }

  for (size_t i = 0; i < mcmc->p.iter; i++) {
    status = qdm_mcmc_next(mcmc);
    if (status != 0) {
      goto cleanup;
    }

    if (i % mcmc->p.thin == 0) {
      status = qdm_mcmc_save(mcmc, i / mcmc->p.thin);
      if (status != 0) {
        goto cleanup;
      }
    }
  }

cleanup:
  return status;
}

int
qdm_mcmc_next(
    qdm_mcmc *mcmc
)
{
  int status = 0;

  status = qdm_mcmc_update_theta(mcmc);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_mcmc_update_xi(mcmc);
  if (status != 0) {
    goto cleanup;
  }

cleanup:
  return status;
}

void
qdm_mcmc_update_tune(
    qdm_mcmc *mcmc
)
{
  for (size_t p = 0; p < mcmc->w.theta->size1; p++) {
    for (size_t m = 0; m < mcmc->w.theta->size2; m++) {
      if (gsl_matrix_get(mcmc->w.theta_acc, p, m) / (double)mcmc->p.acc_check > 0.5) {
        gsl_matrix_set(mcmc->w.theta_tune, p, m, gsl_min(gsl_matrix_get(mcmc->w.theta_tune, p, m) * 1.2, 5));
      }

      if (gsl_matrix_get(mcmc->w.theta_acc, p, m) / (double)mcmc->p.acc_check < 0.3) {
        gsl_matrix_set(mcmc->w.theta_tune, p, m, gsl_matrix_get(mcmc->w.theta_tune, p, m) * 0.8);
      }
    }
  }

  if (gsl_vector_get(mcmc->w.xi_acc, 0) / mcmc->p.acc_check > 0.5) {
    gsl_vector_set(mcmc->w.xi_tune, 0, gsl_min(gsl_vector_get(mcmc->w.xi_tune, 0) * 1.2, 5));
  }
  if (gsl_vector_get(mcmc->w.xi_acc, 0) / mcmc->p.acc_check < 0.3) {
    gsl_vector_set(mcmc->w.xi_tune, 0, gsl_vector_get(mcmc->w.xi_tune, 0) * 0.8);
  }

  if (gsl_vector_get(mcmc->w.xi_acc, 1) / mcmc->p.acc_check > 0.5) {
    gsl_vector_set(mcmc->w.xi_tune, 1, gsl_min(gsl_vector_get(mcmc->w.xi_tune, 1) * 1.2, 5));
  }
  if (gsl_vector_get(mcmc->w.xi_acc, 1) / mcmc->p.acc_check < 0.3) {
    gsl_vector_set(mcmc->w.xi_tune, 1, gsl_vector_get(mcmc->w.xi_tune, 1) * 0.8);
  }

  /* Reset the acceptance counter. */
  gsl_matrix_set_zero(mcmc->w.theta_acc);
  gsl_vector_set_zero(mcmc->w.xi_acc);
}

int
qdm_mcmc_update_theta(
    qdm_mcmc *mcmc
)
{
  int status = 0;

  /* Update the mth spline. */
  size_t p_max = mcmc->w.theta->size1;
  if (mcmc->p.truncate) {
    p_max = 1;
  }

  for (size_t p = 0; p < p_max; p++) {
    for (size_t m = 0; m < mcmc->w.theta->size2; m++) {
      /* Propose new theta star. */
      status = gsl_matrix_memcpy(mcmc->w.theta_star_p, mcmc->w.theta_star);
      if (status != 0) {
        goto cleanup;
      }

      double proposal =
        gsl_matrix_get(mcmc->w.theta_tune, p, m) *
        gsl_ran_ugaussian(mcmc->p.rng) +
        gsl_matrix_get(mcmc->w.theta_star, p, m);

      gsl_matrix_set(mcmc->w.theta_star_p, p, m, proposal);

      gsl_matrix_memcpy(mcmc->w.theta_p, mcmc->w.theta_star_p);
      qdm_theta_matrix_constrain(mcmc->w.theta_p, mcmc->p.theta_min);

      for (size_t i = 0; i < mcmc->p.y->size; i++) {
        qdm_logl_3(
            gsl_vector_ptr(mcmc->w.ll_p, i),
            gsl_vector_ptr(mcmc->w.tau_p, i),

            gsl_vector_get(mcmc->p.x, i),
            gsl_vector_get(mcmc->p.y, i),

            mcmc->p.t,
            mcmc->w.xi,

            mcmc->w.theta_p
        );
      }

      double ratio = qdm_vector_sum(mcmc->w.ll_p) - qdm_vector_sum(mcmc->w.ll);

      if (log(gsl_rng_uniform(mcmc->p.rng)) < ratio) {
        status = gsl_matrix_memcpy(mcmc->w.theta_star, mcmc->w.theta_star_p);
        if (status != 0) {
          goto cleanup;
        }

        status = gsl_matrix_memcpy(mcmc->w.theta, mcmc->w.theta_p);
        if (status != 0) {
          goto cleanup;
        }

        status = gsl_vector_memcpy(mcmc->w.ll, mcmc->w.ll_p);
        if (status != 0) {
          goto cleanup;
        }

        status = gsl_vector_memcpy(mcmc->w.tau, mcmc->w.tau_p);
        if (status != 0) {
          goto cleanup;
        }

        gsl_matrix_set(mcmc->w.theta_acc, p, m, gsl_matrix_get(mcmc->w.theta_acc, p, m) + 1);
      }
    }
  }

cleanup:
  return status;
}

int
qdm_mcmc_update_xi(
    qdm_mcmc *mcmc
)
{
  int status = 0;

  /* Update xi_low. */
  {
    double xi_low = gsl_vector_get(mcmc->w.xi, 0);
    double xi_low_p = exp(log(xi_low) + gsl_vector_get(mcmc->w.xi_tune, 0) * gsl_ran_ugaussian(mcmc->p.rng));

    gsl_vector_memcpy(mcmc->w.xi_p, mcmc->w.xi);
    gsl_vector_set(mcmc->w.xi_p, 0, xi_low_p);

    for (size_t i = 0; i < mcmc->p.y->size; i++) {
      qdm_logl_3(
          gsl_vector_ptr(mcmc->w.ll_p, i),
          gsl_vector_ptr(mcmc->w.tau_p, i),

          gsl_vector_get(mcmc->p.x, i),
          gsl_vector_get(mcmc->p.y, i),

          mcmc->p.t,
          mcmc->w.xi_p,

          mcmc->w.theta
      );
    }

    double ratio = -0.5 * (1 / mcmc->p.xi_prior_var) *  pow(log(xi_low_p) - mcmc->p.xi_prior_mean, 2) +
                    0.5 * (1 / mcmc->p.xi_prior_var) * (pow(log(xi_low  ) - mcmc->p.xi_prior_mean, 2) + qdm_vector_sum(mcmc->w.ll_p) - qdm_vector_sum(mcmc->w.ll));
    if (log(gsl_rng_uniform(mcmc->p.rng)) < ratio) {
      gsl_vector_set(mcmc->w.xi, 0, xi_low_p);

      status = gsl_vector_memcpy(mcmc->w.ll, mcmc->w.ll_p);
      if (status != 0) {
        goto cleanup;
      }

      gsl_vector_set(mcmc->w.xi_acc, 0, gsl_vector_get(mcmc->w.xi_acc, 0) + 1);
    }
  }

  /* Update xi_high. */
  {
    double xi_high = gsl_vector_get(mcmc->w.xi, 1);
    double xi_high_p = exp(log(xi_high) + gsl_vector_get(mcmc->w.xi_tune, 1) * gsl_ran_ugaussian(mcmc->p.rng));

    gsl_vector_memcpy(mcmc->w.xi_p, mcmc->w.xi);
    gsl_vector_set(mcmc->w.xi_p, 1, xi_high_p);

    for (size_t i = 0; i < mcmc->p.y->size; i++) {
      qdm_logl_3(
          gsl_vector_ptr(mcmc->w.ll_p, i),
          gsl_vector_ptr(mcmc->w.tau_p, i),

          gsl_vector_get(mcmc->p.x, i),
          gsl_vector_get(mcmc->p.y, i),

          mcmc->p.t,
          mcmc->w.xi_p,

          mcmc->w.theta
      );
    }

    double ratio = -0.5 * (1 / mcmc->p.xi_prior_var) *  pow(log(xi_high_p) - mcmc->p.xi_prior_mean, 2) +
                    0.5 * (1 / mcmc->p.xi_prior_var) * (pow(log(xi_high  ) - mcmc->p.xi_prior_mean, 2) + qdm_vector_sum(mcmc->w.ll_p) - qdm_vector_sum(mcmc->w.ll));
    if (log(gsl_rng_uniform(mcmc->p.rng)) < ratio) {
      gsl_vector_set(mcmc->w.xi, 1, xi_high_p);

      status = gsl_vector_memcpy(mcmc->w.ll, mcmc->w.ll_p);
      if (status != 0) {
        goto cleanup;
      }

      gsl_vector_set(mcmc->w.xi_acc, 1, gsl_vector_get(mcmc->w.xi_acc, 1) + 1);
    }
  }

cleanup:
  return status;
}

int
qdm_mcmc_save(
    qdm_mcmc *mcmc,
    size_t k
)
{
  int status = 0;

  {
    gsl_matrix_view m = qdm_ijk_get_ij(mcmc->r.theta, k);

    status = gsl_matrix_memcpy(&m.matrix, mcmc->w.theta);
    if (status != 0) {
      goto cleanup;
    }
  }

  {
    gsl_matrix_view m = qdm_ijk_get_ij(mcmc->r.theta_star, k);

    status = gsl_matrix_memcpy(&m.matrix, mcmc->w.theta_star);
    if (status != 0) {
      goto cleanup;
    }
  }

  {
    gsl_matrix_view m = qdm_ijk_get_ij(mcmc->r.ll, k);

    status = gsl_matrix_set_row(&m.matrix, 0, mcmc->w.ll);
    if (status != 0) {
      goto cleanup;
    }
  }

  {
    gsl_matrix_view m = qdm_ijk_get_ij(mcmc->r.tau, k);

    status = gsl_matrix_set_row(&m.matrix, 0, mcmc->w.tau);
    if (status != 0) {
      goto cleanup;
    }
  }

  {
    gsl_matrix_view m = qdm_ijk_get_ij(mcmc->r.xi, k);

    status = gsl_matrix_set_row(&m.matrix, 0, mcmc->w.xi);
    if (status != 0) {
      goto cleanup;
    }
  }

cleanup:
  return status;
}

int
qdm_mcmc_write(
    hid_t id,
    const qdm_mcmc *mcmc
)
{
  int status = 0;

  status = qdm_ijk_write(id, "theta", mcmc->r.theta);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_write(id, "theta_star", mcmc->r.theta_star);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_write(id, "ll", mcmc->r.ll);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_write(id, "tau", mcmc->r.tau);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_write(id, "xi", mcmc->r.xi);
  if (status != 0) {
    goto cleanup;
  }

cleanup:
  return status;
}

int
qdm_mcmc_read(
    hid_t id,
    qdm_mcmc **mcmc
)
{
  int status = 0;

  *mcmc = malloc(sizeof(qdm_mcmc));

  status = qdm_ijk_read(id, "theta", &(*mcmc)->r.theta);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_read(id, "theta_star", &(*mcmc)->r.theta_star);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_read(id, "ll", &(*mcmc)->r.ll);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_read(id, "tau", &(*mcmc)->r.tau);
  if (status != 0) {
    goto cleanup;
  }

  status = qdm_ijk_read(id, "xi", &(*mcmc)->r.xi);
  if (status != 0) {
    goto cleanup;
  }

  (*mcmc)->r.s = (*mcmc)->r.theta->size3;

cleanup:
  return status;
}


#ifndef H_LASER_DATA_JSON
#define H_LASER_DATA_JSON

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

#include <json-c/json.h>
#include <json-c/json_more_utils.h>

#include "laser_data.h"
#include "algos.h"

/* Laserdata to/from json */

JO ld_to_json(LDP);
LDP json_to_ld(JO);

JO corr_to_json(struct correspondence*, int n);
int json_to_corr(JO jo, struct correspondence*, int n);

LDP ld_from_json_stream(FILE*);
LDP ld_from_json_string(const char*s);
void ld_write_as_json(LDP ld, FILE * stream);

/* Other stuff to/from json */

JO matrix_to_json(gsl_matrix*m);
JO vector_to_json(gsl_vector*v);
JO result_to_json(struct sm_params*p, struct sm_result *r);

#endif


/* ode-initval/odeiv.c
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Author:  G. Jungman
 */
#include <config.h>
#include <stdlib.h>
#include <gsl/gsl_errno.h>
#include "gsl_odeiv.h"

gsl_odeiv_step *
gsl_odeiv_step_alloc(const gsl_odeiv_step_type * T, size_t dim)
{
  gsl_odeiv_step *s = (gsl_odeiv_step *) malloc (sizeof (gsl_odeiv_step));

  if (s == 0)
    {
      GSL_ERROR_NULL ("failed to allocate space for ode struct", GSL_ENOMEM);
    };

  s->type = T;
  s->dimension = dim;

  s->state = s->type->alloc(dim);

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

      GSL_ERROR_NULL ("failed to allocate space for ode state",	GSL_ENOMEM);
    };

  return s;
}

const char *
gsl_odeiv_step_name(const gsl_odeiv_step * s)
{
  return s->type->name;
}

unsigned int
gsl_odeiv_step_order(const gsl_odeiv_step * s)
{
  return s->type->order(s->state);
}

int
gsl_odeiv_step_apply(
  gsl_odeiv_step * s,
  double t,
  double h,
  double y[],
  double yerr[],
  const double dydt_in[],
  double dydt_out[],
  const gsl_odeiv_system * dydt)
{
  return s->type->apply(s->state, s->dimension, t, h, y, yerr, dydt_in, dydt_out, dydt);
}

int
gsl_odeiv_step_reset(gsl_odeiv_step * s)
{
  return s->type->reset(s->state, s->dimension);
}

void
gsl_odeiv_step_free(gsl_odeiv_step * s)
{
  s->type->free(s->state);
  free(s);
}


/*
 * Copyright (c) 2011-2013  University of Texas at Austin. All rights reserved.
 *
 * $COPYRIGHT$
 *
 * Additional copyrights may follow
 *
 * This file is part of PerfExpert.
 *
 * PerfExpert is free software: you can redistribute it and/or modify it under
 * the terms of the The University of Texas at Austin Research License
 *
 * PerfExpert 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.
 *
 * Authors: Leonardo Fialho and Ashay Rane
 *
 * $HEADER$
 */

#ifndef HISTOGRAM_H_
#define HISTOGRAM_H_

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

#include "analysis_defs.h"

bool pair_sort(const pair_t& p1, const pair_t& p2);

int flatten_and_sort_histogram(gsl_histogram*& hist, pair_list_t& pair_list);

int create_histogram_if_null(gsl_histogram*& hist, size_t bins);

#endif  /* HISTOGRAM_H_ */


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

#ifndef __GSL_VECTOR_SHORT_H__
#define __GSL_VECTOR_SHORT_H__

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

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

__BEGIN_DECLS

typedef struct
{
  size_t size;
  size_t stride;
  short *data;
  gsl_block_short *block;
  int owner;
}
gsl_vector_short;

typedef struct
{
  gsl_vector_short vector;
} _gsl_vector_short_view;

typedef _gsl_vector_short_view gsl_vector_short_view;

typedef struct
{
  gsl_vector_short vector;
} _gsl_vector_short_const_view;

typedef const _gsl_vector_short_const_view gsl_vector_short_const_view;

/* Allocation */

gsl_vector_short *gsl_vector_short_alloc (const size_t n);
gsl_vector_short *gsl_vector_short_calloc (const size_t n);

gsl_vector_short *gsl_vector_short_alloc_from_block (gsl_block_short * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

gsl_vector_short *gsl_vector_short_alloc_from_vector (gsl_vector_short * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

void gsl_vector_short_free (gsl_vector_short * v);

/* Views */

_gsl_vector_short_view
gsl_vector_short_view_array (short *v, size_t n);

_gsl_vector_short_view
gsl_vector_short_view_array_with_stride (short *base,
                                         size_t stride,
                                         size_t n);

_gsl_vector_short_const_view
gsl_vector_short_const_view_array (const short *v, size_t n);

_gsl_vector_short_const_view
gsl_vector_short_const_view_array_with_stride (const short *base,
                                               size_t stride,
                                               size_t n);

_gsl_vector_short_view
gsl_vector_short_subvector (gsl_vector_short *v,
                            size_t i,
                            size_t n);

_gsl_vector_short_view
gsl_vector_short_subvector_with_stride (gsl_vector_short *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

_gsl_vector_short_const_view
gsl_vector_short_const_subvector (const gsl_vector_short *v,
                                  size_t i,
                                  size_t n);

_gsl_vector_short_const_view
gsl_vector_short_const_subvector_with_stride (const gsl_vector_short *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

short gsl_vector_short_get (const gsl_vector_short * v, const size_t i);
void gsl_vector_short_set (gsl_vector_short * v, const size_t i, short x);

short *gsl_vector_short_ptr (gsl_vector_short * v, const size_t i);
const short *gsl_vector_short_const_ptr (const gsl_vector_short * v, const size_t i);

void gsl_vector_short_set_zero (gsl_vector_short * v);
void gsl_vector_short_set_all (gsl_vector_short * v, short x);
int gsl_vector_short_set_basis (gsl_vector_short * v, size_t i);

int gsl_vector_short_fread (FILE * stream, gsl_vector_short * v);
int gsl_vector_short_fwrite (FILE * stream, const gsl_vector_short * v);
int gsl_vector_short_fscanf (FILE * stream, gsl_vector_short * v);
int gsl_vector_short_fprintf (FILE * stream, const gsl_vector_short * v,
                              const char *format);

int gsl_vector_short_memcpy (gsl_vector_short * dest, const gsl_vector_short * src);

int gsl_vector_short_reverse (gsl_vector_short * v);

int gsl_vector_short_swap (gsl_vector_short * v, gsl_vector_short * w);
int gsl_vector_short_swap_elements (gsl_vector_short * v, const size_t i, const size_t j);

short gsl_vector_short_max (const gsl_vector_short * v);
short gsl_vector_short_min (const gsl_vector_short * v);
void gsl_vector_short_minmax (const gsl_vector_short * v, short * min_out, short * max_out);

size_t gsl_vector_short_max_index (const gsl_vector_short * v);
size_t gsl_vector_short_min_index (const gsl_vector_short * v);
void gsl_vector_short_minmax_index (const gsl_vector_short * v, size_t * imin, size_t * imax);

int gsl_vector_short_add (gsl_vector_short * a, const gsl_vector_short * b);
int gsl_vector_short_sub (gsl_vector_short * a, const gsl_vector_short * b);
int gsl_vector_short_mul (gsl_vector_short * a, const gsl_vector_short * b);
int gsl_vector_short_div (gsl_vector_short * a, const gsl_vector_short * b);
int gsl_vector_short_scale (gsl_vector_short * a, const double x);
int gsl_vector_short_add_constant (gsl_vector_short * a, const double x);

int gsl_vector_short_isnull (const gsl_vector_short * v);

#ifdef HAVE_INLINE

extern inline
short
gsl_vector_short_get (const gsl_vector_short * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_VAL ("index out of range", GSL_EINVAL, 0);
    }
#endif
  return v->data[i * v->stride];
}

extern inline
void
gsl_vector_short_set (gsl_vector_short * v, const size_t i, short x)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_VOID ("index out of range", GSL_EINVAL);
    }
#endif
  v->data[i * v->stride] = x;
}

extern inline
short *
gsl_vector_short_ptr (gsl_vector_short * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (short *) (v->data + i * v->stride);
}

extern inline
const short *
gsl_vector_short_const_ptr (const gsl_vector_short * v, const size_t i)
{
#if GSL_RANGE_CHECK
  if (i >= v->size)
    {
      GSL_ERROR_NULL ("index out of range", GSL_EINVAL);
    }
#endif
  return (const short *) (v->data + i * v->stride);
}

#endif /* HAVE_INLINE */

__END_DECLS

#endif /* __GSL_VECTOR_SHORT_H__ */


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

#pragma once

#ifndef batch_8317ae94_87f4_4cc2_8dab_1eef2919a461_h
#define batch_8317ae94_87f4_4cc2_8dab_1eef2919a461_h

#include <ariel/config.h>
#include <gslib/rtree.h>
#include <ariel/loopblinn.h>

__ariel_begin__

struct bat_triangle;
struct bat_line;
struct bat_batch;

typedef vector<bat_triangle*> bat_triangles;
typedef vector<bat_line*> bat_lines;
typedef rtree_entity<bat_triangle*> bat_rtree_entity;
typedef rtree_node<bat_rtree_entity> bat_rtree_node;
typedef _tree_allocator<bat_rtree_node> bat_rtree_alloc;
typedef tree<bat_rtree_entity, bat_rtree_node, bat_rtree_alloc> bat_tree;
typedef rtree<bat_rtree_entity, quadratic_split_alg<16, 6, bat_tree>, bat_rtree_node, bat_rtree_alloc> bat_rtree;
typedef vector<bat_batch*> bat_batches;

enum bat_type
{
    bf_start,
    bf_cr = bf_start,       /* pt, cr */
    bf_klm_cr,              /* pt, klm, cr */
    bf_klm_tex,             /* pt, klm, tex */
    bf_end = bf_klm_tex,

    bs_start,
    bs_coef_cr = bs_start,  /* pt, coef, cr */
    bs_coef_tex,            /* pt, coef, tex */
    bs_end = bs_coef_tex,
};

struct bat_triangle
{
    lb_joint*           _joints[3];
    vec2                _reduced[3];        /* get a reduced triangle so that no overlapping caused by error would be detected. */
    float               _zorder;
    bool                _is_reduced;

public:
    bat_triangle();
    bat_triangle(lb_joint* i, lb_joint* j, lb_joint* k);
    ~bat_triangle() {}
    void make_rect(rectf& rc) const;
    void set_joint(int i, lb_joint* p) { _joints[i] = p; }
    lb_joint* get_joint(int i) const { return _joints[i]; }
    const vec2& get_point(int i) const { return _joints[i]->get_point(); }
    void* get_lb_binding(int i) const { return _joints[i]->get_binding(); }
    bat_type decide(uint brush_tag) const;
    bool has_klm_coords() const;
    const vec2& get_reduced_point(int i) const;
    bool is_overlapped(const bat_triangle& other) const;
    void ensure_make_reduced();
    void set_zorder(float z) { _zorder = z; }
    float get_zorder() const { return _zorder; }
    void get_center(vec2& c) const;
    void tracing() const;
    void trace_reduced_points() const;
};

struct bat_line
{
    vec2                _points[2];
    vec2                _contourpt[4];      /* calculated contour pts */
    lb_joint*           _srcjs[2];
    vec3                _coef;
    float               _width;
    float               _zorder;
    uint                _tag;               /* pen tag */
    bool                _half;              /* is half line? */
    bool                _recalc;            /* need recalculation? */

public:
    bat_line();
    void set_start_point(const vec2& p) { _points[0] = p; }
    void set_end_point(const vec2& p) { _points[1] = p; }
    void set_source_joint(int i, lb_joint* j) { _srcjs[i] = j; }
    lb_joint* get_source_joint(int i) const { return _srcjs[i]; }
    const vec2& get_start_point() const { return _points[0]; }
    const vec2& get_end_point() const { return _points[1]; }
    void set_pen_tag(uint t) { _tag = t; }
    void setup_coef();
    void set_coef(const vec3& c) { _coef = c; }
    const vec3& get_coef() const { return _coef; }
    void set_zorder(float z) { _zorder = z; }
    float get_zorder() const { return _zorder; }
    void set_line_width(float w) { _width = w; }
    float get_line_width() const { return _width; }
    void set_half_line(bool hl) { _half = hl; }
    bool is_half_line() const { return _half; }
    bat_type decide() const;
    void get_bound_rect(rectf& rc) const;
    int clip_triangle(bat_line output[2], const bat_triangle* triangle) const;
    void calc_contour_points();
    const vec2& get_contour_point(int i) const { return _contourpt[i]; }
    void set_contour_point(int i, const vec2& p) { _contourpt[i] = p; }
    bool set_need_recalc(bool b) { _recalc = b; }
    bool need_recalc() const { return _recalc; }
    void trim_contour(bat_line& line);
    void tracing() const;

public:
    static bat_line* create_line(lb_joint* i, lb_joint* j, float w, float z, uint t, bool half);
    static bat_line* create_half_line(lb_joint* i, lb_joint* j, const vec2& p1, const vec2& p2, float w, float z, uint t);
};

struct bat_batch
{
    bat_type            _type;

public:
    bat_batch(bat_type t): _type(t) {}
    virtual ~bat_batch() {}
    bat_type get_type() const { return _type; }
};

struct bat_fill_batch:
    public bat_batch
{
    bat_rtree           _rtree;

public:
    bat_fill_batch(bat_type t): bat_batch(t) {}
    bat_rtree& get_rtree() { return _rtree; }
    const bat_rtree& const_rtree() const { return _rtree; }
};

struct bat_stroke_batch:
    public bat_batch
{
    bat_lines           _lines;

public:
    bat_stroke_batch(bat_type t): bat_batch(t) {}
    void add_line(bat_line* p) { _lines.push_back(p); }
    bat_lines& get_lines() { return _lines; }
    const bat_lines& const_lines() const { return _lines; }
};

struct bat_stroke_host_batch:
    public bat_stroke_batch
{
public:
    bat_stroke_host_batch(bat_type t): bat_stroke_batch(t) {}
    virtual ~bat_stroke_host_batch();
};

class batch_processor
{
public:
    typedef bat_batches::iterator bat_iter;
    typedef bat_batches::const_iterator bat_const_iter;
    typedef bat_batches::reverse_iterator bat_reversed_iter;
    friend class rose;

public:
    batch_processor();
    ~batch_processor();
    void set_antialias(bool b) { _antialias = b; }
    bool is_aa_enabled() const { return _antialias; }
    void add_non_tex_polygon(lb_polygon* poly, float z, uint brush_tag);
    bat_batch* add_tex_polygons(lb_polygon_list& polys, float z);
    bat_line* add_line(lb_joint* i, lb_joint* j, float w, float z, uint pen_tag);
    bat_line* add_aa_border(lb_joint* i, lb_joint* j, float z, uint pen_tag);
    void finish_batching();
    bat_batches& get_batches() { return _batches; }
    void clear_batches();

protected:
    bat_triangles       _triangles;
    bat_lines           _lines;
    bat_batches         _batches;
    bool                _antialias;

protected:
    template<class _batch>
    _batch* create_batch(bat_type t);
    bat_triangle* create_triangle(lb_joint* i, lb_joint* j, lb_joint* k, float z);
    bat_line* create_line(lb_joint* i, lb_joint* j, float w, float z, uint t, bool half);
    bat_line* create_half_line(lb_joint* i, lb_joint* j, const vec2& p1, const vec2& p2, float w, float z, uint t);
    void add_triangle(lb_joint* i, lb_joint* j, lb_joint* k, bool b[3], float z, uint brush_tag);
    void collect_aa_borders(bat_triangle* triangle, bool b[3], uint pen_tag);
    void proceed_line_batch();
    void gather_tex_triangles(bat_triangles& triangles, lb_polygon* poly, float z);
    bat_batch* find_containable_tex_batch(const bat_triangles& triangles);
    bat_stroke_batch* find_associated_tex_stroke_batch(const bat_batch* bat);
};

__ariel_end__

#endif