#pragma once

#define EXPORT __declspec(dllexport)

#define WIN32_LEAN_AND_MEAN

// STL
#include <array>
#include <cassert>
#include <cstdint>
#include <deque>
#include <exception>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

// Windows
#include <Windows.h>
#include <VersionHelpers.h>
#include <WTypes.h>

// DirectX 11
#include <d3d11_1.h>
#include "d3d8types.h"
#include <d3dcompiler.h>
#include <DirectXMath.h>

// GSL
#include <gsl/span>

// DirectXTK
#include <wrl/client.h>
#include <SimpleMath.h>

// Local
#include "cbuffers.h"
#include "CBufferWriter.h"
#include "d3d8to11.hpp"
#include "d3d8to11_base.h"
#include "d3d8to11_device.h"
#include "d3d8to11_index_buffer.h"
#include "d3d8to11_resource.h"
#include "d3d8to11_surface.h"
#include "d3d8to11_texture.h"
#include "d3d8to11_vertex_buffer.h"
#include "d3d8types.hpp"
#include "defs.h"
#include <dirty_t.h>
#include "hash_combine.h"
#include "int_multiple.h"
#include "Light.h"
#include "Material.h"
#include "Shader.h"
#include "simple_math.h"
#include "SimpleMath.h"
#include "typedefs.h"
#include "Unknown.h"
#include "dynarray.h"


//
//  rope.hpp
//  Fans
//
//  Created by tqtifnypmb on 06/12/2017.
//  Copyright © 2017 tqtifnypmb. All rights reserved.
//

#pragma once

#include <memory>
#include <functional>
#include <vector>
#include <string>

#include <gsl/gsl>
#include "RopeNode.h"
#include "Range.h"
#include "RopeIter.h"
#include "../types.h"

namespace brick
{

class Rope {
public:
    static constexpr size_t max_leaf_length = 1;

	Rope(Rope&& l, Rope&& r);

	Rope();
    Rope(const Rope&);

	Rope(Rope&& r) = default;
	Rope& operator=(Rope&&) = default;
	Rope& operator=(const Rope&) = delete;

	template <class Converter>
    void insert(gsl::span<const char> bytes, size_t pos);
    void insert(const detail::CodePointList& cp, size_t pos);

    void erase(const Range& range);

    size_t size() const {
        return size_;
    }

    RopeIter begin() const;
    RopeIter end() const;

    std::reverse_iterator<RopeIter> rbegin() const {
        return std::reverse_iterator<RopeIter>(end());
    }

    std::reverse_iterator<RopeIter> rend() const {
        return std::reverse_iterator<RopeIter>(begin());
    }

    RopeIter iterator(size_t index) const;

    bool empty() const {
        return size_ == 0;
    }

    void swap(Rope& other) noexcept {
        std::swap(size_, other.size_);
        root_.swap(other.root_);
    }

    std::string string() const;

    detail::RopeNode* root_test() {
        return root_.get();
    }

    detail::RopeNodePtr nextLeaf_test(detail::RopeNode* current) {
        return nextLeaf(current);
    }

    detail::RopeNodePtr prevLeaf_test(detail::RopeNode* current) {
        return prevLeaf(current);
    }

    void rebalance_test() {
        rebalance();
    }

    std::tuple<detail::RopeNodePtr, size_t> get_test(detail::RopeNode* root, size_t index) {
        return getLeaf(root, index);
    }

    size_t lengthOfWholeRope_test(gsl::not_null<detail::RopeNode*> root) {
        return lengthOfWholeRope(root);
    }

    bool checkHeight();
    bool checkLength();

private:
    friend class RopeIter;

    static const size_t npos = -1;

    Rope(std::vector<std::unique_ptr<detail::RopeNode>>& cplist);

    detail::RopeNodePtr nextLeaf(gsl::not_null<detail::RopeNode*> current) const;
    detail::RopeNodePtr prevLeaf(gsl::not_null<detail::RopeNode*> current) const;
    void removeLeaf(detail::RopeNodePtr node);

    size_t lengthOfWholeRope(gsl::not_null<detail::RopeNode*> root);

    std::vector<std::unique_ptr<detail::RopeNode>> collectLeaves(bool move) const;
	bool needBalance();
	void rebalance();

    std::tuple<detail::RopeNodePtr /* leaf */, size_t /* pos */>
    getLeaf(gsl::not_null<detail::RopeNode*> root, size_t index, detail::RopeNode** lastVisitedNode = nullptr) const;

    void insertSubRope(detail::RopeNodePtr leaf, size_t pos, std::unique_ptr<detail::RopeNode> subRope, size_t len);

    size_t size_ = 0;
	std::unique_ptr<detail::RopeNode> root_;
};

template <class Converter>
void Rope::insert(gsl::span<const char> bytes, size_t pos) {
    insert(Converter::encode(bytes), pos);
}

}   // namespace brick


#pragma once

#include <winrt\Windows.Foundation.h>
#include <d3d11.h>
#include <DirectXMath.h>
#include <gsl\gsl>
#include "DrawableGameComponent.h"
#include "MatrixHelper.h"

namespace Library
{
	class SkyboxMaterial;

	class Skybox final : public DrawableGameComponent
	{
		RTTI_DECLARATIONS(Skybox, DrawableGameComponent)

	public:
		Skybox(Game& game, const std::shared_ptr<Camera>& camera, const std::wstring& cubeMapFileName, float scale);
		Skybox(const Skybox&) = delete;
		Skybox(Skybox&&) = default;
		Skybox& operator=(const Skybox&) = delete;
		Skybox& operator=(Skybox&&) = default;
		~Skybox() = default;

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

	private:
		std::wstring mCubeMapFileName;
		DirectX::XMFLOAT4X4 mWorldMatrix{ MatrixHelper::Identity };
		float mScale;
		std::shared_ptr<SkyboxMaterial> mMaterial;
		winrt::com_ptr<ID3D11Buffer> mVertexBuffer;
		winrt::com_ptr<ID3D11Buffer> mIndexBuffer;
		std::uint32_t mIndexCount{ 0 };
		bool mUpdateMaterial{ true };
	};
}


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

#define _FILE_OFFSET_BITS 64
#define _USE_LARGEFILE 1
#define _LARGEFILE_SOURCE 1
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <gsl/gsl_sort.h>
#include "psrsalsa.h"
#define MaxNrOnpulseRegions 10
int NrOnpulseRegions, OnPulseRegion[MaxNrOnpulseRegions][2];
void PlotProfile(int NrBins, float *Ipulse, char *xlabel, char *ylabel, char *title, int Highlight, int color, int clearPage);
void ShiftProfile(int shift, int NrBins, float *Iprofile, float *outputProfile);
int main(int argc, char **argv)
{
  char output_fname[1000], PlotDevice[100], singlechar, *inputname;
  int circularShift, noinput, onlyI, memsave, currentfilenumber, dummy_int;
  int shift, bin1, bin2, subintWritten, poladd, freqadd;
  long i, j, pol, fchan, nsub, binnr, nrinputfiles, subintslost, currentOutputSubint, sumNsub, curNrInsubint;
  float *Iprofile, *Iprofile_firstfile, *shiftedProfile, *subint, x, y, *float_ptr, *float_ptr2;
  datafile_definition **fin;
  datafile_definition fout, clone;
  psrsalsaApplication application;
  initApplication(&application, "padd", "[options] inputfiles");
  application.switch_blocksize = 1;
  application.switch_verbose = 1;
  application.switch_debug = 1;
  application.switch_filelist = 1;
  application.switch_iformat = 1;
  application.switch_oformat = 1;
  application.switch_formatlist = 1;
  application.switch_fscr = 1;
  application.switch_FSCR = 1;
  application.switch_nocounters = 1;
  application.switch_changeRefFreq = 1;
  application.oformat = FITS_format;
  strcpy(PlotDevice, "?");
  onlyI = 0;
  strcpy(output_fname, "addedfile.gg");
  NrOnpulseRegions = 0;
  circularShift = 0;
  noinput = 0;
  shift = 0;
  memsave = 0;
  sumNsub = 1;
  poladd = 0;
  freqadd = 0;
  x = y = singlechar = 0;
  if(argc < 2) {
    printf("Program to add data files together. Usage:\n\n");
    printApplicationHelp(&application);
    printf("Optional options:\n");
    printf("-w                      Output name. Default is \"%s\"\n", output_fname);
    printf("-I                      Only process the first polarization channel\n");
    printf("-c                      Turn on circular shifting (so that no subint is lost).\n");
    printf("                        The first and last subintegrations are spilling over\n");
    printf("                        into each other.\n");
    printf("-n                      No graphical input, circular shifting by this number of\n");
    printf("                        bins, so this option implies -c. So -n 0 results in a\n");
    printf("                        simple concatenation of the input files.\n");
    printf("-nsub                   This number of subintegrations are summed before being\n");
    printf("                        written out\n");
    printf("-poladd                 The input files are to be interpretted as separate\n");
    printf("                        polarization channels (option implies -n 0).\n");
    printf("-freqadd                The input files are to be interpretted as separate\n");
    printf("                        frequency bands (option implies -n 0).\n");
    printf("-memsave                Only one full input data-set exists in memory at a time,\n");
    printf("                        but every input file will be opened twice.\n");
    printf("\n");
    printCitationInfo();
    terminateApplication(&application);
    return 0;
  }else {
    for(i = 1; i < argc; i++) {
      dummy_int = i;
      if(processCommandLine(&application, argc, argv, &dummy_int)) {
 i = dummy_int;
      }else if(strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "-W") == 0) {
 strcpy(output_fname,argv[i+1]);
        i++;
      }else if(strcmp(argv[i], "-memsave") == 0) {
 memsave = 1;
      }else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "-C") == 0) {
 circularShift = 1;
      }else if(strcmp(argv[i], "-I") == 0) {
 onlyI = 1;
      }else if(strcmp(argv[i], "-poladd") == 0) {
 poladd = 1;
 circularShift = 1;
 noinput = 1;
 shift = 0;
      }else if(strcmp(argv[i], "-freqadd") == 0) {
 freqadd = 1;
 circularShift = 1;
 noinput = 1;
 shift = 0;
      }else if(strcmp(argv[i], "-n") == 0) {
 circularShift = 1;
 noinput = 1;
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%d", &shift, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR padd: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 i++;
      }else if(strcmp(argv[i], "-nsub") == 0) {
 if(parse_command_string(application.verbose_state, argc, argv, i+1, 0, -1, "%ld", &sumNsub, NULL) == 0) {
   printerror(application.verbose_state.debug, "ERROR padd: Cannot parse '%s' option.", argv[i]);
   return 0;
 }
 if(sumNsub < 1) {
   fflush(stdout);
   printerror(application.verbose_state.debug, "ERROR padd: Cannot parse option %s, expected one integer number > 1", argv[i]);
   return 0;
 }
 i++;
      }else {
 if(argv[i][0] == '-') {
   printerror(application.verbose_state.debug, "ERROR padd: Unknown option %s. Run padd without command-line options to get 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;
  }
  nrinputfiles = numberInApplicationFilenameList(&application, argv, application.verbose_state);
  if(nrinputfiles < 2) {
    printerror(application.verbose_state.debug, "ERROR padd: Need at least two input files");
    return 0;
  }
  if(freqadd && poladd) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot use the -freqadd and -poladd flag simultaneously.");
    return 0;
  }
  if(sumNsub != 1 && poladd) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot use the -nsub and -poladd flag simultaneously.");
    return 0;
  }
  if(sumNsub != 1 && freqadd) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot use the -nsub and -freqadd flag simultaneously.");
    return 0;
  }
  if(circularShift != 1 && poladd) {
    printerror(application.verbose_state.debug, "ERROR padd: You must use the -c option together with -poladd.");
    return 0;
  }
  if(circularShift != 1 && freqadd) {
    printerror(application.verbose_state.debug, "ERROR padd: You must use the -c option together with -freqadd.");
    return 0;
  }
  if((noinput != 1 || shift != 0) && poladd) {
    printerror(application.verbose_state.debug, "ERROR padd: You must use the -n 0 option together with -poladd.");
    return 0;
  }
  if((noinput != 1 || shift != 0) && freqadd) {
    printerror(application.verbose_state.debug, "ERROR padd: You must use the -n 0 option together with -poladd.");
    return 0;
  }
  fin = malloc(nrinputfiles*sizeof(datafile_definition *));
  if(fin == NULL) {
    printerror(application.verbose_state.debug, "ERROR padd: Memory allocation error");
    return 0;
  }
  for(i = 0; i < nrinputfiles; i++) {
    fin[i] = malloc(sizeof(datafile_definition));
    if(fin[i] == NULL) {
      printerror(application.verbose_state.debug, "ERROR padd: Memory allocation error");
      return 0;
    }
  }
  currentfilenumber = 0;
  while((inputname = getNextFilenameFromList(&application, argv, application.verbose_state)) != NULL) {
    verbose_definition verbose2;
    copyVerboseState(application.verbose_state, &verbose2);
    verbose2.indent = application.verbose_state.indent + 2;
    if(memsave == 0 || (currentfilenumber == 0 && noinput == 0)) {
      if(currentfilenumber == 0) {
 printf("Read in input files:\n");
      }
      if(openPSRData(fin[currentfilenumber], inputname, application.iformat, 0, 1, 0, verbose2) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: Cannot open %s\n", inputname);
 return 0;
      }
      if(currentfilenumber == 0) {
 for(i = 1; i < argc; i++) {
   if(strcmp(argv[i], "-header") == 0) {
     fflush(stdout);
     printwarning(application.verbose_state.debug, "WARNING: If using the -header option, be aware it applied BEFORE the preprocessing.");
   }
 }
      }
      if(preprocessApplication(&application, fin[currentfilenumber]) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: preprocess option failed on file %s\n", inputname);
 return 0;
      }
    }else {
      if(currentfilenumber == 0)
 printf("Read in headers of input files:\n");
      if(openPSRData(fin[currentfilenumber], inputname, application.iformat, 0, 0, 0, verbose2) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: Cannot open %s\n", inputname);
 return 0;
      }
      if(readHeaderPSRData(fin[currentfilenumber], 1, 0, verbose2) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: Cannot read header of file %s\n", inputname);
 return 0;
      }
    }
    if(currentfilenumber == 0 && noinput == 0) {
      Iprofile_firstfile = (float *)malloc(fin[0]->NrPols*fin[0]->NrBins*sizeof(float));
      shiftedProfile = (float *)malloc(fin[0]->NrPols*fin[0]->NrBins*sizeof(float));
      if(Iprofile_firstfile == NULL || shiftedProfile == NULL) {
 printerror(application.verbose_state.debug, "ERROR padd: Cannot allocate memory.");
 return 0;
      }
      if(read_profilePSRData(*fin[0], Iprofile_firstfile, NULL, 0, application.verbose_state) != 1) {
 printerror(application.verbose_state.debug, "ERROR padd: Reading pulse profile of first input file failed.");
 return 0;
      }
    }
    if(memsave) {
      if(closePSRData(fin[currentfilenumber], 1, application.verbose_state) != 0) {
 printerror(application.verbose_state.debug, "ERROR padd: Closing file %s failed\n", inputname);
 return 0;
      }
    }
    if(fin[currentfilenumber]->NrBins != fin[0]->NrBins) {
      printerror(application.verbose_state.debug, "ERROR padd: Number of pulse longitude bins not equal in input files.");
      return 0;
    }
    if(fin[0]->NrPols != fin[currentfilenumber]->NrPols && onlyI == 0) {
      printerror(application.verbose_state.debug, "ERROR padd: Number of polarization channels are different. Maybe you want to use the -I option?");
      return 0;
    }
    if(freqadd == 0) {
      if(fin[currentfilenumber]->NrFreqChan != fin[0]->NrFreqChan) {
 printerror(application.verbose_state.debug, "ERROR padd: Number of frequency channels not equal in input files.");
 return 0;
      }
    }
    if(poladd || freqadd) {
      if(fin[0]->NrSubints != fin[currentfilenumber]->NrSubints) {
 printerror(application.verbose_state.debug, "ERROR padd: Number of subints are different. This is not allowed with the -poladd or -freqadd options.");
 return 0;
      }
    }
    if(poladd) {
      if(fin[currentfilenumber]->NrPols != 1) {
 printerror(application.verbose_state.debug, "ERROR padd: Number of polarization channels in input files should be 1 if using the -poladd option.");
 return 0;
      }
    }
    if(fin[currentfilenumber]->isDeDisp != fin[0]->isDeDisp) {
      printerror(application.verbose_state.debug, "ERROR padd: Dedispersion state is not equal in input files.");
      return 0;
    }
    if(fin[currentfilenumber]->isDeFarad != fin[0]->isDeFarad) {
      printerror(application.verbose_state.debug, "ERROR padd: De-Faraday rotation state is not equal in input files.");
      return 0;
    }
    if(fin[currentfilenumber]->isDePar != fin[0]->isDePar) {
      printerror(application.verbose_state.debug, "ERROR padd: Parallactic angle state is not equal in input files.");
      return 0;
    }
    currentfilenumber++;
  }
  printf("Reading of input files done\n");
  unsigned long *sort_indx;
  sort_indx = (unsigned long *)malloc(nrinputfiles*sizeof(unsigned long));
  if(sort_indx == NULL) {
    printerror(application.verbose_state.debug, "ERROR padd: Memory allocation error\n");
    return 0;
  }
    for(currentfilenumber = 0; currentfilenumber < nrinputfiles; currentfilenumber++) {
      sort_indx[currentfilenumber] = currentfilenumber;
    }
  cleanPSRData(&fout, application.verbose_state);
  copy_params_PSRData(*(fin[0]), &fout, application.verbose_state);
  if(onlyI) {
    fout.NrPols = 1;
  }
  fout.format = application.oformat;
  fout.NrSubints = 0;
  subintslost = 0;
  if(poladd) {
    fout.NrPols = nrinputfiles;
    fout.NrSubints = fin[0]->NrSubints;
  }else if(freqadd) {
    fout.NrSubints = fin[0]->NrSubints;
    fout.NrFreqChan = 0;
    for(currentfilenumber = 0; currentfilenumber < nrinputfiles; currentfilenumber++) {
      fout.NrFreqChan += fin[currentfilenumber]->NrFreqChan;
    }
    fout.freqMode = FREQMODE_FREQTABLE;
    if(fout.freqlabel_list != NULL) {
      free(fout.freqlabel_list);
    }
    fout.freqlabel_list = (double *)malloc(fout.NrFreqChan*fout.NrSubints*sizeof(double));
    if(fout.freqlabel_list == NULL) {
      printerror(application.verbose_state.debug, "ERROR padd: Memory allocation error");
      return 0;
    }
    long currentOutputChan = 0;
    for(i = 0; i < nrinputfiles; i++) {
      currentfilenumber = sort_indx[i];
      for(fchan = 0; fchan < fin[currentfilenumber]->NrFreqChan; fchan++) {
 for(nsub = 0; nsub < fin[currentfilenumber]->NrSubints; nsub++) {
   double freq;
   freq = get_weighted_channel_freq(*(fin[currentfilenumber]), nsub, fchan, application.verbose_state);
   if(set_weighted_channel_freq(&fout, nsub, currentOutputChan, freq, application.verbose_state) == 0) {
     printerror(application.verbose_state.debug, "ERROR padd: Constructing frequency table failed");
     return 0;
   }
 }
 currentOutputChan++;
      }
    }
  }else {
    for(i = 0; i < nrinputfiles; i++) {
      fout.NrSubints += fin[i]->NrSubints;
      if(circularShift == 0) {
 fout.NrSubints -= 1;
 subintslost += 1;
      }
    }
  }
  if(freqadd || poladd) {
    printf("\nOutput data will be %ld subints, %ld phase bins %ld frequency channels and %ld polarizations.\n", fout.NrSubints, fout.NrBins, fout.NrFreqChan, fout.NrPols);
  }else {
    printf("\nInput data contains %ld subints, %ld phase bins %ld frequency channels and %ld polarizations.\n", fout.NrSubints+subintslost, fout.NrBins, fout.NrFreqChan, fout.NrPols);
    printf("%ld subints are lost because of the alignment of input data", subintslost);
    if(subintslost > 0)
      printf(" (consider using -c option)");
  }
  fout.tsubMode = TSUBMODE_TSUBLIST;
  if(fout.tsub_list != NULL) {
    free(fout.tsub_list);
  }
  fout.tsub_list = (double *)malloc(fout.NrSubints*sizeof(double));
  if(fout.tsub_list == NULL) {
    printerror(application.verbose_state.debug, "ERROR padd: Memory allocation error");
    return 0;
  }
  currentOutputSubint = 0;
  fout.tsub_list[0] = 0;
  subintWritten = 0;
  curNrInsubint = 0;
  if(poladd || freqadd) {
    for(nsub = 0; nsub < fin[0]->NrSubints; nsub++) {
      fout.tsub_list[nsub] = get_tsub(*(fin[0]), nsub, application.verbose_state);
    }
  }else {
    for(i = 0; i < nrinputfiles; i++) {
      currentfilenumber = sort_indx[i];
      for(nsub = 0; nsub < fin[currentfilenumber]->NrSubints; nsub++) {
 if(currentOutputSubint < fout.NrSubints)
   fout.tsub_list[currentOutputSubint] += get_tsub(*(fin[currentfilenumber]), nsub, application.verbose_state);
 if(sumNsub == 1) {
   subintWritten = 1;
 }else if(curNrInsubint == sumNsub - 1) {
   subintWritten = 1;
 }
 curNrInsubint++;
 if(subintWritten) {
   subintWritten = 0;
   curNrInsubint = 0;
   currentOutputSubint++;
   if(currentOutputSubint < fout.NrSubints)
     fout.tsub_list[currentOutputSubint] = 0;
 }
      }
    }
  }
  if(freqadd == 0 && poladd == 0) {
    dummy_int = fout.NrSubints % sumNsub;
    fout.NrSubints = fout.NrSubints/sumNsub;
    printf("\nOutput data will contain %ld subints", fout.NrSubints);
    if(sumNsub > 1)
      printf(" after summing every %ld input subints", sumNsub);
    if(dummy_int)
      printf(" (%d input subints lost because of incomplete last subint)", dummy_int);
    printf("\n\n");
  }
  if(fout.gentype == GENTYPE_PULSESTACK && sumNsub != 1) {
    if(fout.NrSubints != 1) {
      fout.gentype = GENTYPE_SUBINTEGRATIONS;
    }else {
      fout.gentype = GENTYPE_PROFILE;
    }
  }
  if(openPSRData(&fout, output_fname, fout.format, 1, 0, 0, application.verbose_state) == 0) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot open %s", output_fname);
    return 0;
  }
  if(writeHeaderPSRData(&fout, argc, argv, application.history_cmd_only, application.verbose_state) != 1) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot write header to %s", output_fname);
    return 0;
  }
  Iprofile = (float *)malloc(fout.NrPols*fout.NrBins*sizeof(float));
  if(Iprofile == NULL) {
    printerror(application.verbose_state.debug, "ERROR padd: Cannot allocate memory.");
    return 0;
  }
  if(sumNsub > 1) {
    subint = (float *)malloc(fout.NrPols*fout.NrBins*fout.NrFreqChan*sizeof(float));
    if(subint == NULL) {
      printerror(application.verbose_state.debug, "ERROR padd: Cannot allocate memory.");
      return 0;
    }
  }
  if(noinput == 0) {
    ppgopen(PlotDevice);
    ppgask(0);
    ppgslw(1);
  }
  currentfilenumber = 0;
  currentOutputSubint = 0;
  curNrInsubint = 0;
  subintWritten = 0;
  rewindFilenameList(&application);
  long currentfilenumber_index;
  long fchan_offset = 0;
  while((inputname = getNextFilenameFromList(&application, argv, application.verbose_state)) != NULL) {
    currentfilenumber_index = sort_indx[currentfilenumber];
    if(memsave) {
      closePSRData(fin[currentfilenumber_index], 0, application.verbose_state);
      if(openPSRData(fin[currentfilenumber_index], inputname, application.iformat, 0, 1, 0, application.verbose_state) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: Cannot open %s\n", inputname);
 return 0;
      }
      if(currentfilenumber == 0) {
 for(i = 1; i < argc; i++) {
   if(strcmp(argv[i], "-header") == 0) {
     fflush(stdout);
     printwarning(application.verbose_state.debug, "WARNING: If using the -header option, be aware it applied BEFORE the preprocessing.");
   }
 }
      }
      if(preprocessApplication(&application, fin[currentfilenumber_index]) == 0) {
 printerror(application.verbose_state.debug, "ERROR padd: preprocess option failed on file %s\n", inputname);
 return 0;
      }
    }
    if(shift >= fout.NrBins)
      shift -= fout.NrBins;
    if(shift < 0)
      shift += fout.NrBins;
    if(noinput == 0 && currentfilenumber != 0) {
      if(read_profilePSRData(*fin[currentfilenumber_index], Iprofile, NULL, 0, application.verbose_state) != 1) {
 printerror(application.verbose_state.debug, "ERROR padd: Reading pulse profile failed.");
 return 0;
      }
      do {
 ShiftProfile(shift, fout.NrBins, Iprofile, shiftedProfile);
 PlotProfile(fout.NrBins, Iprofile_firstfile, "Bin number", "Intensity", "Click to shift profile, press s to stop", 0, 1, 1);
 PlotProfile(fout.NrBins, shiftedProfile, "", "", "", 0, 2, 0);
 j = 0;
 do {
   if(j == 0)
     ppgband(0, 0, 0.0, 0.0, &x, &y, &singlechar);
   else
     ppgband(4, 0, bin1, 0.0, &x, &y, &singlechar);
   if(singlechar == 65) {
     if(j == 0)
       bin1 = x;
     else
       bin2 = x;
     j++;
   }else if(singlechar == 115 || singlechar ==83 ) {
     j = 10;
   }
 }while(j < 2);
 if(j < 10) {
   shift += bin2 - bin1;
   if(shift >= fout.NrBins)
     shift -= fout.NrBins;
   if(shift < 0)
     shift += fout.NrBins;
 }
      }while(j < 10);
    }
    if(shift != 0) {
      if(continuous_shift(*fin[currentfilenumber_index], &clone, shift, circularShift, "padd", MEMORY_format, 0, NULL, application.verbose_state, application.verbose_state.debug) != 1) {
 printerror(application.verbose_state.debug, "ERROR padd: circular shift failed.");
      }
      swap_orig_clone(fin[currentfilenumber_index], &clone, application.verbose_state);
    }
    long nrPulsesInCurFile;
    nrPulsesInCurFile = fin[currentfilenumber_index]->NrSubints;
    if(shift == 0 && circularShift == 0)
      nrPulsesInCurFile -= 1;
    for(nsub = 0; nsub < nrPulsesInCurFile; nsub++) {
      int nrpolsinloop;
      nrpolsinloop = fout.NrPols;
      if(poladd) {
 nrpolsinloop = 1;
      }
      for(pol = 0; pol < nrpolsinloop; pol++) {
 for(fchan = 0; fchan < fin[currentfilenumber_index]->NrFreqChan; fchan++) {
   if(readPulsePSRData(fin[currentfilenumber_index], nsub, pol, fchan, 0, fin[currentfilenumber_index]->NrBins, Iprofile, application.verbose_state) != 1) {
     printerror(application.verbose_state.debug, "ERROR padd: Read error");
     return 0;
   }
   if(sumNsub == 1) {
     if(poladd == 0 && freqadd == 0) {
  if(writePulsePSRData(&fout, currentOutputSubint, pol, fchan, 0, fout.NrBins, Iprofile, application.verbose_state) != 1) {
    printerror(application.verbose_state.debug, "ERROR padd: Write error");
    return 0;
  }
     }else {
       if(poladd) {
  if(writePulsePSRData(&fout, nsub, currentfilenumber, fchan, 0, fout.NrBins, Iprofile, application.verbose_state) != 1) {
    printerror(application.verbose_state.debug, "ERROR padd: Write error");
    return 0;
  }
       }else if(freqadd) {
  if(writePulsePSRData(&fout, nsub, pol, fchan+fchan_offset, 0, fout.NrBins, Iprofile, application.verbose_state) != 1) {
    printerror(application.verbose_state.debug, "ERROR padd: Write error");
    return 0;
  }
       }
     }
     subintWritten = 1;
   }else {
     float_ptr = &subint[fout.NrBins*(pol+fout.NrPols*fchan)];
     float_ptr2 = Iprofile;
     if(curNrInsubint == 0) {
       for(binnr = 0; binnr < fout.NrBins; binnr++) {
  *float_ptr = *float_ptr2;
  float_ptr++;
  float_ptr2++;
       }
     }else {
       for(binnr = 0; binnr < fout.NrBins; binnr++) {
  *float_ptr += *float_ptr2;
  float_ptr++;
  float_ptr2++;
       }
     }
     if(curNrInsubint == sumNsub - 1) {
       if(writePulsePSRData(&fout, currentOutputSubint, pol, fchan, 0, fout.NrBins, float_ptr-fout.NrBins, application.verbose_state) != 1) {
  printerror(application.verbose_state.debug, "ERROR padd: Write error");
  return 0;
       }
       subintWritten = 1;
     }
   }
 }
      }
      curNrInsubint++;
      if(subintWritten) {
 subintWritten = 0;
 curNrInsubint = 0;
 currentOutputSubint++;
      }
      if(application.verbose_state.nocounters == 0) {
 printf("Processing input file %d: %.1f%%     \r", currentfilenumber+1, (100.0*(nsub+1))/(float)(fin[currentfilenumber_index]->NrSubints));
 fflush(stdout);
      }
    }
    if(freqadd) {
      fchan_offset += fin[currentfilenumber_index]->NrFreqChan;
    }
    if(application.verbose_state.nocounters == 0) {
      printf("Processing file %d is done (%s).                                \n", currentfilenumber+1, fin[currentfilenumber_index]->filename);
    }
    closePSRData(fin[currentfilenumber_index], 0, application.verbose_state);
    currentfilenumber++;
  }
  closePSRData(&fout, 0, application.verbose_state);
  if(noinput == 0)
    ppgend();
  free(Iprofile);
  if(noinput == 0) {
    free(shiftedProfile);
    free(Iprofile_firstfile);
  }
  if(sumNsub > 1)
    free(subint);
  for(i = 0; i < nrinputfiles; i++) {
    free(fin[i]);
  }
  free(fin);
  free(sort_indx);
  terminateApplication(&application);
  return 0;
}
int CheckOnPulse(int bin, int NrRegions, int Regions[MaxNrOnpulseRegions][2])
{
  int i;
  for(i = 0; i < NrRegions; i++) {
    if(bin >= Regions[i][0] && bin <= Regions[i][1])
      return i+1;
  }
  return 0;
}
void PlotProfile(int NrBins, float *Ipulse, char *xlabel, char *ylabel, char *title, int Highlight, int color, int clearPage)
{
  long j;
  float ymin, ymax;
  ymin = ymax = Ipulse[0];
  for(j = 1; j < NrBins; j++) {
    if(Ipulse[j] > ymax)
      ymax = Ipulse[j];
    if(Ipulse[j] < ymin)
      ymin = Ipulse[j];
  }
  if(clearPage) {
    ppgpage();
    ppgsci(1);
    ppgsvp(0.1, 0.9, 0.1, 0.9);
    ppgswin(0,NrBins-1,-0.1,1.1);
    ppgbox("bcnsti",0.0,0,"bcnti",0.0,0);
    ppglab(xlabel, ylabel, title);
  }
  ppgsci(color);
  ppgmove(0, Ipulse[0]/ymax);
  for(j = 1; j < NrBins; j++) {
    if(Highlight != 0)
      ppgsci(color+CheckOnPulse(j,NrOnpulseRegions,OnPulseRegion));
    else
      ppgsci(color);
    ppgdraw(j, Ipulse[j]/ymax);
  }
  ppgsci(1);
}
void ShiftProfile(int shift, int NrBins, float *Iprofile, float *outputProfile)
{
  int b, b2;
  for(b = 0; b < NrBins; b++) {
    b2 = b+shift;
    if(b2 < 0)
      b2 += NrBins;
    if(b2 >= NrBins)
      b2 -= NrBins;
    outputProfile[b2] = Iprofile[b];
  }
}


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

#ifndef __GSL_MATRIX_ULONG_H__
#define __GSL_MATRIX_ULONG_H__

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_vector_ulong.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;
  unsigned long * data;
  gsl_block_ulong * block;
  int owner;
} gsl_matrix_ulong;

typedef struct
{
  gsl_matrix_ulong matrix;
} _gsl_matrix_ulong_view;

typedef _gsl_matrix_ulong_view gsl_matrix_ulong_view;

typedef struct
{
  gsl_matrix_ulong matrix;
} _gsl_matrix_ulong_const_view;

typedef const _gsl_matrix_ulong_const_view gsl_matrix_ulong_const_view;

/* Allocation */

GSL_EXPORT
gsl_matrix_ulong *
gsl_matrix_ulong_alloc (const size_t n1, const size_t n2);

GSL_EXPORT
gsl_matrix_ulong *
gsl_matrix_ulong_calloc (const size_t n1, const size_t n2);

GSL_EXPORT
gsl_matrix_ulong *
gsl_matrix_ulong_alloc_from_block (gsl_block_ulong * b,
                                   const size_t offset,
                                   const size_t n1,
                                   const size_t n2,
                                   const size_t d2);

GSL_EXPORT
gsl_matrix_ulong *
gsl_matrix_ulong_alloc_from_matrix (gsl_matrix_ulong * m,
                                    const size_t k1,
                                    const size_t k2,
                                    const size_t n1,
                                    const size_t n2);

GSL_EXPORT
gsl_vector_ulong *
gsl_vector_ulong_alloc_row_from_matrix (gsl_matrix_ulong * m,
                                        const size_t i);

GSL_EXPORT
gsl_vector_ulong *
gsl_vector_ulong_alloc_col_from_matrix (gsl_matrix_ulong * m,
                                        const size_t j);

GSL_EXPORT void gsl_matrix_ulong_free (gsl_matrix_ulong * m);

/* Views */

GSL_EXPORT
_gsl_matrix_ulong_view
gsl_matrix_ulong_submatrix (gsl_matrix_ulong * m,
                            const size_t i, const size_t j,
                            const size_t n1, const size_t n2);

GSL_EXPORT
_gsl_vector_ulong_view
gsl_matrix_ulong_row (gsl_matrix_ulong * m, const size_t i);

GSL_EXPORT
_gsl_vector_ulong_view
gsl_matrix_ulong_column (gsl_matrix_ulong * m, const size_t j);

GSL_EXPORT
_gsl_vector_ulong_view
gsl_matrix_ulong_diagonal (gsl_matrix_ulong * m);

GSL_EXPORT
_gsl_vector_ulong_view
gsl_matrix_ulong_subdiagonal (gsl_matrix_ulong * m, const size_t k);

GSL_EXPORT
_gsl_vector_ulong_view
gsl_matrix_ulong_superdiagonal (gsl_matrix_ulong * m, const size_t k);

GSL_EXPORT
_gsl_matrix_ulong_view
gsl_matrix_ulong_view_array (unsigned long * base,
                             const size_t n1,
                             const size_t n2);

GSL_EXPORT
_gsl_matrix_ulong_view
gsl_matrix_ulong_view_array_with_tda (unsigned long * base,
                                      const size_t n1,
                                      const size_t n2,
                                      const size_t tda);

GSL_EXPORT
_gsl_matrix_ulong_view
gsl_matrix_ulong_view_vector (gsl_vector_ulong * v,
                              const size_t n1,
                              const size_t n2);

GSL_EXPORT
_gsl_matrix_ulong_view
gsl_matrix_ulong_view_vector_with_tda (gsl_vector_ulong * v,
                                       const size_t n1,
                                       const size_t n2,
                                       const size_t tda);

GSL_EXPORT
_gsl_matrix_ulong_const_view
gsl_matrix_ulong_const_submatrix (const gsl_matrix_ulong * m,
                                  const size_t i, const size_t j,
                                  const size_t n1, const size_t n2);

GSL_EXPORT
_gsl_vector_ulong_const_view
gsl_matrix_ulong_const_row (const gsl_matrix_ulong * m,
                            const size_t i);

GSL_EXPORT
_gsl_vector_ulong_const_view
gsl_matrix_ulong_const_column (const gsl_matrix_ulong * m,
                               const size_t j);

GSL_EXPORT
_gsl_vector_ulong_const_view
gsl_matrix_ulong_const_diagonal (const gsl_matrix_ulong * m);

GSL_EXPORT
_gsl_vector_ulong_const_view
gsl_matrix_ulong_const_subdiagonal (const gsl_matrix_ulong * m,
                                    const size_t k);

GSL_EXPORT
_gsl_vector_ulong_const_view
gsl_matrix_ulong_const_superdiagonal (const gsl_matrix_ulong * m,
                                      const size_t k);

GSL_EXPORT
_gsl_matrix_ulong_const_view
gsl_matrix_ulong_const_view_array (const unsigned long * base,
                                   const size_t n1,
                                   const size_t n2);

GSL_EXPORT
_gsl_matrix_ulong_const_view
gsl_matrix_ulong_const_view_array_with_tda (const unsigned long * base,
                                            const size_t n1,
                                            const size_t n2,
                                            const size_t tda);

GSL_EXPORT
_gsl_matrix_ulong_const_view
gsl_matrix_ulong_const_view_vector (const gsl_vector_ulong * v,
                                    const size_t n1,
                                    const size_t n2);

GSL_EXPORT
_gsl_matrix_ulong_const_view
gsl_matrix_ulong_const_view_vector_with_tda (const gsl_vector_ulong * v,
                                             const size_t n1,
                                             const size_t n2,
                                             const size_t tda);

/* Operations */

GSL_EXPORT unsigned long   gsl_matrix_ulong_get(const gsl_matrix_ulong * m, const size_t i, const size_t j);
GSL_EXPORT void    gsl_matrix_ulong_set(gsl_matrix_ulong * m, const size_t i, const size_t j, const unsigned long x);

GSL_EXPORT unsigned long * gsl_matrix_ulong_ptr(gsl_matrix_ulong * m, const size_t i, const size_t j);
GSL_EXPORT const unsigned long * gsl_matrix_ulong_const_ptr(const gsl_matrix_ulong * m, const size_t i, const size_t j);

GSL_EXPORT void gsl_matrix_ulong_set_zero (gsl_matrix_ulong * m);
GSL_EXPORT void gsl_matrix_ulong_set_identity (gsl_matrix_ulong * m);
GSL_EXPORT void gsl_matrix_ulong_set_all (gsl_matrix_ulong * m, unsigned long x);

GSL_EXPORT int gsl_matrix_ulong_fread (FILE * stream, gsl_matrix_ulong * m) ;
GSL_EXPORT int gsl_matrix_ulong_fwrite (FILE * stream, const gsl_matrix_ulong * m) ;
GSL_EXPORT int gsl_matrix_ulong_fscanf (FILE * stream, gsl_matrix_ulong * m);
GSL_EXPORT int gsl_matrix_ulong_fprintf (FILE * stream, const gsl_matrix_ulong * m, const char * format);

GSL_EXPORT int gsl_matrix_ulong_memcpy(gsl_matrix_ulong * dest, const gsl_matrix_ulong * src);
GSL_EXPORT int gsl_matrix_ulong_swap(gsl_matrix_ulong * m1, gsl_matrix_ulong * m2);

GSL_EXPORT int gsl_matrix_ulong_swap_rows(gsl_matrix_ulong * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_ulong_swap_columns(gsl_matrix_ulong * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_ulong_swap_rowcol(gsl_matrix_ulong * m, const size_t i, const size_t j);
GSL_EXPORT int gsl_matrix_ulong_transpose (gsl_matrix_ulong * m);
GSL_EXPORT int gsl_matrix_ulong_transpose_memcpy (gsl_matrix_ulong * dest, const gsl_matrix_ulong * src);

GSL_EXPORT unsigned long gsl_matrix_ulong_max (const gsl_matrix_ulong * m);
GSL_EXPORT unsigned long gsl_matrix_ulong_min (const gsl_matrix_ulong * m);
GSL_EXPORT void gsl_matrix_ulong_minmax (const gsl_matrix_ulong * m, unsigned long * min_out, unsigned long * max_out);

GSL_EXPORT void gsl_matrix_ulong_max_index (const gsl_matrix_ulong * m, size_t * imax, size_t *jmax);
GSL_EXPORT void gsl_matrix_ulong_min_index (const gsl_matrix_ulong * m, size_t * imin, size_t *jmin);
GSL_EXPORT void gsl_matrix_ulong_minmax_index (const gsl_matrix_ulong * m, size_t * imin, size_t * jmin, size_t * imax, size_t * jmax);

GSL_EXPORT int gsl_matrix_ulong_isnull (const gsl_matrix_ulong * m);

GSL_EXPORT int gsl_matrix_ulong_add (gsl_matrix_ulong * a, const gsl_matrix_ulong * b);
GSL_EXPORT int gsl_matrix_ulong_sub (gsl_matrix_ulong * a, const gsl_matrix_ulong * b);
GSL_EXPORT int gsl_matrix_ulong_mul_elements (gsl_matrix_ulong * a, const gsl_matrix_ulong * b);
GSL_EXPORT int gsl_matrix_ulong_div_elements (gsl_matrix_ulong * a, const gsl_matrix_ulong * b);
GSL_EXPORT int gsl_matrix_ulong_scale (gsl_matrix_ulong * a, const double x);
GSL_EXPORT int gsl_matrix_ulong_add_constant (gsl_matrix_ulong * a, const double x);
GSL_EXPORT int gsl_matrix_ulong_add_diagonal (gsl_matrix_ulong * a, const double x);

/***********************************************************************/
/* The functions below are obsolete                                    */
/***********************************************************************/
GSL_EXPORT int gsl_matrix_ulong_get_row(gsl_vector_ulong * v, const gsl_matrix_ulong * m, const size_t i);
GSL_EXPORT int gsl_matrix_ulong_get_col(gsl_vector_ulong * v, const gsl_matrix_ulong * m, const size_t j);
GSL_EXPORT int gsl_matrix_ulong_set_row(gsl_matrix_ulong * m, const size_t i, const gsl_vector_ulong * v);
GSL_EXPORT int gsl_matrix_ulong_set_col(gsl_matrix_ulong * m, const size_t j, const gsl_vector_ulong * v);

/* inline functions if you are using GCC */

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

extern inline
void
gsl_matrix_ulong_set(gsl_matrix_ulong * m, const size_t i, const size_t j, const unsigned long x)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_VOID("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_VOID("second index out of range", GSL_EINVAL) ;
    }
#endif
  m->data[i * m->tda + j] = x ;
}

extern inline
unsigned long *
gsl_matrix_ulong_ptr(gsl_matrix_ulong * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (unsigned long *) (m->data + (i * m->tda + j)) ;
}

extern inline
const unsigned long *
gsl_matrix_ulong_const_ptr(const gsl_matrix_ulong * m, const size_t i, const size_t j)
{
#if GSL_RANGE_CHECK
  if (i >= m->size1)
    {
      GSL_ERROR_NULL("first index out of range", GSL_EINVAL) ;
    }
  else if (j >= m->size2)
    {
      GSL_ERROR_NULL("second index out of range", GSL_EINVAL) ;
    }
#endif
  return (const unsigned long *) (m->data + (i * m->tda + j)) ;
}

#endif

__END_DECLS

#endif /* __GSL_MATRIX_ULONG_H__ */


//! \file openmc_driver.h
//! Driver to initialize and run OpenMC in stages
#ifndef ENRICO_OPENMC_DRIVER_H
#define ENRICO_OPENMC_DRIVER_H

#include "cell_instance.h"
#include "geom.h"
#include "neutronics_driver.h"

#include "openmc/tallies/tally.h"
#include <gsl/gsl>
#include <mpi.h>

#include <vector>

namespace enrico {

//! Driver to initialize and run OpenMC in stages
class OpenmcDriver : public NeutronicsDriver {
public:
  //! One-time initalization of OpenMC and member variables
  //! \param comm An existing MPI communicator used to inialize OpenMC
  explicit OpenmcDriver(MPI_Comm comm);

  //! One-time finalization of OpenMC
  ~OpenmcDriver();

  //! Create energy production tallies for a list of materials
  //! \param[in] materials  Indices into OpenMC's materials array
  void create_tallies(gsl::span<int32_t> materials);

  xt::xtensor<double, 1> heat_source(double power) const final;

  //! Initialization required in each Picard iteration
  void init_step() final;

  //! Runs OpenMC for one Picard iteration
  void solve_step() final;

  //! Writes OpenMC output for given timestep and iteration
  //! \param timestep timestep index
  //! \param iteration iteration index
  void write_step(int timestep, int iteration) final;

  //! Finalization required in each Picard iteration
  void finalize_step() final;

  // Data
  openmc::Tally* tally_;            //!< Fission energy deposition tally
  int32_t index_filter_;            //!< Index in filters arrays for material filter
  std::vector<CellInstance> cells_; //!< Array of cell instances
};

} // namespace enrico

#endif // ENRICO_OPENMC_DRIVER_H


#ifndef VM_CODE_CODE_VIEW_H
#define VM_CODE_CODE_VIEW_H

#include <cstddef>
#include <cstring>
#include <cstdint>
#include <type_traits>
#include <array>
#include <bitset>
#include <optional>
#include <variant>
#include <algorithm>
#include <iosfwd>
#include <ostream>
#include <iomanip>
#include <gsl/span>
#include <gsl/gsl>
#include "wasm_base.h"

namespace wasm::opc {

namespace detail {

template <class It>
[[gnu::pure]]
std::tuple<wasm_uint32_t, wasm_uint32_t, It> read_memory_immediate(It first, It last)
{
	alignas(wasm_uint32_t) char buff1[sizeof(wasm_uint32_t)];
	alignas(wasm_uint32_t) char buff2[sizeof(wasm_uint32_t)];
	wasm_uint32_t flags;
	wasm_uint32_t offset;
	for(auto& chr: buff1)
	{
		assert(first != last);
		chr = *first++;
	}
	for(auto& chr: buff2)
	{
		assert(first != last);
		chr = *first++;
	}
	std::memcpy(&flags, buff1, sizeof(flags));
	std::memcpy(&offset, buff1, sizeof(offset));
	return std::make_tuple(flags, offset, first);
}

template <class T, class It>
[[gnu::pure]]
std::pair<T, It> read_serialized_immediate(It first, It last)
{
	static_assert(std::is_trivially_copyable_v<T>);
	T value;
	alignas(T) char buff[sizeof(T)];
	for(auto& chr: buff)
	{
		assert(first != last);
		chr = *first++;
	}
	std::memcpy(&value, buff, sizeof(value));
	return std::make_pair(value, first);
}

} /* namespace detail */

struct BadOpcodeError:
	public std::logic_error
{
	BadOpcodeError(OpCode op, const char* msg):
		std::logic_error(msg),
		opcode(op)
	{

	}

	const OpCode opcode;
};

template <class It, class Visitor>
decltype(auto) visit_opcode(Visitor visitor, It first, It last)
{
	assert(first != last);
	OpCode op;
	auto pos = first;
	using value_type = typename std::iterator_traits<It>::value_type;
	using underlying_type = std::underlying_type_t<OpCode>;
	if constexpr(not std::is_same_v<value_type, OpCode>)
	{
		value_type opcode = *pos++;
		op = static_cast<OpCode>(opcode);
		assert(static_cast<value_type>(op) == opcode);
	}
	else
	{
		op = *pos++;
	}

	// Handling the invalid opcode case is optional.
	if constexpr(std::is_invocable_v<Visitor, OpCode, std::nullopt_t>)
	{
		if(not opcode_exists(static_cast<underlying_type>(op)))
		{
			return visitor(
				first,
				last,
				pos,
				op,
				BadOpcodeError(op, "Given op is not a valid WASM opcode.")
			);
		}
	}
	else
	{
		if(not opcode_exists(static_cast<underlying_type>(op)))
			assert(false);
	}

	if(op >= OpCode::I32_LOAD and op <= OpCode::I64_STORE32)
	{
		wasm_uint32_t flags, offset;
		std::tie(flags, offset, pos) = detail::read_memory_immediate(pos, last);
		return visitor(first, last, pos, op, flags, offset);
	}
	else if(
		(op >= OpCode::GET_LOCAL and op <= OpCode::SET_GLOBAL)
		or (op == OpCode::CALL or op == OpCode::CALL_INDIRECT)
		or (op == OpCode::BR or op == OpCode::BR_IF)
		or (op == OpCode::ELSE)
	)
	{
		wasm_uint32_t value;
		std::tie(value, pos) = detail::read_serialized_immediate<wasm_uint32_t>(pos, last);
		return visitor(first, last, pos, op, value);
	}
	else if(op == OpCode::BLOCK or op == OpCode::IF)
	{
		assert(first != last);
		LanguageType tp = static_cast<LanguageType>(*first++);
		wasm_uint32_t label;
		std::tie(label, pos) = detail::read_serialized_immediate<wasm_uint32_t>(pos, last);
		return visitor(first, last, pos, op, tp, label);
	}
	else if(op == OpCode::LOOP)
	{
		assert(first != last);
		LanguageType tp = static_cast<LanguageType>(*first++);
		return visitor(first, last, pos, op, tp);
	}
	else if(op == OpCode::BR_TABLE)
	{
		wasm_uint32_t len;
		std::tie(len, pos) = detail::read_serialized_immediate<wasm_uint32_t>(pos, last);
		auto base = pos;
		std::advance(pos, (1 + len) * sizeof(wasm_uint32_t));
		return visitor(first, last, pos, op, base, len);
	}

	switch(op)
	{
	case OpCode::I32_CONST: {
		wasm_sint32_t v;
		std::tie(v, pos) = detail::read_serialized_immediate<wasm_sint32_t>(pos, last);
		return visitor(first, last, pos, op, v);
		break;
	}
	case OpCode::I64_CONST: {
		wasm_sint64_t v;
		std::tie(v, pos) = detail::read_serialized_immediate<wasm_sint64_t>(pos, last);
		return visitor(first, last, pos, op, v);
		break;
	}
	case OpCode::F32_CONST: {
		wasm_float32_t v;
		std::tie(v, pos) = detail::read_serialized_immediate<wasm_float32_t>(pos, last);
		return visitor(first, last, pos, op, v);
		break;
	}
	case OpCode::F64_CONST: {
		wasm_float64_t v;
		std::tie(v, pos) = detail::read_serialized_immediate<wasm_float64_t>(pos, last);
		return visitor(first, last, pos, op, v);
		break;
	}
	default:
		return visitor(op, first, pos, last);
	}
	assert(false and "Internal Error: All cases should have been handled by this point.");
}

struct MemoryImmediate:
	public std::pair<const wasm_uint32_t, const wasm_uint32_t>
{
	using std::pair<const wasm_uint32_t, const wasm_uint32_t>::pair;
};

wasm_uint32_t flags(const MemoryImmediate& immed)
{ return immed.first; }

wasm_uint32_t offset(const MemoryImmediate& immed)
{ return immed.second; }

struct BlockImmediate:
	public std::pair<const LanguageType, const wasm_uint32_t>
{
	using std::pair<const LanguageType, const wasm_uint32_t>::pair;
};

gsl::span<const LanguageType> signature(const BlockImmediate& immed)
{ return gsl::span<const LanguageType>(&(immed.first), 1u); }

std::size_t arity(const BlockImmediate& immed)
{ return signature(immed).size(); }

wasm_uint32_t offset(const BlockImmediate& immed)
{ return immed.second; }

struct BranchTableImmediate
{
	template <class ... T>
	BranchTableImmediate(T&& ... args):
		table_(std::forward<T>(args)...)
	{

	}

	wasm_uint32_t at(wasm_uint32_t idx) const
	{
		idx = std::min(std::size_t(table_.size() - 1u), std::size_t(idx));
		wasm_uint32_t depth;
		std::memcpy(&depth, table_.data() + idx, sizeof(depth));
		return depth;
	}

private:
	const gsl::span<const char[sizeof(wasm_uint32_t)]> table_;
};

struct CodeView
{
	struct Iterator;
	using value_type = WasmInstruction;
	using pointer = WasmInstruction*;
	using const_pointer = const WasmInstruction*;
	using reference = WasmInstruction&;
	using const_reference = WasmInstruction&;
	using size_type = std::string_view::size_type;
	using difference_type = std::string_view::difference_type;
	using iterator = Iterator;
	using const_iterator = iterator;

private:

	struct InstructionVisitor {

		template <class ... T>
		WasmInstruction operator()(
			const char* first,
			const char* last,
			const char* pos,
			OpCode op,
			T&& ... args
		)
		{
			assert(first < pos);
			assert(pos <= last);
			return make_instr(
				std::string_view(first, pos - first),
				op,
				last,
				std::forward<T>(args)...
			);
		}

	private:
		// Overload for instructions with immediate operands
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last)
		{ return WasmInstruction(view, op, last, std::monostate()); }

		template <
			class T,
			/* enable overloads for the simple alternatives. */
			class = std::enable_if_t<
				std::disjunction_v<
					std::is_same_v<std::decay_t<T>, wasm_uint32_t>,
					std::is_same_v<std::decay_t<T>, wasm_sint32_t>,
					std::is_same_v<std::decay_t<T>, wasm_sint64_t>,
					std::is_same_v<std::decay_t<T>, wasm_float32_t>,
					std::is_same_v<std::decay_t<T>, wasm_float64_t>
				>
			>
		>
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last, T&& arg)
		{ return WasmInstruction(view, op, last, std::forward<T>(arg)); }

		/// Loop overload
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last, LanguageType tp)
		{ return WasmInstruction(view, op, last, tp); }

		/// Branch table overload
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last, const char* base, wasm_uint32_t len)
		{
			assert(last > base);
			std::size_t byte_count = base - last;
			std::size_t bytes_needed = sizeof(wasm_uint32_t) * (len + 1u);
			assert(byte_count >= bytes_needed);
			// the table and 'view' should end at the same byte address
			assert(view.data() + view.size() == (base + (len + 1u) * sizeof(wasm_uint32_t)));
			using buffer_type = const char[sizeof(wasm_uint32_t)];
			auto table = gsl::span<buffer_type>(reinterpret_cast<buffer_type*>(base), len + 1u);
			return WasmInstruction(view, op, last, table);
		}

		/// Block overload
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last, LanguageType tp, wasm_uint32_t label)
		{ return WasmInstruction(view, op, last, BlockImmediate(tp, label)); }

		/// Memory overload
		WasmInstruction make_instr(std::string_view view, OpCode op, const char* last, wasm_uint32_t flags, wasm_uint32_t offset)
		{ return WasmInstruction(view, op, last, MemoryImmediate(flags, offset)); }

		/// Invalid opcode overload
		[[noreturn]]
		WasmInstruction make_instr(std::string_view, OpCode, const char*, const BadOpCodeError& err)
		{ throw err; }

	};

public:

	struct Iterator {
		using value_type = CodeView::value_type;
		using difference_type = CodeView::difference_type;
		using pointer = CodeView::pointer;
		using reference = CodeView::value_type;
		using iterator_category = std::input_iterator_tag;

		friend bool operator==(const Iterator& left, const Iterator& right)
		{ return left.code_ == right.code_; }

		friend bool operator!=(const Iterator& left, const Iterator& right)
		{ return not (left == right); }
	private:
		gsl::not_null<CodeView*> code_;
	};

	CodeView(const WasmFunction& func):
		function_(&func),
		code_(code(func))
	{

	}

	const WasmFunction* function() const
	{ return function_; }

	OpCode current_op() const
	{
		assert(ready());
		return static_cast<WasmInstruction>(code_.front());
	}

	bool done() const
	{ return not code_.empty(); }

	std::optional<WasmInstruction> next_instruction() const
	{
		assert(ready());
		if(code_.size() == 0)
			return std::nullopt;
		return visit_opcode(InstructionVisitor{}, code_.data(), code_.data() + code_.size());
	}

	const char* pos() const
	{ return code_.data(); }

	void advance(const CodeView& other)
	{
		assert(function() == other.function());
		assert(ready());
		assert(code_.data() + code_.size() == other.code_.data() + other.code_.size());
		assert(code_.data() < other.code_.data());
		code_ = other.code_;
	}

private:

	bool ready() const
	{
		if(done())
			return false;
		assert(opcode_exists(code_.front()));
		return true;
	}
	const WasmFunction* function_;
	std::string_view code_;
};

} /* namespace opc */
} /* namespace wasm */

#endif /* VM_CODE_CODE_VIEW_H */


//
// Created by robin on 2018/9/1.
// Copyright (c) 2018 Robin. All rights reserved.
//

#pragma once

#include <type_traits>
#include <vector>
#include <algorithm>
#include <gsl/gsl>

namespace satz::bytes {

/**
 * @brief Generate n random bytes.
 */
std::vector<uint8_t> make_random_bytes (int n);

/**
 * @brief Given a byte sequence, return the indices of non-zero bits, regarding
 *    the bytes as a little-endian bit array with index starting at 0.
 * @param bytes
 * @post The resultant vector should be in increasing order.
 */
template <typename T>
std::vector<T> make_indices (gsl::span<const uint8_t> bytes) {
  std::vector<T> d;
  d.reserve(bytes.size() * 8);

  for (int i = 0; i < bytes.size(); ++i) {
    for (int j = 0; j < 8; ++j) {
      if ((bytes[i] >> j) & 0x1) d.push_back(8 * i + j);
    }
  }

  return d;
}

/**
 * @brief Given a byte sequence, join the bytes into a single object.
 *    If the number of bytes is greater than the size of T, discard extra
 *    bytes. If the number of bytes is less than the size of T, pad with
 *    leading zeros.
 * @param bytes
 * @example
 *    [0xef, 0xbe, 0xed, 0xfe] ==> 0xfeedbeef
 *    [0xed, 0xfe] ==> 0x0000feed
 *    [0xef, 0xbe, 0xed, 0xfe, 0xee] => 0xfeedbeef
 * @post The relative byte order of the result should be the same as the argument.
 */
template <typename T>
T from_bytes (gsl::span<const uint8_t> bytes) {

  static_assert(std::is_trivially_copyable_v<T>);
  using U = std::make_unsigned_t<T>;
  static_assert(sizeof(U) == sizeof(T));

  U             ret = 0;
  const ssize_t m   = bytes.size();
  const ssize_t n   = sizeof(U);

  std::for_each(bytes.rbegin() + std::max(m - n, ssize_t(0)),
                bytes.rend(),
                [&ret] (uint8_t b) {
                  ret = (ret << 8) | b;
                });

  return static_cast<T>(ret);
}

}


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

#ifndef __GSL_VECTOR_ULONG_H__
#define __GSL_VECTOR_ULONG_H__

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

#include <stdlib.h>
#include <gsl/gsl_types.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_inline.h>
#include <gsl/gsl_check_range.h>
#include <gsl/gsl_block_ulong.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;
  unsigned long *data;
  gsl_block_ulong *block;
  int owner;
}
gsl_vector_ulong;

typedef struct
{
  gsl_vector_ulong vector;
} _gsl_vector_ulong_view;

typedef _gsl_vector_ulong_view gsl_vector_ulong_view;

typedef struct
{
  gsl_vector_ulong vector;
} _gsl_vector_ulong_const_view;

typedef const _gsl_vector_ulong_const_view gsl_vector_ulong_const_view;

/* Allocation */

GSL_FUN gsl_vector_ulong *gsl_vector_ulong_alloc (const size_t n);
GSL_FUN gsl_vector_ulong *gsl_vector_ulong_calloc (const size_t n);

GSL_FUN gsl_vector_ulong *gsl_vector_ulong_alloc_from_block (gsl_block_ulong * b,
                                                     const size_t offset,
                                                     const size_t n,
                                                     const size_t stride);

GSL_FUN gsl_vector_ulong *gsl_vector_ulong_alloc_from_vector (gsl_vector_ulong * v,
                                                      const size_t offset,
                                                      const size_t n,
                                                      const size_t stride);

GSL_FUN void gsl_vector_ulong_free (gsl_vector_ulong * v);

/* Views */

GSL_FUN _gsl_vector_ulong_view
gsl_vector_ulong_view_array (unsigned long *v, size_t n);

GSL_FUN _gsl_vector_ulong_view
gsl_vector_ulong_view_array_with_stride (unsigned long *base,
                                         size_t stride,
                                         size_t n);

GSL_FUN _gsl_vector_ulong_const_view
gsl_vector_ulong_const_view_array (const unsigned long *v, size_t n);

GSL_FUN _gsl_vector_ulong_const_view
gsl_vector_ulong_const_view_array_with_stride (const unsigned long *base,
                                               size_t stride,
                                               size_t n);

GSL_FUN _gsl_vector_ulong_view
gsl_vector_ulong_subvector (gsl_vector_ulong *v,
                            size_t i,
                            size_t n);

GSL_FUN _gsl_vector_ulong_view
gsl_vector_ulong_subvector_with_stride (gsl_vector_ulong *v,
                                        size_t i,
                                        size_t stride,
                                        size_t n);

GSL_FUN _gsl_vector_ulong_const_view
gsl_vector_ulong_const_subvector (const gsl_vector_ulong *v,
                                  size_t i,
                                  size_t n);

GSL_FUN _gsl_vector_ulong_const_view
gsl_vector_ulong_const_subvector_with_stride (const gsl_vector_ulong *v,
                                              size_t i,
                                              size_t stride,
                                              size_t n);

/* Operations */

GSL_FUN void gsl_vector_ulong_set_zero (gsl_vector_ulong * v);
GSL_FUN void gsl_vector_ulong_set_all (gsl_vector_ulong * v, unsigned long x);
GSL_FUN int gsl_vector_ulong_set_basis (gsl_vector_ulong * v, size_t i);

GSL_FUN int gsl_vector_ulong_fread (FILE * stream, gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_fwrite (FILE * stream, const gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_fscanf (FILE * stream, gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_fprintf (FILE * stream, const gsl_vector_ulong * v,
                              const char *format);

GSL_FUN int gsl_vector_ulong_memcpy (gsl_vector_ulong * dest, const gsl_vector_ulong * src);

GSL_FUN int gsl_vector_ulong_reverse (gsl_vector_ulong * v);

GSL_FUN int gsl_vector_ulong_swap (gsl_vector_ulong * v, gsl_vector_ulong * w);
GSL_FUN int gsl_vector_ulong_swap_elements (gsl_vector_ulong * v, const size_t i, const size_t j);

GSL_FUN unsigned long gsl_vector_ulong_max (const gsl_vector_ulong * v);
GSL_FUN unsigned long gsl_vector_ulong_min (const gsl_vector_ulong * v);
GSL_FUN void gsl_vector_ulong_minmax (const gsl_vector_ulong * v, unsigned long * min_out, unsigned long * max_out);

GSL_FUN size_t gsl_vector_ulong_max_index (const gsl_vector_ulong * v);
GSL_FUN size_t gsl_vector_ulong_min_index (const gsl_vector_ulong * v);
GSL_FUN void gsl_vector_ulong_minmax_index (const gsl_vector_ulong * v, size_t * imin, size_t * imax);

GSL_FUN int gsl_vector_ulong_add (gsl_vector_ulong * a, const gsl_vector_ulong * b);
GSL_FUN int gsl_vector_ulong_sub (gsl_vector_ulong * a, const gsl_vector_ulong * b);
GSL_FUN int gsl_vector_ulong_mul (gsl_vector_ulong * a, const gsl_vector_ulong * b);
GSL_FUN int gsl_vector_ulong_div (gsl_vector_ulong * a, const gsl_vector_ulong * b);
GSL_FUN int gsl_vector_ulong_scale (gsl_vector_ulong * a, const unsigned long x);
GSL_FUN int gsl_vector_ulong_add_constant (gsl_vector_ulong * a, const double x);
GSL_FUN int gsl_vector_ulong_axpby (const unsigned long alpha, const gsl_vector_ulong * x, const unsigned long beta, gsl_vector_ulong * y);
GSL_FUN unsigned long gsl_vector_ulong_sum (const gsl_vector_ulong * a);

GSL_FUN int gsl_vector_ulong_equal (const gsl_vector_ulong * u,
                            const gsl_vector_ulong * v);

GSL_FUN int gsl_vector_ulong_isnull (const gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_ispos (const gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_isneg (const gsl_vector_ulong * v);
GSL_FUN int gsl_vector_ulong_isnonneg (const gsl_vector_ulong * v);

GSL_FUN INLINE_DECL unsigned long gsl_vector_ulong_get (const gsl_vector_ulong * v, const size_t i);
GSL_FUN INLINE_DECL void gsl_vector_ulong_set (gsl_vector_ulong * v, const size_t i, unsigned long x);
GSL_FUN INLINE_DECL unsigned long * gsl_vector_ulong_ptr (gsl_vector_ulong * v, const size_t i);
GSL_FUN INLINE_DECL const unsigned long * gsl_vector_ulong_const_ptr (const gsl_vector_ulong * v, const size_t i);

#ifdef HAVE_INLINE

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

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

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

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

__END_DECLS

#endif /* __GSL_VECTOR_ULONG_H__ */


// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once

#include "Data/Data.h"
#include <gsl/gsl>

// forward declare cv::KeyPoint
namespace cv
{
    class KeyPoint;
}

namespace mage
{
    struct InitializationData;
    struct FrameData;
    class AnalyzedImage;

    class Introspector
    {
    public:
        virtual ~Introspector() = default;

        virtual void Introspect(const InitializationData& /*data*/) {}

        virtual void IntrospectEstimatedPose(const mage::FrameId& /*frameId*/, const mage::Matrix& /*viewMatrix*/) {}

        virtual void IntrospectAnalyzedImage(const mage::FrameData& /*frame*/, const mage::AnalyzedImage& /* image */) {}
    };
}


#include <pygsl/utils.h>
#include <pygsl/block_helpers.h>
#include <pygsl/error_helpers.h>
#include <gsl/gsl_qrng.h>
#include <pygsl/error_helpers.h>
#include "qrng_module_defines.h"
static PyObject *module = NULL;

static void			/* generic instance destruction */
generic_dealloc (PyObject *self)
{
  DEBUG_MESS(1, " *** generic_dealloc %p\n", (void *) self);
  PyObject_Del(self);
}

/*---------------------------------------------------------------------------*/
/* encapsulation for the PyGSL_qrng_type */
typedef struct {
     PyObject_HEAD
     gsl_qrng_type * qrng_type;
     const char * py_name; /* can not use the name here... niederreiter-*/
} PyGSL_qrng_type;

/*
PyObject*
qrng_type_getattr(PyGSL_qrng_type *self, char *name)
{
     if(strcmp(name, "__doc__") == 0){
	  return PyGSL_get_docobject_for_object(self->py_name);
     }else{
	  Py_INCREF(Py_None);
	  return Py_None;
     }
}
*/
static PyTypeObject PyGSL_qrng_type_pytype = {
  PyObject_HEAD_INIT(NULL)	/* fix up the type slot in initcrng */
  0,				/* ob_size */
  "PyGSL_qrng_type",     	/* tp_name */
  sizeof(PyGSL_qrng_type),       /* tp_basicsize */
  0,				/* tp_itemsize */

  /* standard methods */
  (destructor)  generic_dealloc,   /* tp_dealloc  ref-count==0  */
  (printfunc)   0,		   /* tp_print    "print x"     */
  (getattrfunc) 0/*qrng_type_getattr*/, /* tp_getattr  "x.attr"      */
  (setattrfunc) 0,		   /* tp_setattr  "x.attr=v"    */
  (cmpfunc)     0,		   /* tp_compare  "x > y"       */
  (reprfunc)    0,                 /* tp_repr     `x`, print x  */

  /* type categories */
  0,				/* tp_as_number   +,-,*,/,%,&,>>,pow...*/
  0,				/* tp_as_sequence +,[i],[i:j],len, ...*/
  0,				/* tp_as_mapping  [key], len, ...*/

  /* more methods */
  (hashfunc)     0,		/* tp_hash    "dict[x]" */
  (ternaryfunc)  0,             /* tp_call    "x()"     */
  (reprfunc)     0,             /* tp_str     "str(x)"  */
  (getattrofunc) 0,		/* tp_getattro */
  (setattrofunc) 0,		/* tp_setattro */
  0,				/* tp_as_buffer */
  0L,				/* tp_flags */
  NULL/* PyGSL_qrng_type_pytype_doc*/       /* tp_doc */
};

void
create_qrng_types(PyObject *module)
{
     PyGSL_qrng_type *a_rng = NULL;
     const gsl_qrng_type* thisRNGType,
	  *types[3] = {gsl_qrng_niederreiter_2, gsl_qrng_sobol, NULL};
     const char* gsl_qrng_names[3] = {"_qrng.niederreiter_2", "_qrng.sobol", NULL};

     PyObject* module_dict=PyModule_GetDict(module);
     PyObject* item = NULL;
     int i;

     assert(module_dict);
     FUNC_MESS_BEGIN();
     /* provide other rng types as subclasses of rng  */
     for(i=0; types[i]!=NULL; i++){
	  thisRNGType = types[i];
	  a_rng =  PyObject_NEW(PyGSL_qrng_type, &PyGSL_qrng_type_pytype);
	  a_rng->qrng_type = (gsl_qrng_type *) thisRNGType;
	  item = PyString_FromString((thisRNGType)->name);
	  assert(item);
	  PyGSL_clear_name(PyString_AsString(item), PyString_Size(item));
	  assert(gsl_qrng_names[i]);
	  a_rng->py_name = gsl_qrng_names[i];
	  PyDict_SetItem(module_dict, item, (PyObject *) a_rng);
	  Py_DECREF(item);
	  item = NULL;
	  thisRNGType++;
     }
     FUNC_MESS_END();
}
#define PyGSL_QRngType_Check(v) ((v)->ob_type == &PyGSL_qrng_type_pytype)

/*---------------------------------------------------------------------------*/
/* qrng */

staticforward PyTypeObject PyGSL_qrng_pytype;
#if 1
typedef struct {
  PyObject_HEAD
  gsl_qrng * qrng;
} PyGSL_qrng;
#endif
static void qrng_delete(PyGSL_qrng *self);

static PyObject *		/* on "instance.attr" */
qrng_getattr (PyGSL_qrng *self, char *name);

static PyObject *
qrng_get(PyGSL_qrng *self, PyObject *args);

static PyTypeObject PyGSL_qrng_pytype = {
  PyObject_HEAD_INIT(NULL)	/* fix up the type slot in initcrng */
  0,				/* ob_size */
  "PyGSL_qrng",			/* tp_name */
  sizeof(PyGSL_qrng),	        /* tp_basicsize */
  0,				/* tp_itemsize */

  /* standard methods */
  (destructor)  qrng_delete,       /* tp_dealloc  ref-count==0  */
  (printfunc)   0,		   /* tp_print    "print x"     */
  (getattrfunc) qrng_getattr,       /* tp_getattr  "x.attr"      */
  (setattrfunc) 0,		   /* tp_setattr  "x.attr=v"    */
  (cmpfunc)     0,		   /* tp_compare  "x > y"       */
  (reprfunc)    0,                 /* tp_repr     `x`, print x  */

  /* type categories */
  0,				/* tp_as_number   +,-,*,/,%,&,>>,pow...*/
  0,				/* tp_as_sequence +,[i],[i:j],len, ...*/
  0,				/* tp_as_mapping  [key], len, ...*/

  /* more methods */
  (hashfunc)     0,		/* tp_hash    "dict[x]" */
  (ternaryfunc)  qrng_get,      /* tp_call    "x()"     */
  (reprfunc)     0,             /* tp_str     "str(x)"  */
  (getattrofunc) 0,		/* tp_getattro */
  (setattrofunc) 0,		/* tp_setattro */
  0,				/* tp_as_buffer */
  0L,				/* tp_flags */
  0		/* tp_doc */
};

#define PyGSLQRng_Check(v) ((v)->ob_type == &PyGSL_qrng_pytype)

PyObject *
qrng_init(PyObject *self, PyObject *args)
{
     PyObject *type = NULL;
     PyGSL_qrng *qrng = NULL;
     int dimension;
     assert(args);
     if (0 == PyArg_ParseTuple(args, "O!i:rng.__init__", &PyGSL_qrng_type_pytype,
			       &type, &dimension)){
	  PyGSL_add_traceback(module, __FILE__, "rng.__init__", __LINE__ - 2);
	  return NULL;
     }
     if (dimension <= 0){
	  PyErr_SetString(PyExc_ValueError, "The sample number must be positive!");
	  PyGSL_add_traceback(module, __FILE__, "qrng.__init__", __LINE__ - 2);
	  return NULL;
     }
     qrng =  (PyGSL_qrng *) PyObject_NEW(PyGSL_qrng, &PyGSL_qrng_pytype);
     qrng->qrng = gsl_qrng_alloc(((PyGSL_qrng_type *)type)->qrng_type, dimension);
     return (PyObject *) qrng;
}

static void
qrng_delete(PyGSL_qrng *self)
{
     assert(PyGSLQRng_Check(self));
     gsl_qrng_free(self->qrng);
     DEBUG_MESS(1, " self %p\n",(void *) self);
}

static PyObject *
qrng_reinit(PyGSL_qrng *self, PyObject *args)
{
     assert(PyGSLQRng_Check(self));
     gsl_qrng_init(self->qrng);
     Py_INCREF(Py_None);
     return Py_None;
}

static PyObject *
qrng_get(PyGSL_qrng *self, PyObject *args)
{
     int dimension = 1, lineno=0;
     PyArrayObject *a_array;
     PyGSL_array_index_t dims[2];
     double *data;
     int i;

     FUNC_MESS_BEGIN();
     assert(PyGSLQRng_Check(self));
     if(0 == PyArg_ParseTuple(args, "|i", &dimension)){
	  goto fail;
     }
     if(dimension <= 0){
	  lineno = __LINE__ - 1;
	  PyErr_SetString(PyExc_ValueError,
			  "The sample number must be positive!");
	  goto fail;
     }
     dims[0] = dimension;
     dims[1] = self->qrng->dimension;
     DEBUG_MESS(5, "Building return array with dimensions (%ld,%ld)", (long)dims[0], (long)dims[1]);
     a_array = (PyArrayObject *) PyGSL_New_Array(2, dims, PyArray_DOUBLE);
     if(a_array == NULL){lineno = __LINE__ - 1; goto fail;}
     DEBUG_MESS(5, "Its strides are (%d,%d)", a_array->strides[0], a_array->strides[1]);
     assert((a_array->strides[1] / sizeof(double)) == 1);

     for(i=0; i<dimension; i++){
	  DEBUG_MESS(6, "Setting slice %d", i);
	  data = (double *) (a_array->data + a_array->strides[0] * i);
	  DEBUG_MESS(6, "Data at %p", (void *) data);
	  gsl_qrng_get(self->qrng, data);
     }

     FUNC_MESS_END();
     return (PyObject *) a_array;

 fail:
     FUNC_MESS("In Fail!");
     PyGSL_add_traceback(module, __FILE__, "_qrng.__attr__",  lineno);
     return NULL;
}

static PyObject *
qrng_name(PyGSL_qrng *self, PyObject *args)
{
     assert(PyGSLQRng_Check(self));
     if(0 == PyArg_ParseTuple(args, ":name"))
	  return NULL;
     return PyString_FromString(gsl_qrng_name(self->qrng));
}

static PyObject *
qrng_clone(PyGSL_qrng *self, PyObject *args)
{
     PyGSL_qrng * qrng;
     assert(PyGSLQRng_Check(self));
     if(0 == PyArg_ParseTuple(args, ":clone"))
	  return NULL;
     qrng =  (PyGSL_qrng *) PyObject_NEW(PyGSL_qrng, &PyGSL_qrng_pytype);
     qrng->qrng = gsl_qrng_clone(self->qrng);
     return (PyObject *) qrng;
}

static struct PyMethodDef qrng_methods[] = {
     {"init", (PyCFunction) qrng_reinit, METH_VARARGS, QRNG_INIT},
     {"get", (PyCFunction) qrng_get, METH_VARARGS, QRNG_GET},
     {"name", (PyCFunction) qrng_name, METH_VARARGS, QRNG_NAME},
     {"clone", (PyCFunction) qrng_clone, METH_VARARGS, QRNG_CLONE},
     {"__copy__", (PyCFunction) qrng_clone, METH_VARARGS, QRNG_CLONE},
     {NULL, NULL}
};

static PyObject *		/* on "instance.attr" */
qrng_getattr (PyGSL_qrng *self, char *name){
     PyObject *tmp = NULL;
     assert(PyGSLQRng_Check(self));

     /*
     if(strcmp(name, "__doc__") == 0)
	  return PyGSL_get_docobject_for_object("qrng.qrng");
     */
     tmp = Py_FindMethod(qrng_methods, (PyObject *) self, name);
     if(NULL == tmp){
	  PyGSL_add_traceback(module, __FILE__, "qrng.__attr__", __LINE__ - 1);
	  return NULL;
     }
     return tmp;

}

static PyMethodDef PyGSL_qrng_module_functions[] = {
     {"qrng", qrng_init, METH_VARARGS},
     {0, 0}
};

void
init_qrng(void)
{
     PyObject *m;

     m = Py_InitModule("_qrng", PyGSL_qrng_module_functions);
     init_pygsl();

     assert(m);
     create_qrng_types(m);
     module = m;

     PyGSL_qrng_type_pytype.ob_type = &PyType_Type;
     PyGSL_qrng_pytype.ob_type = &PyType_Type;

     /*
       {
       PyObject *o, *s, *d;
       d = PyModule_GetDict(m);

       s = PyGSL_get_docobject_for_object("_qrng");
       if(s)
          PyDict_SetItemString(d, "__doc__", s);

     o = PyGSL_get_docobject_for_object("_qrng.PyGSL_qrng_type");
     if(o){
	  Py_INCREF(o);
	  PyGSL_qrng_type_pytype.tp_doc = PyString_AsString(o);
     }
     o = PyGSL_get_docobject_for_object("_qrng.PyGSL_qrng");
     if(o){
	  Py_INCREF(o);
	  PyGSL_qrng_type_pytype.tp_doc = PyString_AsString(o);
     }
     }
     */

}


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

#ifndef __GSL_MATRIX_DOUBLE_H__
#define __GSL_MATRIX_DOUBLE_H__

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

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

__BEGIN_DECLS

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

typedef struct
{
  gsl_matrix matrix;
} _gsl_matrix_view;

typedef _gsl_matrix_view gsl_matrix_view;

typedef struct
{
  gsl_matrix matrix;
} _gsl_matrix_const_view;

typedef const _gsl_matrix_const_view gsl_matrix_const_view;

/* Allocation */

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

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

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

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

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

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

void gsl_matrix_free (gsl_matrix * m);

/* Views */

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

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

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

_gsl_vector_view
gsl_matrix_diagonal (gsl_matrix * m);

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

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

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

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

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

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

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

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

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

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

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

_gsl_vector_const_view
gsl_matrix_const_diagonal (const gsl_matrix * m);

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

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

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

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

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

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

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

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

/* Operations */

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

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

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

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

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

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

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

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

double gsl_matrix_norm1 (const gsl_matrix * m);

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

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

/* inline functions if you are using GCC */

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

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

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

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

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

#endif

__END_DECLS

#endif /* __GSL_MATRIX_DOUBLE_H__ */


#ifndef DEGNOME
#define DEGNOME

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

//Degnomedia Rogerus
typedef struct Degnome Degnome;
struct Degnome {
	double* dna_array;
	double hat_size;

};

Degnome* Degnome_new(void);
void Degnome_mate(Degnome* location, Degnome* p1, Degnome* p2, gsl_rng* rng,
	int mutation_rate, int mutation_effect, int crossover_rate);
void Degnome_free(Degnome* q);

int chrom_size;

#endif